aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniele Di Proietto <ddiproietto@google.com>2023-05-17 17:01:53 +0000
committerDaniele Di Proietto <ddiproietto@google.com>2023-05-17 17:05:54 +0000
commit4b02fb3c4d903c08bfd00c6a5336cebb7d80fb55 (patch)
tree35b49166a76473d178ef2c60f946952898d9e8ab
parentc254cef39ade32c4294421b522f0a1e41a86cb4a (diff)
parentbad11ba2234a116bafcce7910d8bad375584c5d1 (diff)
downloadperfetto-4b02fb3c4d903c08bfd00c6a5336cebb7d80fb55.tar.gz
Merge commit 'bad11ba2234a116bafcce7910d8bad375584c5d1' into HEAD
Bug: 260112703 Bug: 278884624 Change-Id: I0d7fdad29902e683a40bdade9395da8b0a759b88
-rw-r--r--.clang-tidy2
-rw-r--r--Android.bp346
-rw-r--r--BUILD379
-rw-r--r--BUILD.gn1
-rw-r--r--CHANGELOG21
-rw-r--r--bazel/deps.bzl6
-rw-r--r--bazel/rules.bzl19
-rw-r--r--buildtools/BUILD.gn7
-rw-r--r--docs/analysis/trace-processor.md6
-rw-r--r--docs/contributing/perfetto-in-the-press.md2
-rw-r--r--docs/data-sources/cpu-scheduling.md7
-rw-r--r--docs/images/enable-profile-flame-graph.pngbin268550 -> 0 bytes
-rw-r--r--docs/instrumentation/tracing-sdk.md2
-rw-r--r--docs/quickstart/callstack-sampling.md5
-rw-r--r--docs/quickstart/chrome-tracing.md2
-rw-r--r--examples/sdk/README.md2
-rw-r--r--gn/BUILD.gn6
-rw-r--r--gn/perfetto.gni5
-rw-r--r--gn/perfetto_tp_tables.gni14
-rw-r--r--gn/perfetto_unittests.gni6
-rw-r--r--gn/standalone/BUILD.gn12
-rw-r--r--gn/standalone/toolchain/win_find_msvc.py27
-rw-r--r--include/perfetto/base/compiler.h10
-rw-r--r--include/perfetto/ext/base/status_or.h4
-rw-r--r--include/perfetto/ext/base/threading/util.h5
-rw-r--r--include/perfetto/ext/cloud_trace_processor/BUILD.gn26
-rw-r--r--include/perfetto/ext/cloud_trace_processor/environment.h48
-rw-r--r--include/perfetto/ext/cloud_trace_processor/orchestrator.h85
-rw-r--r--include/perfetto/ext/cloud_trace_processor/worker.h84
-rw-r--r--include/perfetto/ext/tracing/core/consumer.h8
-rw-r--r--include/perfetto/ext/tracing/core/tracing_service.h16
-rw-r--r--include/perfetto/ext/tracing/ipc/service_ipc_host.h7
-rw-r--r--include/perfetto/protozero/proto_decoder.h3
-rw-r--r--include/perfetto/tracing/core/trace_config.h12
-rw-r--r--include/perfetto/tracing/data_source.h67
-rw-r--r--include/perfetto/tracing/interceptor.h2
-rw-r--r--include/perfetto/tracing/internal/track_event_macros.h2
-rw-r--r--protos/perfetto/cloud_trace_processor/BUILD.gn38
-rw-r--r--protos/perfetto/cloud_trace_processor/common.proto33
-rw-r--r--protos/perfetto/cloud_trace_processor/orchestrator.proto109
-rw-r--r--protos/perfetto/cloud_trace_processor/worker.proto105
-rw-r--r--protos/perfetto/common/observable_events.proto14
-rw-r--r--protos/perfetto/common/tracing_service_capabilities.proto3
-rw-r--r--protos/perfetto/config/perfetto_config.proto43
-rw-r--r--protos/perfetto/config/process_stats/process_stats_config.proto5
-rw-r--r--protos/perfetto/config/trace_config.proto38
-rw-r--r--protos/perfetto/ipc/consumer_port.proto4
-rw-r--r--protos/perfetto/metrics/android/binder_metric.proto3
-rw-r--r--protos/perfetto/metrics/android/jank_cuj_metric.proto18
-rw-r--r--protos/perfetto/metrics/android/java_heap_stats.proto4
-rw-r--r--protos/perfetto/metrics/android/monitor_contention_metric.proto28
-rw-r--r--protos/perfetto/metrics/android/process_metadata.proto3
-rw-r--r--protos/perfetto/metrics/android/startup_metric.proto15
-rw-r--r--protos/perfetto/metrics/android/surfaceflinger.proto28
-rw-r--r--protos/perfetto/metrics/perfetto_merged_metrics.proto99
-rw-r--r--protos/perfetto/metrics/webview/webview_jank_approximation.proto10
-rw-r--r--protos/perfetto/trace/ftrace/ftrace_event.proto2
-rw-r--r--protos/perfetto/trace/ftrace/mali.proto10
-rw-r--r--protos/perfetto/trace/perfetto_trace.proto64
-rw-r--r--protos/perfetto/trace/ps/process_stats.proto7
-rw-r--r--protos/perfetto/trace/statsd/statsd_atom.proto2
-rw-r--r--protos/perfetto/trace_processor/BUILD.gn7
-rw-r--r--protos/perfetto/trace_processor/proto_files.gni3
-rw-r--r--protos/third_party/CHROMIUM_OWNERS4
-rw-r--r--protos/third_party/chromium/chrome_track_event.proto40
-rw-r--r--protos/third_party/statsd/shell_data.proto4
-rw-r--r--python/generators/stdlib_docs/parse.py4
-rw-r--r--python/generators/trace_processor_table/public.py3
-rw-r--r--python/generators/trace_processor_table/serialize.py133
-rw-r--r--python/generators/trace_processor_table/util.py205
-rwxr-xr-xpython/perfetto/prebuilts/manifests/trace_processor_shell.py62
-rwxr-xr-xpython/perfetto/prebuilts/manifests/tracebox.py56
-rwxr-xr-xpython/perfetto/prebuilts/manifests/traceconv.py62
-rw-r--r--python/perfetto/trace_processor/metrics.descriptor119
-rw-r--r--python/perfetto/trace_processor/metrics.descriptor.sha16
-rw-r--r--python/perfetto/trace_processor/trace_processor.descriptor.sha16
-rw-r--r--src/android_stats/perfetto_atoms.h1
-rw-r--r--src/base/http/BUILD.gn11
-rw-r--r--src/base/metatrace.cc7
-rw-r--r--src/cloud_trace_processor/BUILD.gn64
-rw-r--r--src/cloud_trace_processor/orchestrator_impl.cc210
-rw-r--r--src/cloud_trace_processor/orchestrator_impl.h61
-rw-r--r--src/cloud_trace_processor/trace_processor_wrapper.cc156
-rw-r--r--src/cloud_trace_processor/trace_processor_wrapper.h82
-rw-r--r--src/cloud_trace_processor/trace_processor_wrapper_unittest.cc205
-rw-r--r--src/cloud_trace_processor/worker_impl.cc118
-rw-r--r--src/cloud_trace_processor/worker_impl.h67
-rw-r--r--src/perfetto_cmd/perfetto_cmd.cc134
-rw-r--r--src/perfetto_cmd/perfetto_cmd.h13
-rw-r--r--src/profiling/perf/perf_producer.cc42
-rw-r--r--src/protozero/filtering/filter_util.cc43
-rw-r--r--src/protozero/filtering/filter_util.h18
-rw-r--r--src/protozero/filtering/filter_util_unittest.cc37
-rw-r--r--src/protozero/filtering/message_filter_unittest.cc81
-rw-r--r--src/protozero/packed_repeated_fields.cc5
-rw-r--r--src/protozero/proto_decoder_unittest.cc21
-rw-r--r--src/shared_lib/test/BUILD.gn8
-rw-r--r--src/tools/ftrace_proto_gen/event_list2
-rw-r--r--src/tools/ftrace_proto_gen/ftrace_proto_gen.cc5
-rw-r--r--src/tools/proto_filter/proto_filter.cc33
-rw-r--r--src/trace_processor/BUILD.gn1
-rw-r--r--src/trace_processor/containers/bit_vector.cc149
-rw-r--r--src/trace_processor/containers/bit_vector.h139
-rw-r--r--src/trace_processor/containers/bit_vector_unittest.cc77
-rw-r--r--src/trace_processor/containers/row_map.cc244
-rw-r--r--src/trace_processor/containers/row_map.h490
-rw-r--r--src/trace_processor/containers/row_map_unittest.cc265
-rw-r--r--src/trace_processor/containers/string_pool.cc17
-rw-r--r--src/trace_processor/db/BUILD.gn20
-rw-r--r--src/trace_processor/db/column.h35
-rw-r--r--src/trace_processor/db/column_overlay.cc (renamed from src/trace_processor/types/variadic.cc)12
-rw-r--r--src/trace_processor/db/column_overlay.h49
-rw-r--r--src/trace_processor/db/column_storage.h9
-rw-r--r--src/trace_processor/db/column_storage_overlay.h111
-rw-r--r--src/trace_processor/db/null_overlay.cc87
-rw-r--r--src/trace_processor/db/null_overlay.h51
-rw-r--r--src/trace_processor/db/numeric_storage.cc308
-rw-r--r--src/trace_processor/db/numeric_storage.h82
-rw-r--r--src/trace_processor/db/sorting_overlay.h47
-rw-r--r--src/trace_processor/db/storage.cc (renamed from protos/perfetto/trace_processor/cloud_trace_processor.proto)12
-rw-r--r--src/trace_processor/db/storage.h72
-rw-r--r--src/trace_processor/db/storage_overlay.cc61
-rw-r--r--src/trace_processor/db/storage_overlay.h44
-rw-r--r--src/trace_processor/db/storage_unittest.cc294
-rw-r--r--src/trace_processor/db/storage_variants.h108
-rw-r--r--src/trace_processor/db/table_unittest.cc130
-rw-r--r--src/trace_processor/db/view_unittest.cc169
-rw-r--r--src/trace_processor/db/view_unittest.py75
-rw-r--r--src/trace_processor/importers/common/args_translation_table.cc19
-rw-r--r--src/trace_processor/importers/common/track_tracker.cc48
-rw-r--r--src/trace_processor/importers/common/track_tracker.h27
-rw-r--r--src/trace_processor/importers/ftrace/ftrace_descriptors.cc22
-rw-r--r--src/trace_processor/importers/ftrace/ftrace_parser.cc103
-rw-r--r--src/trace_processor/importers/ftrace/ftrace_parser.h3
-rw-r--r--src/trace_processor/importers/ftrace/iostat_tracker.cc8
-rw-r--r--src/trace_processor/importers/ftrace/mali_gpu_event_tracker.cc66
-rw-r--r--src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h13
-rw-r--r--src/trace_processor/importers/ftrace/sched_event_tracker.cc4
-rw-r--r--src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc12
-rw-r--r--src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc38
-rw-r--r--src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc7
-rw-r--r--src/trace_processor/importers/fuchsia/fuchsia_trace_utils.cc2
-rw-r--r--src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h14
-rw-r--r--src/trace_processor/importers/proto/android_camera_event_module.h2
-rw-r--r--src/trace_processor/importers/proto/android_probes_module.cc9
-rw-r--r--src/trace_processor/importers/proto/android_probes_parser.cc53
-rw-r--r--src/trace_processor/importers/proto/android_probes_parser.h3
-rw-r--r--src/trace_processor/importers/proto/atoms.descriptorbin566028 -> 566680 bytes
-rw-r--r--src/trace_processor/importers/proto/chrome_system_probes_parser.h2
-rw-r--r--src/trace_processor/importers/proto/gpu_event_parser.cc4
-rw-r--r--src/trace_processor/importers/proto/proto_trace_parser.cc14
-rw-r--r--src/trace_processor/importers/proto/proto_trace_parser_unittest.cc8
-rw-r--r--src/trace_processor/importers/proto/statsd_module.h2
-rw-r--r--src/trace_processor/importers/proto/system_probes_parser.cc34
-rw-r--r--src/trace_processor/importers/proto/system_probes_parser.h2
-rw-r--r--src/trace_processor/importers/proto/track_event_tracker.cc5
-rw-r--r--src/trace_processor/importers/systrace/systrace_line_parser.cc12
-rw-r--r--src/trace_processor/importers/systrace/systrace_parser.cc8
-rw-r--r--src/trace_processor/metrics/metrics.h2
-rw-r--r--src/trace_processor/metrics/sql/android/BUILD.gn1
-rw-r--r--src/trace_processor/metrics/sql/android/android_batt.sql13
-rw-r--r--src/trace_processor/metrics/sql/android/android_binder.sql2
-rw-r--r--src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql30
-rw-r--r--src/trace_processor/metrics/sql/android/android_jank_cuj.sql10
-rw-r--r--src/trace_processor/metrics/sql/android/android_monitor_contention.sql3
-rw-r--r--src/trace_processor/metrics/sql/android/android_startup.sql29
-rw-r--r--src/trace_processor/metrics/sql/android/android_surfaceflinger.sql34
-rw-r--r--src/trace_processor/metrics/sql/android/frame_missed.sql8
-rw-r--r--src/trace_processor/metrics/sql/android/jank/cujs.sql16
-rw-r--r--src/trace_processor/metrics/sql/android/jank/cujs_boundaries.sql9
-rw-r--r--src/trace_processor/metrics/sql/android/jank/frames.sql13
-rw-r--r--src/trace_processor/metrics/sql/android/jank/internal/counters.sql29
-rw-r--r--src/trace_processor/metrics/sql/android/java_heap_stats.sql25
-rw-r--r--src/trace_processor/metrics/sql/android/network_activity_template.sql74
-rw-r--r--src/trace_processor/metrics/sql/android/process_metadata.sql4
-rw-r--r--src/trace_processor/metrics/sql/chrome/chrome_tasks_template.sql1
-rw-r--r--src/trace_processor/prelude/functions/BUILD.gn22
-rw-r--r--src/trace_processor/prelude/functions/clock_functions.h2
-rw-r--r--src/trace_processor/prelude/functions/create_function.cc64
-rw-r--r--src/trace_processor/prelude/functions/create_function.h24
-rw-r--r--src/trace_processor/prelude/functions/create_view_function.cc92
-rw-r--r--src/trace_processor/prelude/functions/create_view_function.h8
-rw-r--r--src/trace_processor/prelude/functions/import.h2
-rw-r--r--src/trace_processor/prelude/functions/register_function.h233
-rw-r--r--src/trace_processor/prelude/functions/sql_function.cc (renamed from src/trace_processor/prelude/functions/register_function.cc)6
-rw-r--r--src/trace_processor/prelude/functions/sql_function.h114
-rw-r--r--src/trace_processor/prelude/functions/stack_functions.cc20
-rw-r--r--src/trace_processor/prelude/functions/stack_functions.h3
-rw-r--r--src/trace_processor/prelude/functions/to_ftrace.cc (renamed from src/trace_processor/sqlite/sqlite_raw_table.cc)52
-rw-r--r--src/trace_processor/prelude/functions/to_ftrace.h (renamed from src/trace_processor/sqlite/sqlite_raw_table.h)33
-rw-r--r--src/trace_processor/prelude/functions/utils.h5
-rw-r--r--src/trace_processor/prelude/functions/window_functions.h2
-rw-r--r--src/trace_processor/prelude/operators/BUILD.gn1
-rw-r--r--src/trace_processor/prelude/operators/span_join_operator.cc39
-rw-r--r--src/trace_processor/prelude/operators/span_join_operator.h51
-rw-r--r--src/trace_processor/prelude/operators/span_join_operator_unittest.cc19
-rw-r--r--src/trace_processor/prelude/operators/window_operator.cc55
-rw-r--r--src/trace_processor/prelude/operators/window_operator.h36
-rw-r--r--src/trace_processor/prelude/table_functions/BUILD.gn26
-rw-r--r--src/trace_processor/prelude/table_functions/ancestor.cc1
-rw-r--r--src/trace_processor/prelude/table_functions/ancestor.h28
-rw-r--r--src/trace_processor/prelude/table_functions/ancestor_unittest.cc1
-rw-r--r--src/trace_processor/prelude/table_functions/connected_flow.h12
-rw-r--r--src/trace_processor/prelude/table_functions/descendant.cc1
-rw-r--r--src/trace_processor/prelude/table_functions/descendant.h17
-rw-r--r--src/trace_processor/prelude/table_functions/descendant_unittest.cc1
-rw-r--r--src/trace_processor/prelude/table_functions/experimental_annotated_stack.cc11
-rw-r--r--src/trace_processor/prelude/table_functions/experimental_counter_dur.cc10
-rw-r--r--src/trace_processor/prelude/table_functions/experimental_sched_upid.cc9
-rw-r--r--src/trace_processor/prelude/table_functions/experimental_slice_layout.cc2
-rw-r--r--src/trace_processor/prelude/table_functions/experimental_slice_layout.h12
-rw-r--r--src/trace_processor/prelude/table_functions/experimental_slice_layout_unittest.cc1
-rw-r--r--src/trace_processor/prelude/table_functions/tables.py166
-rw-r--r--src/trace_processor/prelude/tables_views/BUILD.gn31
-rw-r--r--src/trace_processor/prelude/tables_views/tables.sql25
-rw-r--r--src/trace_processor/prelude/tables_views/views.sql55
-rw-r--r--src/trace_processor/read_trace_integrationtest.cc24
-rw-r--r--src/trace_processor/sqlite/BUILD.gn24
-rw-r--r--src/trace_processor/sqlite/db_sqlite_table.cc59
-rw-r--r--src/trace_processor/sqlite/db_sqlite_table.h80
-rw-r--r--src/trace_processor/sqlite/query_cache.h1
-rw-r--r--src/trace_processor/sqlite/sql_stats_table.cc33
-rw-r--r--src/trace_processor/sqlite/sql_stats_table.h31
-rw-r--r--src/trace_processor/sqlite/sqlite_engine.cc154
-rw-r--r--src/trace_processor/sqlite/sqlite_engine.h263
-rw-r--r--src/trace_processor/sqlite/sqlite_table.cc283
-rw-r--r--src/trace_processor/sqlite/sqlite_table.h410
-rw-r--r--src/trace_processor/sqlite/stats_table.cc35
-rw-r--r--src/trace_processor/sqlite/stats_table.h29
-rw-r--r--src/trace_processor/stdlib/android/BUILD.gn3
-rw-r--r--src/trace_processor/stdlib/android/battery_stats.sql210
-rw-r--r--src/trace_processor/stdlib/android/binder.sql4
-rw-r--r--src/trace_processor/stdlib/android/monitor_contention.sql5
-rw-r--r--src/trace_processor/stdlib/android/network_packets.sql52
-rw-r--r--src/trace_processor/stdlib/android/process_metadata.sql22
-rw-r--r--src/trace_processor/stdlib/android/statsd.sql60
-rw-r--r--src/trace_processor/stdlib/chrome/BUILD.gn5
-rw-r--r--src/trace_processor/stdlib/chrome/chrome_scrolls.sql68
-rw-r--r--src/trace_processor/stdlib/common/BUILD.gn1
-rw-r--r--src/trace_processor/stdlib/common/cpus.sql60
-rw-r--r--src/trace_processor/storage/trace_storage.h12
-rw-r--r--src/trace_processor/tables/BUILD.gn17
-rw-r--r--src/trace_processor/tables/android_tables.py3
-rw-r--r--src/trace_processor/tables/counter_tables.h41
-rw-r--r--src/trace_processor/tables/counter_tables.py1
-rw-r--r--src/trace_processor/tables/flow_tables.h39
-rw-r--r--src/trace_processor/tables/flow_tables.py1
-rw-r--r--src/trace_processor/tables/macros.h102
-rw-r--r--src/trace_processor/tables/macros_internal.h683
-rw-r--r--src/trace_processor/tables/memory_tables.py4
-rw-r--r--src/trace_processor/tables/metadata_tables.py68
-rw-r--r--src/trace_processor/tables/profiler_tables.h44
-rw-r--r--src/trace_processor/tables/profiler_tables.py16
-rw-r--r--src/trace_processor/tables/py_tables_benchmark.cc (renamed from src/trace_processor/tables/macros_benchmark.cc)73
-rw-r--r--src/trace_processor/tables/py_tables_benchmark.py48
-rw-r--r--src/trace_processor/tables/py_tables_unittest.cc147
-rw-r--r--src/trace_processor/tables/py_tables_unittest.py22
-rw-r--r--src/trace_processor/tables/slice_tables.h59
-rw-r--r--src/trace_processor/tables/slice_tables.py192
-rw-r--r--src/trace_processor/tables/table_destructors.cc1
-rw-r--r--src/trace_processor/tables/trace_proto_tables.h52
-rw-r--r--src/trace_processor/tables/trace_proto_tables.py2
-rw-r--r--src/trace_processor/tables/track_tables.py16
-rw-r--r--src/trace_processor/tp_metatrace.cc21
-rw-r--r--src/trace_processor/trace_processor_impl.cc351
-rw-r--r--src/trace_processor/trace_processor_impl.h19
-rw-r--r--src/trace_processor/types/BUILD.gn1
-rw-r--r--src/trace_processor/util/status_macros.h2
-rw-r--r--src/trace_processor/views/BUILD.gn6
-rw-r--r--src/trace_processor/views/macros_internal.h11
-rw-r--r--src/trace_processor/views/macros_unittest.cc33
-rw-r--r--src/trace_processor/views/macros_unittest.py45
-rw-r--r--src/trace_processor/views/slice_views.h18
-rw-r--r--src/traceconv/trace_to_systrace.cc8
-rw-r--r--src/traced/probes/ftrace/cpu_reader_unittest.cc110
-rw-r--r--src/traced/probes/ftrace/event_info.cc35
-rw-r--r--src/traced/probes/ftrace/test/data/b281660544_new/available_events1
-rw-r--r--src/traced/probes/ftrace/test/data/b281660544_new/events/f2fs/f2fs_truncate_partial_nodes/format15
-rw-r--r--src/traced/probes/ftrace/test/data/b281660544_new/events/header_page4
-rw-r--r--src/traced/probes/ftrace/test/data/b281660544_old/available_events1
-rw-r--r--src/traced/probes/ftrace/test/data/b281660544_old/events/f2fs/f2fs_truncate_partial_nodes/format15
-rw-r--r--src/traced/probes/ftrace/test/data/b281660544_old/events/header_page4
-rw-r--r--src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_END/format13
-rw-r--r--src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_START/format13
-rw-r--r--src/traced/probes/ps/process_stats_data_source.cc38
-rw-r--r--src/traced/probes/ps/process_stats_data_source.h6
-rw-r--r--src/traced/probes/ps/process_stats_data_source_unittest.cc94
-rw-r--r--src/traced/probes/statsd_client/statsd_binder_data_source.cc38
-rw-r--r--src/traced/service/BUILD.gn4
-rw-r--r--src/traced/service/service.cc10
-rw-r--r--src/tracing/core/BUILD.gn27
-rw-r--r--src/tracing/core/metatrace_writer.cc5
-rw-r--r--src/tracing/core/shared_memory_abi.cc10
-rw-r--r--src/tracing/core/shared_memory_arbiter_impl.cc5
-rw-r--r--src/tracing/core/trace_buffer.cc3
-rw-r--r--src/tracing/core/tracing_service_impl.cc126
-rw-r--r--src/tracing/core/tracing_service_impl.h20
-rw-r--r--src/tracing/core/tracing_service_impl_unittest.cc392
-rw-r--r--src/tracing/core/virtual_destructors.cc7
-rw-r--r--src/tracing/core/zlib_compressor.cc173
-rw-r--r--src/tracing/core/zlib_compressor.h33
-rw-r--r--src/tracing/core/zlib_compressor_unittest.cc178
-rw-r--r--src/tracing/internal/tracing_muxer_impl.cc6
-rw-r--r--src/tracing/internal/tracing_muxer_impl.h2
-rw-r--r--src/tracing/internal/tracing_muxer_impl_integrationtest.cc8
-rw-r--r--src/tracing/ipc/consumer/consumer_ipc_client_impl.cc7
-rw-r--r--src/tracing/ipc/service/consumer_ipc_service.cc9
-rw-r--r--src/tracing/ipc/service/consumer_ipc_service.h2
-rw-r--r--src/tracing/ipc/service/service_ipc_host_impl.cc14
-rw-r--r--src/tracing/ipc/service/service_ipc_host_impl.h4
-rw-r--r--src/tracing/test/aligned_buffer_test.cc5
-rw-r--r--src/tracing/test/mock_consumer.h2
-rw-r--r--src/tracing/test/tracing_integration_test.cc2
-rw-r--r--test/cmdline_integrationtest.cc137
-rw-r--r--test/configs/BUILD.gn1
-rw-r--r--test/configs/snapshot.cfg49
-rw-r--r--test/configs/statsd.cfg2
-rw-r--r--test/cts/reporter/reporter_test_cts.cc2
-rw-r--r--test/data/fuchsia_events_and_args.fxt.sha2561
-rw-r--r--test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-android_trace_30s_load.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha2562
-rw-r--r--test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha2562
-rw-r--r--test/end_to_end_benchmark.cc4
-rw-r--r--test/ftrace_integrationtest.cc2
-rw-r--r--test/test_helper.cc2
-rw-r--r--test/test_helper.h2
-rw-r--r--test/trace_processor/diff_tests/android/android_battery_stats_event_slices.out4
-rw-r--r--test/trace_processor/diff_tests/android/android_battery_stats_state.out4
-rw-r--r--test/trace_processor/diff_tests/android/android_binder_metric.out2134
-rw-r--r--test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out30
-rwxr-xr-xtest/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py40
-rw-r--r--test/trace_processor/diff_tests/android/android_blocking_calls_on_jank_cuj_metric.out2
-rw-r--r--test/trace_processor/diff_tests/android/android_monitor_contention.out1146
-rw-r--r--test/trace_processor/diff_tests/android/android_network_activity.out4
-rw-r--r--test/trace_processor/diff_tests/android/android_system_property_slice.out6
-rw-r--r--test/trace_processor/diff_tests/android/tests.py175
-rw-r--r--test/trace_processor/diff_tests/android/tests_general.py71
-rw-r--r--test/trace_processor/diff_tests/chrome/chrome_scroll_check.py49
-rw-r--r--test/trace_processor/diff_tests/chrome/chrome_scroll_helper.py66
-rw-r--r--test/trace_processor/diff_tests/chrome/chrome_tasks.out8
-rw-r--r--test/trace_processor/diff_tests/chrome/scroll_jank_gpu_check.py46
-rw-r--r--test/trace_processor/diff_tests/chrome/tests_scroll_jank.py22
-rw-r--r--test/trace_processor/diff_tests/fuchsia/tests.py24
-rw-r--r--test/trace_processor/diff_tests/graphics/android_jank_cuj.out52
-rw-r--r--test/trace_processor/diff_tests/graphics/android_jank_cuj.py11
-rw-r--r--test/trace_processor/diff_tests/graphics/frame_missed.py14
-rw-r--r--test/trace_processor/diff_tests/graphics/tests.py14
-rw-r--r--test/trace_processor/diff_tests/parsing/sched_waking_raw_test.sql5
-rw-r--r--test/trace_processor/diff_tests/parsing/tests.py10
-rw-r--r--test/trace_processor/diff_tests/performance/frame_timeline_metric.out4
-rw-r--r--test/trace_processor/diff_tests/power/tests_power_rails.py14
-rw-r--r--test/trace_processor/diff_tests/profiling/heap_graph.textproto2
-rw-r--r--test/trace_processor/diff_tests/profiling/heap_stats_closest_proc.out2
-rw-r--r--test/trace_processor/diff_tests/profiling/java_heap_histogram.out3
-rw-r--r--test/trace_processor/diff_tests/profiling/tests.py1
-rw-r--r--test/trace_processor/diff_tests/profiling/tests_metrics.py2
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup.out3
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_attribution.out16
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_attribution.py11
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out5
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_breakdown.out3
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out3
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_lock_contention.out1
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out1
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_minsdk33.out1
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_process_track.out2
-rw-r--r--test/trace_processor/diff_tests/startup/android_startup_slow.out3
-rw-r--r--third_party/.gitignore3
-rwxr-xr-xtools/cpu_profile62
-rwxr-xr-xtools/gen_amalgamated1
-rwxr-xr-xtools/gen_android_bp3
-rwxr-xr-xtools/gen_bazel18
-rwxr-xr-xtools/gen_binary_descriptors66
-rwxr-xr-xtools/gen_tp_table_docs.py22
-rwxr-xr-xtools/gen_tp_table_headers.py70
-rwxr-xr-xtools/heap_profile62
-rwxr-xr-xtools/install-build-deps85
-rwxr-xr-xtools/record_android_trace56
-rw-r--r--tools/run_buildtools_binary.py8
-rwxr-xr-xtools/trace_processor62
-rwxr-xr-xtools/tracebox56
-rwxr-xr-xtools/traceconv62
-rw-r--r--ui/package-lock.json1538
-rw-r--r--ui/package.json3
-rw-r--r--ui/release/channels.json4
-rw-r--r--ui/src/assets/common.scss8
-rw-r--r--ui/src/assets/details.scss1
-rw-r--r--ui/src/assets/perfetto.scss1
-rw-r--r--ui/src/assets/record.scss2
-rw-r--r--ui/src/assets/widgets/form.scss (renamed from ui/src/base/math_utils.ts)29
-rw-r--r--ui/src/assets/widgets/menu.scss4
-rw-r--r--ui/src/base/bigint_math.ts77
-rw-r--r--ui/src/base/bigint_math_unittest.ts141
-rw-r--r--ui/src/base/math_utils_unittest.ts29
-rw-r--r--ui/src/common/actions.ts93
-rw-r--r--ui/src/common/actions_unittest.ts12
-rw-r--r--ui/src/common/canvas_utils.ts6
-rw-r--r--ui/src/common/empty_state.ts6
-rw-r--r--ui/src/common/engine.ts28
-rw-r--r--ui/src/common/high_precision_time.ts258
-rw-r--r--ui/src/common/high_precision_time_unittest.ts308
-rw-r--r--ui/src/common/internal_layout_utils.ts50
-rw-r--r--ui/src/common/logs.ts14
-rw-r--r--ui/src/common/plugin_api.ts13
-rw-r--r--ui/src/common/plugins.ts15
-rw-r--r--ui/src/common/state.ts58
-rw-r--r--ui/src/common/state_unittest.ts15
-rw-r--r--ui/src/common/time.ts131
-rw-r--r--ui/src/common/time_unittest.ts70
-rw-r--r--ui/src/common/track_data.ts8
-rw-r--r--ui/src/common/upload_utils.ts48
-rw-r--r--ui/src/common/upload_utils_unittest.ts105
-rw-r--r--ui/src/controller/aggregation/counter_aggregation_controller.ts15
-rw-r--r--ui/src/controller/aggregation/cpu_aggregation_controller.ts5
-rw-r--r--ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts5
-rw-r--r--ui/src/controller/aggregation/frame_aggregation_controller.ts5
-rw-r--r--ui/src/controller/aggregation/slice_aggregation_controller.ts5
-rw-r--r--ui/src/controller/aggregation/thread_aggregation_controller.ts9
-rw-r--r--ui/src/controller/area_selection_handler.ts6
-rw-r--r--ui/src/controller/area_selection_handler_unittest.ts16
-rw-r--r--ui/src/controller/flamegraph_controller.ts50
-rw-r--r--ui/src/controller/flow_events_controller.ts10
-rw-r--r--ui/src/controller/ftrace_controller.ts95
-rw-r--r--ui/src/controller/logs_controller.ts95
-rw-r--r--ui/src/controller/permalink_controller.ts3
-rw-r--r--ui/src/controller/record_controller.ts6
-rw-r--r--ui/src/controller/search_controller.ts60
-rw-r--r--ui/src/controller/selection_controller.ts59
-rw-r--r--ui/src/controller/trace_controller.ts138
-rw-r--r--ui/src/controller/track_controller.ts45
-rw-r--r--ui/src/controller/track_decider.ts103
-rw-r--r--ui/src/frontend/aggregation_panel.ts4
-rw-r--r--ui/src/frontend/base_slice_track.ts59
-rw-r--r--ui/src/frontend/base_slice_track_unittest.ts50
-rw-r--r--ui/src/frontend/chrome_slice_panel.ts46
-rw-r--r--ui/src/frontend/counter_panel.ts11
-rw-r--r--ui/src/frontend/debug.ts4
-rw-r--r--ui/src/frontend/details_panel.ts11
-rw-r--r--ui/src/frontend/drag/border_drag_strategy.ts19
-rw-r--r--ui/src/frontend/drag/drag_strategy.ts11
-rw-r--r--ui/src/frontend/drag/inner_drag_strategy.ts4
-rw-r--r--ui/src/frontend/drag/outer_drag_strategy.ts11
-rw-r--r--ui/src/frontend/drag_gesture_handler.ts6
-rw-r--r--ui/src/frontend/flamegraph_panel.ts107
-rw-r--r--ui/src/frontend/flow_events_renderer.ts2
-rw-r--r--ui/src/frontend/frontend_local_state.ts183
-rw-r--r--ui/src/frontend/ftrace_panel.ts16
-rw-r--r--ui/src/frontend/globals.ts93
-rw-r--r--ui/src/frontend/gridline_helper.ts218
-rw-r--r--ui/src/frontend/gridline_helper_unittest.ts360
-rw-r--r--ui/src/frontend/keyboard_event_handler.ts53
-rw-r--r--ui/src/frontend/logs_panel.ts39
-rw-r--r--ui/src/frontend/notes_panel.ts74
-rw-r--r--ui/src/frontend/overview_timeline_panel.ts50
-rw-r--r--ui/src/frontend/panel_container.ts13
-rw-r--r--ui/src/frontend/pivot_table_query_generator.ts5
-rw-r--r--ui/src/frontend/publish.ts5
-rw-r--r--ui/src/frontend/query_table.ts32
-rw-r--r--ui/src/frontend/scroll_helper.ts88
-rw-r--r--ui/src/frontend/search_handler.ts7
-rw-r--r--ui/src/frontend/slice.ts5
-rw-r--r--ui/src/frontend/slice_details_panel.ts19
-rw-r--r--ui/src/frontend/slice_panel.ts9
-rw-r--r--ui/src/frontend/sql_types.ts36
-rw-r--r--ui/src/frontend/thread_state.ts35
-rw-r--r--ui/src/frontend/tickmark_panel.ts57
-rw-r--r--ui/src/frontend/time_axis_panel.ts30
-rw-r--r--ui/src/frontend/time_scale.ts129
-rw-r--r--ui/src/frontend/time_scale_unittest.ts94
-rw-r--r--ui/src/frontend/time_selection_panel.ts71
-rw-r--r--ui/src/frontend/trace_converter.ts3
-rw-r--r--ui/src/frontend/track.ts10
-rw-r--r--ui/src/frontend/track_cache.ts1
-rw-r--r--ui/src/frontend/track_group_panel.ts31
-rw-r--r--ui/src/frontend/track_panel.ts61
-rw-r--r--ui/src/frontend/vertical_line_helper.ts20
-rw-r--r--ui/src/frontend/viewer_page.ts83
-rw-r--r--ui/src/frontend/widgets/button.ts10
-rw-r--r--ui/src/frontend/widgets/duration.ts6
-rw-r--r--ui/src/frontend/widgets/form.ts61
-rw-r--r--ui/src/frontend/widgets/menu.ts12
-rw-r--r--ui/src/frontend/widgets/popup.ts40
-rw-r--r--ui/src/frontend/widgets/timestamp.ts4
-rw-r--r--ui/src/frontend/widgets/tree.ts102
-rw-r--r--ui/src/frontend/widgets_page.ts63
-rw-r--r--ui/src/traceconv/index.ts6
-rw-r--r--ui/src/tracks/actual_frames/index.ts11
-rw-r--r--ui/src/tracks/android_log/index.ts28
-rw-r--r--ui/src/tracks/async_slices/index.ts22
-rw-r--r--ui/src/tracks/chrome_slices/index.ts78
-rw-r--r--ui/src/tracks/counter/index.ts99
-rw-r--r--ui/src/tracks/cpu_freq/index.ts52
-rw-r--r--ui/src/tracks/cpu_profile/index.ts28
-rw-r--r--ui/src/tracks/cpu_slices/index.ts76
-rw-r--r--ui/src/tracks/debug/add_debug_track_menu.ts95
-rw-r--r--ui/src/tracks/debug/details_tab.ts31
-rw-r--r--ui/src/tracks/debug/slice_track.ts4
-rw-r--r--ui/src/tracks/expected_frames/index.ts22
-rw-r--r--ui/src/tracks/ftrace/index.ts44
-rw-r--r--ui/src/tracks/heap_profile/index.ts36
-rw-r--r--ui/src/tracks/perf_samples_profile/index.ts34
-rw-r--r--ui/src/tracks/process_scheduling/index.ts53
-rw-r--r--ui/src/tracks/process_summary/index.ts49
-rw-r--r--ui/src/tracks/scroll_jank/event_latency_track.ts83
-rw-r--r--ui/src/tracks/scroll_jank/index.ts63
-rw-r--r--ui/src/tracks/scroll_jank/scroll_details_tab.ts90
-rw-r--r--ui/src/tracks/scroll_jank/scroll_track.ts116
-rw-r--r--ui/src/tracks/thread_state/index.ts64
529 files changed, 20626 insertions, 6727 deletions
diff --git a/.clang-tidy b/.clang-tidy
index 07073df36..8a822c2af 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,4 +1,4 @@
-Checks: android-cloexec-*,bugprone-*,google-explicit-constructor,android-comparison-in-temp-failure-retry,modernize-use-nullptr,performance-for-range-copy,performance-noexcept-move-constructor,readability-container-size-empty,readability-else-after-return
+Checks: android-cloexec-*,bugprone-*,-bugprone-easily-swappable-parameters,google-explicit-constructor,android-comparison-in-temp-failure-retry,modernize-use-nullptr,performance-for-range-copy,performance-noexcept-move-constructor,readability-container-size-empty,readability-else-after-return
CheckOptions:
- key: bugprone-assert-side-effect.AssertMacros
value: 'PERFETTO_DCHECK'
diff --git a/Android.bp b/Android.bp
index f12c1c39a..f4f9a2d09 100644
--- a/Android.bp
+++ b/Android.bp
@@ -593,6 +593,7 @@ cc_library_shared {
":perfetto_src_tracing_common",
":perfetto_src_tracing_core_core",
":perfetto_src_tracing_core_service",
+ ":perfetto_src_tracing_core_zlib_compressor",
":perfetto_src_tracing_ipc_common",
":perfetto_src_tracing_ipc_default_socket",
":perfetto_src_tracing_ipc_producer_producer",
@@ -660,10 +661,19 @@ cc_library_shared {
defaults: [
"perfetto_defaults",
],
+ cflags: [
+ "-DZLIB_IMPLEMENTATION",
+ ],
target: {
android: {
shared_libs: [
"liblog",
+ "libz",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libz",
],
},
},
@@ -1735,6 +1745,11 @@ filegroup {
name: "perfetto_include_perfetto_ext_base_version",
}
+// GN: //include/perfetto/ext/cloud_trace_processor:cloud_trace_processor
+filegroup {
+ name: "perfetto_include_perfetto_ext_cloud_trace_processor_cloud_trace_processor",
+}
+
// GN: //include/perfetto/ext/ipc:ipc
filegroup {
name: "perfetto_include_perfetto_ext_ipc_ipc",
@@ -2049,11 +2064,13 @@ cc_test {
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_metrics",
":perfetto_src_trace_processor_prelude_functions_functions",
+ ":perfetto_src_trace_processor_prelude_functions_interface",
":perfetto_src_trace_processor_prelude_operators_operators",
+ ":perfetto_src_trace_processor_prelude_table_functions_interface",
":perfetto_src_trace_processor_prelude_table_functions_table_functions",
":perfetto_src_trace_processor_sorter_sorter",
+ ":perfetto_src_trace_processor_sqlite_query_constraints",
":perfetto_src_trace_processor_sqlite_sqlite",
- ":perfetto_src_trace_processor_sqlite_sqlite_minimal",
":perfetto_src_trace_processor_storage_minimal",
":perfetto_src_trace_processor_storage_storage",
":perfetto_src_trace_processor_tables_tables",
@@ -2248,6 +2265,8 @@ cc_test {
"perfetto_src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
"perfetto_src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ "perfetto_src_trace_processor_prelude_table_functions_tables",
+ "perfetto_src_trace_processor_prelude_tables_views_tables_views",
"perfetto_src_trace_processor_stdlib_gen_amalgamated_stdlib",
"perfetto_src_trace_processor_tables_tables_python",
],
@@ -2268,6 +2287,48 @@ cc_test {
test_config: "PerfettoIntegrationTests.xml",
}
+// GN: //protos/perfetto/cloud_trace_processor:lite
+genrule {
+ name: "perfetto_protos_perfetto_cloud_trace_processor_lite_gen",
+ srcs: [
+ "protos/perfetto/cloud_trace_processor/common.proto",
+ "protos/perfetto/cloud_trace_processor/orchestrator.proto",
+ "protos/perfetto/cloud_trace_processor/worker.proto",
+ ],
+ tools: [
+ "aprotoc",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/cloud_trace_processor/common.pb.cc",
+ "external/perfetto/protos/perfetto/cloud_trace_processor/orchestrator.pb.cc",
+ "external/perfetto/protos/perfetto/cloud_trace_processor/worker.pb.cc",
+ ],
+}
+
+// GN: //protos/perfetto/cloud_trace_processor:lite
+genrule {
+ name: "perfetto_protos_perfetto_cloud_trace_processor_lite_gen_headers",
+ srcs: [
+ "protos/perfetto/cloud_trace_processor/common.proto",
+ "protos/perfetto/cloud_trace_processor/orchestrator.proto",
+ "protos/perfetto/cloud_trace_processor/worker.proto",
+ ],
+ tools: [
+ "aprotoc",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/cloud_trace_processor/common.pb.h",
+ "external/perfetto/protos/perfetto/cloud_trace_processor/orchestrator.pb.h",
+ "external/perfetto/protos/perfetto/cloud_trace_processor/worker.pb.h",
+ ],
+ export_include_dirs: [
+ ".",
+ "protos",
+ ],
+}
+
// GN: //protos/perfetto/common:cpp
genrule {
name: "perfetto_protos_perfetto_common_cpp_gen",
@@ -6848,6 +6909,48 @@ genrule {
],
}
+// GN: //protos/perfetto/trace_processor:lite
+genrule {
+ name: "perfetto_protos_perfetto_trace_processor_lite_gen",
+ srcs: [
+ "protos/perfetto/trace_processor/metatrace_categories.proto",
+ "protos/perfetto/trace_processor/stack.proto",
+ "protos/perfetto/trace_processor/trace_processor.proto",
+ ],
+ tools: [
+ "aprotoc",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pb.cc",
+ "external/perfetto/protos/perfetto/trace_processor/stack.pb.cc",
+ "external/perfetto/protos/perfetto/trace_processor/trace_processor.pb.cc",
+ ],
+}
+
+// GN: //protos/perfetto/trace_processor:lite
+genrule {
+ name: "perfetto_protos_perfetto_trace_processor_lite_gen_headers",
+ srcs: [
+ "protos/perfetto/trace_processor/metatrace_categories.proto",
+ "protos/perfetto/trace_processor/stack.proto",
+ "protos/perfetto/trace_processor/trace_processor.proto",
+ ],
+ tools: [
+ "aprotoc",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pb.h",
+ "external/perfetto/protos/perfetto/trace_processor/stack.pb.h",
+ "external/perfetto/protos/perfetto/trace_processor/trace_processor.pb.h",
+ ],
+ export_include_dirs: [
+ ".",
+ "protos",
+ ],
+}
+
// GN: //protos/perfetto/trace_processor:metrics_impl_zero
genrule {
name: "perfetto_protos_perfetto_trace_processor_metrics_impl_zero_gen",
@@ -6888,7 +6991,6 @@ genrule {
genrule {
name: "perfetto_protos_perfetto_trace_processor_zero_gen",
srcs: [
- "protos/perfetto/trace_processor/cloud_trace_processor.proto",
"protos/perfetto/trace_processor/metatrace_categories.proto",
"protos/perfetto/trace_processor/stack.proto",
"protos/perfetto/trace_processor/trace_processor.proto",
@@ -6899,7 +7001,6 @@ genrule {
],
cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
out: [
- "external/perfetto/protos/perfetto/trace_processor/cloud_trace_processor.pbzero.cc",
"external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pbzero.cc",
"external/perfetto/protos/perfetto/trace_processor/stack.pbzero.cc",
"external/perfetto/protos/perfetto/trace_processor/trace_processor.pbzero.cc",
@@ -6910,7 +7011,6 @@ genrule {
genrule {
name: "perfetto_protos_perfetto_trace_processor_zero_gen_headers",
srcs: [
- "protos/perfetto/trace_processor/cloud_trace_processor.proto",
"protos/perfetto/trace_processor/metatrace_categories.proto",
"protos/perfetto/trace_processor/stack.proto",
"protos/perfetto/trace_processor/trace_processor.proto",
@@ -6921,7 +7021,6 @@ genrule {
],
cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
out: [
- "external/perfetto/protos/perfetto/trace_processor/cloud_trace_processor.pbzero.h",
"external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pbzero.h",
"external/perfetto/protos/perfetto/trace_processor/stack.pbzero.h",
"external/perfetto/protos/perfetto/trace_processor/trace_processor.pbzero.h",
@@ -8374,6 +8473,24 @@ genrule {
],
}
+// GN: //src/cloud_trace_processor:sources
+filegroup {
+ name: "perfetto_src_cloud_trace_processor_sources",
+ srcs: [
+ "src/cloud_trace_processor/orchestrator_impl.cc",
+ "src/cloud_trace_processor/trace_processor_wrapper.cc",
+ "src/cloud_trace_processor/worker_impl.cc",
+ ],
+}
+
+// GN: //src/cloud_trace_processor:unittests
+filegroup {
+ name: "perfetto_src_cloud_trace_processor_unittests",
+ srcs: [
+ "src/cloud_trace_processor/trace_processor_wrapper_unittest.cc",
+ ],
+}
+
// GN: //src/ipc:client
filegroup {
name: "perfetto_src_ipc_client",
@@ -9280,7 +9397,12 @@ filegroup {
name: "perfetto_src_trace_processor_db_db",
srcs: [
"src/trace_processor/db/column.cc",
+ "src/trace_processor/db/column_overlay.cc",
"src/trace_processor/db/column_storage.cc",
+ "src/trace_processor/db/null_overlay.cc",
+ "src/trace_processor/db/numeric_storage.cc",
+ "src/trace_processor/db/storage.cc",
+ "src/trace_processor/db/storage_overlay.cc",
"src/trace_processor/db/table.cc",
"src/trace_processor/db/view.cc",
],
@@ -9292,11 +9414,39 @@ filegroup {
srcs: [
"src/trace_processor/db/column_storage_overlay_unittest.cc",
"src/trace_processor/db/compare_unittest.cc",
- "src/trace_processor/db/table_unittest.cc",
+ "src/trace_processor/db/storage_unittest.cc",
"src/trace_processor/db/view_unittest.cc",
],
}
+// GN: //src/trace_processor/db:view_unittest
+genrule {
+ name: "perfetto_src_trace_processor_db_view_unittest",
+ srcs: [
+ "src/trace_processor/db/view_unittest.py",
+ ],
+ tools: [
+ "perfetto_src_trace_processor_db_view_unittest_binary",
+ ],
+ cmd: "$(location perfetto_src_trace_processor_db_view_unittest_binary) --gen-dir=$(genDir) --relative-input-dir=external/perfetto --inputs $(in)",
+ out: [
+ "src/trace_processor/db/view_unittest_py.h",
+ ],
+}
+
+// GN: //src/trace_processor/db:view_unittest
+python_binary_host {
+ name: "perfetto_src_trace_processor_db_view_unittest_binary",
+ srcs: [
+ "python/generators/trace_processor_table/public.py",
+ "python/generators/trace_processor_table/serialize.py",
+ "python/generators/trace_processor_table/util.py",
+ "src/trace_processor/db/view_unittest.py",
+ "tools/gen_tp_table_headers.py",
+ ],
+ main: "tools/gen_tp_table_headers.py",
+}
+
// GN: //src/trace_processor:demangle
cc_library_static {
name: "perfetto_src_trace_processor_demangle",
@@ -9890,6 +10040,7 @@ genrule {
"src/trace_processor/metrics/sql/android/java_heap_histogram.sql",
"src/trace_processor/metrics/sql/android/java_heap_stats.sql",
"src/trace_processor/metrics/sql/android/mem_stats_priority_breakdown.sql",
+ "src/trace_processor/metrics/sql/android/network_activity_template.sql",
"src/trace_processor/metrics/sql/android/p_state.sql",
"src/trace_processor/metrics/sql/android/power_drain_in_watts.sql",
"src/trace_processor/metrics/sql/android/power_profile_data.sql",
@@ -10019,9 +10170,17 @@ filegroup {
"src/trace_processor/prelude/functions/import.cc",
"src/trace_processor/prelude/functions/layout_functions.cc",
"src/trace_processor/prelude/functions/pprof_functions.cc",
- "src/trace_processor/prelude/functions/register_function.cc",
"src/trace_processor/prelude/functions/sqlite3_str_split.cc",
"src/trace_processor/prelude/functions/stack_functions.cc",
+ "src/trace_processor/prelude/functions/to_ftrace.cc",
+ ],
+}
+
+// GN: //src/trace_processor/prelude/functions:interface
+filegroup {
+ name: "perfetto_src_trace_processor_prelude_functions_interface",
+ srcs: [
+ "src/trace_processor/prelude/functions/sql_function.cc",
],
}
@@ -10050,6 +10209,14 @@ filegroup {
],
}
+// GN: //src/trace_processor/prelude/table_functions:interface
+filegroup {
+ name: "perfetto_src_trace_processor_prelude_table_functions_interface",
+ srcs: [
+ "src/trace_processor/prelude/table_functions/table_function.cc",
+ ],
+}
+
// GN: //src/trace_processor/prelude/table_functions:table_functions
filegroup {
name: "perfetto_src_trace_processor_prelude_table_functions_table_functions",
@@ -10064,11 +10231,47 @@ filegroup {
"src/trace_processor/prelude/table_functions/experimental_sched_upid.cc",
"src/trace_processor/prelude/table_functions/experimental_slice_layout.cc",
"src/trace_processor/prelude/table_functions/flamegraph_construction_algorithms.cc",
- "src/trace_processor/prelude/table_functions/table_function.cc",
"src/trace_processor/prelude/table_functions/view.cc",
],
}
+// GN: //src/trace_processor/prelude/table_functions:tables
+genrule {
+ name: "perfetto_src_trace_processor_prelude_table_functions_tables",
+ srcs: [
+ "src/trace_processor/prelude/table_functions/tables.py",
+ ],
+ tools: [
+ "perfetto_src_trace_processor_prelude_table_functions_tables_binary",
+ ],
+ cmd: "$(location perfetto_src_trace_processor_prelude_table_functions_tables_binary) --gen-dir=$(genDir) --relative-input-dir=external/perfetto --inputs $(in)",
+ out: [
+ "src/trace_processor/prelude/table_functions/tables_py.h",
+ ],
+}
+
+// GN: //src/trace_processor/prelude/table_functions:tables
+python_binary_host {
+ name: "perfetto_src_trace_processor_prelude_table_functions_tables_binary",
+ srcs: [
+ "python/generators/trace_processor_table/public.py",
+ "python/generators/trace_processor_table/serialize.py",
+ "python/generators/trace_processor_table/util.py",
+ "src/trace_processor/prelude/table_functions/tables.py",
+ "src/trace_processor/tables/android_tables.py",
+ "src/trace_processor/tables/counter_tables.py",
+ "src/trace_processor/tables/flow_tables.py",
+ "src/trace_processor/tables/memory_tables.py",
+ "src/trace_processor/tables/metadata_tables.py",
+ "src/trace_processor/tables/profiler_tables.py",
+ "src/trace_processor/tables/slice_tables.py",
+ "src/trace_processor/tables/trace_proto_tables.py",
+ "src/trace_processor/tables/track_tables.py",
+ "tools/gen_tp_table_headers.py",
+ ],
+ main: "tools/gen_tp_table_headers.py",
+}
+
// GN: //src/trace_processor/prelude/table_functions:unittests
filegroup {
name: "perfetto_src_trace_processor_prelude_table_functions_unittests",
@@ -10082,6 +10285,22 @@ filegroup {
],
}
+// GN: //src/trace_processor/prelude/tables_views:tables_views
+genrule {
+ name: "perfetto_src_trace_processor_prelude_tables_views_tables_views",
+ srcs: [
+ "src/trace_processor/prelude/tables_views/tables.sql",
+ "src/trace_processor/prelude/tables_views/views.sql",
+ ],
+ cmd: "$(location tools/gen_amalgamated_sql.py) --namespace=prelude::tables_views --cpp-out=$(out) $(in)",
+ out: [
+ "src/trace_processor/prelude/tables_views/tables_views.h",
+ ],
+ tool_files: [
+ "tools/gen_amalgamated_sql.py",
+ ],
+}
+
// GN: //src/trace_processor/rpc:httpd
filegroup {
name: "perfetto_src_trace_processor_rpc_httpd",
@@ -10125,24 +10344,24 @@ filegroup {
],
}
-// GN: //src/trace_processor/sqlite:sqlite
+// GN: //src/trace_processor/sqlite:query_constraints
filegroup {
- name: "perfetto_src_trace_processor_sqlite_sqlite",
+ name: "perfetto_src_trace_processor_sqlite_query_constraints",
srcs: [
- "src/trace_processor/sqlite/db_sqlite_table.cc",
- "src/trace_processor/sqlite/sql_stats_table.cc",
- "src/trace_processor/sqlite/sqlite_raw_table.cc",
- "src/trace_processor/sqlite/sqlite_utils.cc",
- "src/trace_processor/sqlite/stats_table.cc",
+ "src/trace_processor/sqlite/query_constraints.cc",
],
}
-// GN: //src/trace_processor/sqlite:sqlite_minimal
+// GN: //src/trace_processor/sqlite:sqlite
filegroup {
- name: "perfetto_src_trace_processor_sqlite_sqlite_minimal",
+ name: "perfetto_src_trace_processor_sqlite_sqlite",
srcs: [
- "src/trace_processor/sqlite/query_constraints.cc",
+ "src/trace_processor/sqlite/db_sqlite_table.cc",
+ "src/trace_processor/sqlite/sql_stats_table.cc",
+ "src/trace_processor/sqlite/sqlite_engine.cc",
"src/trace_processor/sqlite/sqlite_table.cc",
+ "src/trace_processor/sqlite/sqlite_utils.cc",
+ "src/trace_processor/sqlite/stats_table.cc",
],
}
@@ -10161,16 +10380,21 @@ genrule {
name: "perfetto_src_trace_processor_stdlib_gen_amalgamated_stdlib",
srcs: [
"src/trace_processor/stdlib/android/battery.sql",
+ "src/trace_processor/stdlib/android/battery_stats.sql",
"src/trace_processor/stdlib/android/binder.sql",
"src/trace_processor/stdlib/android/monitor_contention.sql",
+ "src/trace_processor/stdlib/android/network_packets.sql",
"src/trace_processor/stdlib/android/process_metadata.sql",
"src/trace_processor/stdlib/android/slices.sql",
"src/trace_processor/stdlib/android/startup/internal_startups_maxsdk28.sql",
"src/trace_processor/stdlib/android/startup/internal_startups_minsdk29.sql",
"src/trace_processor/stdlib/android/startup/internal_startups_minsdk33.sql",
"src/trace_processor/stdlib/android/startup/startups.sql",
+ "src/trace_processor/stdlib/android/statsd.sql",
+ "src/trace_processor/stdlib/chrome/chrome_scrolls.sql",
"src/trace_processor/stdlib/chrome/cpu_powerups.sql",
"src/trace_processor/stdlib/common/counters.sql",
+ "src/trace_processor/stdlib/common/cpus.sql",
"src/trace_processor/stdlib/common/metadata.sql",
"src/trace_processor/stdlib/common/percentiles.sql",
"src/trace_processor/stdlib/common/slices.sql",
@@ -10218,7 +10442,7 @@ genrule {
tools: [
"perfetto_src_trace_processor_tables_py_tables_unittest_binary",
],
- cmd: "$(location perfetto_src_trace_processor_tables_py_tables_unittest_binary) --gen-dir=$(genDir) --inputs $(in) --outputs $(out)",
+ cmd: "$(location perfetto_src_trace_processor_tables_py_tables_unittest_binary) --gen-dir=$(genDir) --relative-input-dir=external/perfetto --inputs $(in)",
out: [
"src/trace_processor/tables/py_tables_unittest_py.h",
],
@@ -10262,7 +10486,7 @@ genrule {
tools: [
"perfetto_src_trace_processor_tables_tables_python_binary",
],
- cmd: "$(location perfetto_src_trace_processor_tables_tables_python_binary) --gen-dir=$(genDir) --inputs $(in) --outputs $(out)",
+ cmd: "$(location perfetto_src_trace_processor_tables_tables_python_binary) --gen-dir=$(genDir) --relative-input-dir=external/perfetto --inputs $(in)",
out: [
"src/trace_processor/tables/android_tables_py.h",
"src/trace_processor/tables/counter_tables_py.h",
@@ -10301,7 +10525,6 @@ python_binary_host {
filegroup {
name: "perfetto_src_trace_processor_tables_unittests",
srcs: [
- "src/trace_processor/tables/macros_unittest.cc",
"src/trace_processor/tables/py_tables_unittest.cc",
],
}
@@ -10322,7 +10545,6 @@ filegroup {
"src/trace_processor/types/destructible.cc",
"src/trace_processor/types/gfp_flags.cc",
"src/trace_processor/types/task_state.cc",
- "src/trace_processor/types/variadic.cc",
],
}
@@ -10462,6 +10684,34 @@ filegroup {
],
}
+// GN: //src/trace_processor/views:macros_unittest
+genrule {
+ name: "perfetto_src_trace_processor_views_macros_unittest",
+ srcs: [
+ "src/trace_processor/views/macros_unittest.py",
+ ],
+ tools: [
+ "perfetto_src_trace_processor_views_macros_unittest_binary",
+ ],
+ cmd: "$(location perfetto_src_trace_processor_views_macros_unittest_binary) --gen-dir=$(genDir) --relative-input-dir=external/perfetto --inputs $(in)",
+ out: [
+ "src/trace_processor/views/macros_unittest_py.h",
+ ],
+}
+
+// GN: //src/trace_processor/views:macros_unittest
+python_binary_host {
+ name: "perfetto_src_trace_processor_views_macros_unittest_binary",
+ srcs: [
+ "python/generators/trace_processor_table/public.py",
+ "python/generators/trace_processor_table/serialize.py",
+ "python/generators/trace_processor_table/util.py",
+ "src/trace_processor/views/macros_unittest.py",
+ "tools/gen_tp_table_headers.py",
+ ],
+ main: "tools/gen_tp_table_headers.py",
+}
+
// GN: //src/trace_processor/views:unittests
filegroup {
name: "perfetto_src_trace_processor_views_unittests",
@@ -10523,6 +10773,14 @@ filegroup {
],
}
+// GN: //src/traceconv:unittests
+filegroup {
+ name: "perfetto_src_traceconv_unittests",
+ srcs: [
+ "src/traceconv/trace_to_text_unittest.cc",
+ ],
+}
+
// GN: //src/traceconv:utils
filegroup {
name: "perfetto_src_traceconv_utils",
@@ -11077,6 +11335,15 @@ filegroup {
"src/tracing/core/trace_packet_unittest.cc",
"src/tracing/core/trace_writer_impl_unittest.cc",
"src/tracing/core/tracing_service_impl_unittest.cc",
+ "src/tracing/core/zlib_compressor_unittest.cc",
+ ],
+}
+
+// GN: //src/tracing/core:zlib_compressor
+filegroup {
+ name: "perfetto_src_tracing_core_zlib_compressor",
+ srcs: [
+ "src/tracing/core/zlib_compressor.cc",
],
}
@@ -11572,6 +11839,7 @@ cc_test {
":perfetto_include_perfetto_ext_base_http_http",
":perfetto_include_perfetto_ext_base_threading_threading",
":perfetto_include_perfetto_ext_base_version",
+ ":perfetto_include_perfetto_ext_cloud_trace_processor_cloud_trace_processor",
":perfetto_include_perfetto_ext_ipc_ipc",
":perfetto_include_perfetto_ext_trace_processor_demangle",
":perfetto_include_perfetto_ext_trace_processor_export_json",
@@ -11580,6 +11848,7 @@ cc_test {
":perfetto_include_perfetto_ext_traced_traced",
":perfetto_include_perfetto_ext_tracing_core_core",
":perfetto_include_perfetto_ext_tracing_ipc_ipc",
+ ":perfetto_include_perfetto_profiling_pprof_builder",
":perfetto_include_perfetto_protozero_protozero",
":perfetto_include_perfetto_public_abi_base",
":perfetto_include_perfetto_public_base",
@@ -11591,6 +11860,7 @@ cc_test {
":perfetto_include_perfetto_tracing_core_core",
":perfetto_include_perfetto_tracing_core_forward_decls",
":perfetto_include_perfetto_tracing_tracing",
+ ":perfetto_protos_perfetto_cloud_trace_processor_lite_gen",
":perfetto_protos_perfetto_common_cpp_gen",
":perfetto_protos_perfetto_common_lite_gen",
":perfetto_protos_perfetto_common_zero_gen",
@@ -11666,6 +11936,7 @@ cc_test {
":perfetto_protos_perfetto_trace_power_cpp_gen",
":perfetto_protos_perfetto_trace_power_lite_gen",
":perfetto_protos_perfetto_trace_power_zero_gen",
+ ":perfetto_protos_perfetto_trace_processor_lite_gen",
":perfetto_protos_perfetto_trace_processor_metrics_impl_zero_gen",
":perfetto_protos_perfetto_trace_processor_zero_gen",
":perfetto_protos_perfetto_trace_profiling_cpp_gen",
@@ -11704,6 +11975,8 @@ cc_test {
":perfetto_src_base_unittests",
":perfetto_src_base_unix_socket",
":perfetto_src_base_version",
+ ":perfetto_src_cloud_trace_processor_sources",
+ ":perfetto_src_cloud_trace_processor_unittests",
":perfetto_src_ipc_client",
":perfetto_src_ipc_common",
":perfetto_src_ipc_host",
@@ -11741,6 +12014,7 @@ cc_test {
":perfetto_src_profiling_perf_producer_unittests",
":perfetto_src_profiling_perf_regs_parsing",
":perfetto_src_profiling_perf_unwinding",
+ ":perfetto_src_profiling_symbolizer_symbolize_database",
":perfetto_src_profiling_symbolizer_symbolizer",
":perfetto_src_profiling_symbolizer_unittests",
":perfetto_src_profiling_unittests",
@@ -11798,17 +12072,19 @@ cc_test {
":perfetto_src_trace_processor_metrics_metrics",
":perfetto_src_trace_processor_metrics_unittests",
":perfetto_src_trace_processor_prelude_functions_functions",
+ ":perfetto_src_trace_processor_prelude_functions_interface",
":perfetto_src_trace_processor_prelude_functions_unittests",
":perfetto_src_trace_processor_prelude_operators_operators",
":perfetto_src_trace_processor_prelude_operators_unittests",
+ ":perfetto_src_trace_processor_prelude_table_functions_interface",
":perfetto_src_trace_processor_prelude_table_functions_table_functions",
":perfetto_src_trace_processor_prelude_table_functions_unittests",
":perfetto_src_trace_processor_rpc_rpc",
":perfetto_src_trace_processor_rpc_unittests",
":perfetto_src_trace_processor_sorter_sorter",
":perfetto_src_trace_processor_sorter_unittests",
+ ":perfetto_src_trace_processor_sqlite_query_constraints",
":perfetto_src_trace_processor_sqlite_sqlite",
- ":perfetto_src_trace_processor_sqlite_sqlite_minimal",
":perfetto_src_trace_processor_sqlite_unittests",
":perfetto_src_trace_processor_storage_minimal",
":perfetto_src_trace_processor_storage_storage",
@@ -11835,6 +12111,10 @@ cc_test {
":perfetto_src_trace_processor_util_zip_reader",
":perfetto_src_trace_processor_views_unittests",
":perfetto_src_trace_processor_views_views",
+ ":perfetto_src_traceconv_lib",
+ ":perfetto_src_traceconv_pprofbuilder",
+ ":perfetto_src_traceconv_unittests",
+ ":perfetto_src_traceconv_utils",
":perfetto_src_traced_probes_android_game_intervention_list_android_game_intervention_list",
":perfetto_src_traced_probes_android_game_intervention_list_unittests",
":perfetto_src_traced_probes_android_log_android_log",
@@ -11882,6 +12162,7 @@ cc_test {
":perfetto_src_tracing_core_service",
":perfetto_src_tracing_core_test_support",
":perfetto_src_tracing_core_unittests",
+ ":perfetto_src_tracing_core_zlib_compressor",
":perfetto_src_tracing_ipc_common",
":perfetto_src_tracing_ipc_consumer_consumer",
":perfetto_src_tracing_ipc_default_socket",
@@ -11915,6 +12196,7 @@ cc_test {
"perfetto_gtest_logcat_printer",
],
generated_headers: [
+ "perfetto_protos_perfetto_cloud_trace_processor_lite_gen_headers",
"perfetto_protos_perfetto_common_cpp_gen_headers",
"perfetto_protos_perfetto_common_lite_gen_headers",
"perfetto_protos_perfetto_common_zero_gen_headers",
@@ -11990,6 +12272,7 @@ cc_test {
"perfetto_protos_perfetto_trace_power_cpp_gen_headers",
"perfetto_protos_perfetto_trace_power_lite_gen_headers",
"perfetto_protos_perfetto_trace_power_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_processor_lite_gen_headers",
"perfetto_protos_perfetto_trace_processor_metrics_impl_zero_gen_headers",
"perfetto_protos_perfetto_trace_processor_zero_gen_headers",
"perfetto_protos_perfetto_trace_profiling_cpp_gen_headers",
@@ -12023,6 +12306,7 @@ cc_test {
"perfetto_src_protozero_testing_messages_cpp_gen_headers",
"perfetto_src_protozero_testing_messages_lite_gen_headers",
"perfetto_src_protozero_testing_messages_zero_gen_headers",
+ "perfetto_src_trace_processor_db_view_unittest",
"perfetto_src_trace_processor_gen_cc_test_messages_descriptor",
"perfetto_src_trace_processor_importers_proto_gen_cc_chrome_track_event_descriptor",
"perfetto_src_trace_processor_importers_proto_gen_cc_config_descriptor",
@@ -12033,9 +12317,13 @@ cc_test {
"perfetto_src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
"perfetto_src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ "perfetto_src_trace_processor_prelude_table_functions_tables",
+ "perfetto_src_trace_processor_prelude_tables_views_tables_views",
"perfetto_src_trace_processor_stdlib_gen_amalgamated_stdlib",
"perfetto_src_trace_processor_tables_py_tables_unittest",
"perfetto_src_trace_processor_tables_tables_python",
+ "perfetto_src_trace_processor_views_macros_unittest",
+ "perfetto_src_traceconv_gen_cc_trace_descriptor",
"perfetto_src_traced_probes_ftrace_test_messages_cpp_gen_headers",
"perfetto_src_traced_probes_ftrace_test_messages_lite_gen_headers",
"perfetto_src_traced_probes_ftrace_test_messages_zero_gen_headers",
@@ -12471,13 +12759,15 @@ cc_binary {
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_metrics",
":perfetto_src_trace_processor_prelude_functions_functions",
+ ":perfetto_src_trace_processor_prelude_functions_interface",
":perfetto_src_trace_processor_prelude_operators_operators",
+ ":perfetto_src_trace_processor_prelude_table_functions_interface",
":perfetto_src_trace_processor_prelude_table_functions_table_functions",
":perfetto_src_trace_processor_rpc_httpd",
":perfetto_src_trace_processor_rpc_rpc",
":perfetto_src_trace_processor_sorter_sorter",
+ ":perfetto_src_trace_processor_sqlite_query_constraints",
":perfetto_src_trace_processor_sqlite_sqlite",
- ":perfetto_src_trace_processor_sqlite_sqlite_minimal",
":perfetto_src_trace_processor_storage_minimal",
":perfetto_src_trace_processor_storage_storage",
":perfetto_src_trace_processor_tables_tables",
@@ -12549,6 +12839,8 @@ cc_binary {
"perfetto_src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
"perfetto_src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ "perfetto_src_trace_processor_prelude_table_functions_tables",
+ "perfetto_src_trace_processor_prelude_tables_views_tables_views",
"perfetto_src_trace_processor_stdlib_gen_amalgamated_stdlib",
"perfetto_src_trace_processor_tables_tables_python",
],
@@ -12692,11 +12984,13 @@ cc_binary_host {
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_metrics",
":perfetto_src_trace_processor_prelude_functions_functions",
+ ":perfetto_src_trace_processor_prelude_functions_interface",
":perfetto_src_trace_processor_prelude_operators_operators",
+ ":perfetto_src_trace_processor_prelude_table_functions_interface",
":perfetto_src_trace_processor_prelude_table_functions_table_functions",
":perfetto_src_trace_processor_sorter_sorter",
+ ":perfetto_src_trace_processor_sqlite_query_constraints",
":perfetto_src_trace_processor_sqlite_sqlite",
- ":perfetto_src_trace_processor_sqlite_sqlite_minimal",
":perfetto_src_trace_processor_storage_minimal",
":perfetto_src_trace_processor_storage_storage",
":perfetto_src_trace_processor_tables_tables",
@@ -12772,6 +13066,8 @@ cc_binary_host {
"perfetto_src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
"perfetto_src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ "perfetto_src_trace_processor_prelude_table_functions_tables",
+ "perfetto_src_trace_processor_prelude_tables_views_tables_views",
"perfetto_src_trace_processor_stdlib_gen_amalgamated_stdlib",
"perfetto_src_trace_processor_tables_tables_python",
"perfetto_src_traceconv_gen_cc_trace_descriptor",
diff --git a/BUILD b/BUILD
index 01153ff64..195292f90 100644
--- a/BUILD
+++ b/BUILD
@@ -64,6 +64,152 @@ perfetto_cc_library(
linkstatic = True,
)
+# GN target: //src/cloud_trace_processor:cloud_trace_processor
+perfetto_cc_library(
+ name = "cloud_trace_processor",
+ srcs = [
+ ":src_base_threading_threading",
+ ":src_cloud_trace_processor_sources",
+ ":src_kernel_utils_syscall_table",
+ ":src_protozero_proto_ring_buffer",
+ ":src_trace_processor_db_db",
+ ":src_trace_processor_export_json",
+ ":src_trace_processor_importers_android_bugreport_android_bugreport",
+ ":src_trace_processor_importers_common_common",
+ ":src_trace_processor_importers_common_parser_types",
+ ":src_trace_processor_importers_common_trace_parser_hdr",
+ ":src_trace_processor_importers_ftrace_ftrace_descriptors",
+ ":src_trace_processor_importers_ftrace_full",
+ ":src_trace_processor_importers_ftrace_minimal",
+ ":src_trace_processor_importers_fuchsia_fuchsia_record",
+ ":src_trace_processor_importers_fuchsia_full",
+ ":src_trace_processor_importers_fuchsia_minimal",
+ ":src_trace_processor_importers_gzip_full",
+ ":src_trace_processor_importers_i2c_full",
+ ":src_trace_processor_importers_json_full",
+ ":src_trace_processor_importers_json_minimal",
+ ":src_trace_processor_importers_memory_tracker_graph_processor",
+ ":src_trace_processor_importers_ninja_ninja",
+ ":src_trace_processor_importers_proto_full",
+ ":src_trace_processor_importers_proto_minimal",
+ ":src_trace_processor_importers_proto_packet_sequence_state_generation_hdr",
+ ":src_trace_processor_importers_proto_proto_importer_module",
+ ":src_trace_processor_importers_syscalls_full",
+ ":src_trace_processor_importers_systrace_full",
+ ":src_trace_processor_importers_systrace_systrace_line",
+ ":src_trace_processor_importers_systrace_systrace_parser",
+ ":src_trace_processor_lib",
+ ":src_trace_processor_metatrace",
+ ":src_trace_processor_metrics_metrics",
+ ":src_trace_processor_prelude_functions_functions",
+ ":src_trace_processor_prelude_functions_interface",
+ ":src_trace_processor_prelude_operators_operators",
+ ":src_trace_processor_prelude_table_functions_interface",
+ ":src_trace_processor_prelude_table_functions_table_functions",
+ ":src_trace_processor_prelude_table_functions_tables",
+ ":src_trace_processor_rpc_rpc",
+ ":src_trace_processor_sorter_sorter",
+ ":src_trace_processor_sqlite_query_constraints",
+ ":src_trace_processor_sqlite_sqlite",
+ ":src_trace_processor_storage_minimal",
+ ":src_trace_processor_storage_storage",
+ ":src_trace_processor_tables_tables",
+ ":src_trace_processor_tables_tables_python",
+ ":src_trace_processor_types_types",
+ ":src_trace_processor_util_bump_allocator",
+ ":src_trace_processor_util_descriptors",
+ ":src_trace_processor_util_glob",
+ ":src_trace_processor_util_gzip",
+ ":src_trace_processor_util_interned_message_view",
+ ":src_trace_processor_util_profile_builder",
+ ":src_trace_processor_util_proto_profiler",
+ ":src_trace_processor_util_proto_to_args_parser",
+ ":src_trace_processor_util_protozero_to_text",
+ ":src_trace_processor_util_sql_argument",
+ ":src_trace_processor_util_stack_traces_util",
+ ":src_trace_processor_util_stdlib",
+ ":src_trace_processor_util_util",
+ ":src_trace_processor_util_zip_reader",
+ ":src_trace_processor_views_views",
+ ],
+ hdrs = [
+ ":include_perfetto_base_base",
+ ":include_perfetto_ext_base_base",
+ ":include_perfetto_ext_base_threading_threading",
+ ":include_perfetto_ext_cloud_trace_processor_cloud_trace_processor",
+ ":include_perfetto_ext_trace_processor_demangle",
+ ":include_perfetto_ext_trace_processor_export_json",
+ ":include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
+ ":include_perfetto_ext_traced_sys_stats_counters",
+ ":include_perfetto_protozero_protozero",
+ ":include_perfetto_public_abi_base",
+ ":include_perfetto_public_base",
+ ":include_perfetto_public_protozero",
+ ":include_perfetto_trace_processor_basic_types",
+ ":include_perfetto_trace_processor_storage",
+ ":include_perfetto_trace_processor_trace_processor",
+ ],
+ deps = [
+ ":protos_perfetto_cloud_trace_processor_lite",
+ ":protos_perfetto_common_lite",
+ ":protos_perfetto_common_zero",
+ ":protos_perfetto_config_android_zero",
+ ":protos_perfetto_config_ftrace_zero",
+ ":protos_perfetto_config_gpu_zero",
+ ":protos_perfetto_config_inode_file_zero",
+ ":protos_perfetto_config_interceptors_zero",
+ ":protos_perfetto_config_power_zero",
+ ":protos_perfetto_config_process_stats_zero",
+ ":protos_perfetto_config_profiling_zero",
+ ":protos_perfetto_config_statsd_zero",
+ ":protos_perfetto_config_sys_stats_zero",
+ ":protos_perfetto_config_system_info_zero",
+ ":protos_perfetto_config_track_event_zero",
+ ":protos_perfetto_config_zero",
+ ":protos_perfetto_trace_android_zero",
+ ":protos_perfetto_trace_chrome_zero",
+ ":protos_perfetto_trace_filesystem_zero",
+ ":protos_perfetto_trace_ftrace_zero",
+ ":protos_perfetto_trace_gpu_zero",
+ ":protos_perfetto_trace_interned_data_zero",
+ ":protos_perfetto_trace_minimal_zero",
+ ":protos_perfetto_trace_non_minimal_zero",
+ ":protos_perfetto_trace_perfetto_zero",
+ ":protos_perfetto_trace_power_zero",
+ ":protos_perfetto_trace_processor_lite",
+ ":protos_perfetto_trace_processor_metrics_impl_zero",
+ ":protos_perfetto_trace_processor_zero",
+ ":protos_perfetto_trace_profiling_zero",
+ ":protos_perfetto_trace_ps_zero",
+ ":protos_perfetto_trace_statsd_zero",
+ ":protos_perfetto_trace_sys_stats_zero",
+ ":protos_perfetto_trace_system_info_zero",
+ ":protos_perfetto_trace_track_event_zero",
+ ":protos_perfetto_trace_translation_zero",
+ ":protos_third_party_pprof_zero",
+ ":protozero",
+ ":src_base_base",
+ ":src_base_version",
+ ":src_trace_processor_containers_containers",
+ ":src_trace_processor_importers_proto_gen_cc_chrome_track_event_descriptor",
+ ":src_trace_processor_importers_proto_gen_cc_config_descriptor",
+ ":src_trace_processor_importers_proto_gen_cc_statsd_atoms_descriptor",
+ ":src_trace_processor_importers_proto_gen_cc_trace_descriptor",
+ ":src_trace_processor_importers_proto_gen_cc_track_event_descriptor",
+ ":src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
+ ":src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
+ ":src_trace_processor_metrics_gen_cc_metrics_descriptor",
+ ":src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ ":src_trace_processor_prelude_tables_views_tables_views",
+ ":src_trace_processor_stdlib_gen_amalgamated_stdlib",
+ ] + PERFETTO_CONFIG.deps.jsoncpp +
+ PERFETTO_CONFIG.deps.sqlite +
+ PERFETTO_CONFIG.deps.sqlite_ext_percentile +
+ PERFETTO_CONFIG.deps.zlib +
+ PERFETTO_CONFIG.deps.demangle_wrapper,
+ linkstatic = True,
+)
+
# GN target: //src/ipc/protoc_plugin:ipc_plugin
perfetto_cc_binary(
name = "ipc_plugin",
@@ -279,6 +425,7 @@ perfetto_cc_library(
":src_tracing_common",
":src_tracing_core_core",
":src_tracing_core_service",
+ ":src_tracing_core_zlib_compressor",
":src_tracing_ipc_common",
":src_tracing_ipc_default_socket",
":src_tracing_ipc_producer_producer",
@@ -355,7 +502,7 @@ perfetto_cc_library(
":protozero",
":src_base_base",
":src_base_version",
- ],
+ ] + PERFETTO_CONFIG.deps.zlib,
linkstatic = True,
)
@@ -387,6 +534,22 @@ perfetto_filegroup(
],
)
+# GN target: //include/perfetto/ext/base/threading:threading
+perfetto_filegroup(
+ name = "include_perfetto_ext_base_threading_threading",
+ srcs = [
+ "include/perfetto/ext/base/threading/channel.h",
+ "include/perfetto/ext/base/threading/future.h",
+ "include/perfetto/ext/base/threading/future_combinators.h",
+ "include/perfetto/ext/base/threading/poll.h",
+ "include/perfetto/ext/base/threading/spawn.h",
+ "include/perfetto/ext/base/threading/stream.h",
+ "include/perfetto/ext/base/threading/stream_combinators.h",
+ "include/perfetto/ext/base/threading/thread_pool.h",
+ "include/perfetto/ext/base/threading/util.h",
+ ],
+)
+
# GN target: //include/perfetto/ext/base:base
perfetto_filegroup(
name = "include_perfetto_ext_base_base",
@@ -446,6 +609,16 @@ perfetto_filegroup(
],
)
+# GN target: //include/perfetto/ext/cloud_trace_processor:cloud_trace_processor
+perfetto_filegroup(
+ name = "include_perfetto_ext_cloud_trace_processor_cloud_trace_processor",
+ srcs = [
+ "include/perfetto/ext/cloud_trace_processor/environment.h",
+ "include/perfetto/ext/cloud_trace_processor/orchestrator.h",
+ "include/perfetto/ext/cloud_trace_processor/worker.h",
+ ],
+)
+
# GN target: //include/perfetto/ext/ipc:ipc
perfetto_filegroup(
name = "include_perfetto_ext_ipc_ipc",
@@ -758,6 +931,16 @@ perfetto_cc_library(
linkstatic = True,
)
+# GN target: //src/base/threading:threading
+perfetto_filegroup(
+ name = "src_base_threading_threading",
+ srcs = [
+ "src/base/threading/spawn.cc",
+ "src/base/threading/stream_combinators.cc",
+ "src/base/threading/thread_pool.cc",
+ ],
+)
+
# GN target: //src/base:base
perfetto_cc_library(
name = "src_base_base",
@@ -849,6 +1032,19 @@ perfetto_genrule(
],
)
+# GN target: //src/cloud_trace_processor:sources
+perfetto_filegroup(
+ name = "src_cloud_trace_processor_sources",
+ srcs = [
+ "src/cloud_trace_processor/orchestrator_impl.cc",
+ "src/cloud_trace_processor/orchestrator_impl.h",
+ "src/cloud_trace_processor/trace_processor_wrapper.cc",
+ "src/cloud_trace_processor/trace_processor_wrapper.h",
+ "src/cloud_trace_processor/worker_impl.cc",
+ "src/cloud_trace_processor/worker_impl.h",
+ ],
+)
+
# GN target: //src/ipc:client
perfetto_filegroup(
name = "src_ipc_client",
@@ -1082,10 +1278,22 @@ perfetto_filegroup(
"src/trace_processor/db/base_id.h",
"src/trace_processor/db/column.cc",
"src/trace_processor/db/column.h",
+ "src/trace_processor/db/column_overlay.cc",
+ "src/trace_processor/db/column_overlay.h",
"src/trace_processor/db/column_storage.cc",
"src/trace_processor/db/column_storage.h",
"src/trace_processor/db/column_storage_overlay.h",
"src/trace_processor/db/compare.h",
+ "src/trace_processor/db/null_overlay.cc",
+ "src/trace_processor/db/null_overlay.h",
+ "src/trace_processor/db/numeric_storage.cc",
+ "src/trace_processor/db/numeric_storage.h",
+ "src/trace_processor/db/sorting_overlay.h",
+ "src/trace_processor/db/storage.cc",
+ "src/trace_processor/db/storage.h",
+ "src/trace_processor/db/storage_overlay.cc",
+ "src/trace_processor/db/storage_overlay.h",
+ "src/trace_processor/db/storage_variants.h",
"src/trace_processor/db/table.cc",
"src/trace_processor/db/table.h",
"src/trace_processor/db/typed_column.h",
@@ -1579,6 +1787,7 @@ perfetto_filegroup(
"src/trace_processor/metrics/sql/android/java_heap_histogram.sql",
"src/trace_processor/metrics/sql/android/java_heap_stats.sql",
"src/trace_processor/metrics/sql/android/mem_stats_priority_breakdown.sql",
+ "src/trace_processor/metrics/sql/android/network_activity_template.sql",
"src/trace_processor/metrics/sql/android/p_state.sql",
"src/trace_processor/metrics/sql/android/power_drain_in_watts.sql",
"src/trace_processor/metrics/sql/android/power_profile_data.sql",
@@ -1794,17 +2003,26 @@ perfetto_filegroup(
"src/trace_processor/prelude/functions/layout_functions.h",
"src/trace_processor/prelude/functions/pprof_functions.cc",
"src/trace_processor/prelude/functions/pprof_functions.h",
- "src/trace_processor/prelude/functions/register_function.cc",
- "src/trace_processor/prelude/functions/register_function.h",
"src/trace_processor/prelude/functions/sqlite3_str_split.cc",
"src/trace_processor/prelude/functions/sqlite3_str_split.h",
"src/trace_processor/prelude/functions/stack_functions.cc",
"src/trace_processor/prelude/functions/stack_functions.h",
+ "src/trace_processor/prelude/functions/to_ftrace.cc",
+ "src/trace_processor/prelude/functions/to_ftrace.h",
"src/trace_processor/prelude/functions/utils.h",
"src/trace_processor/prelude/functions/window_functions.h",
],
)
+# GN target: //src/trace_processor/prelude/functions:interface
+perfetto_filegroup(
+ name = "src_trace_processor_prelude_functions_interface",
+ srcs = [
+ "src/trace_processor/prelude/functions/sql_function.cc",
+ "src/trace_processor/prelude/functions/sql_function.h",
+ ],
+)
+
# GN target: //src/trace_processor/prelude/operators:operators
perfetto_filegroup(
name = "src_trace_processor_prelude_operators_operators",
@@ -1816,6 +2034,15 @@ perfetto_filegroup(
],
)
+# GN target: //src/trace_processor/prelude/table_functions:interface
+perfetto_filegroup(
+ name = "src_trace_processor_prelude_table_functions_interface",
+ srcs = [
+ "src/trace_processor/prelude/table_functions/table_function.cc",
+ "src/trace_processor/prelude/table_functions/table_function.h",
+ ],
+)
+
# GN target: //src/trace_processor/prelude/table_functions:table_functions
perfetto_filegroup(
name = "src_trace_processor_prelude_table_functions_table_functions",
@@ -1840,13 +2067,46 @@ perfetto_filegroup(
"src/trace_processor/prelude/table_functions/experimental_slice_layout.h",
"src/trace_processor/prelude/table_functions/flamegraph_construction_algorithms.cc",
"src/trace_processor/prelude/table_functions/flamegraph_construction_algorithms.h",
- "src/trace_processor/prelude/table_functions/table_function.cc",
- "src/trace_processor/prelude/table_functions/table_function.h",
"src/trace_processor/prelude/table_functions/view.cc",
"src/trace_processor/prelude/table_functions/view.h",
],
)
+# GN target: //src/trace_processor/prelude/table_functions:tables
+perfetto_cc_tp_tables(
+ name = "src_trace_processor_prelude_table_functions_tables",
+ srcs = [
+ "src/trace_processor/prelude/table_functions/tables.py",
+ ],
+ deps = [
+ ":src_trace_processor_tables_tables_python",
+ ],
+ outs = [
+ "src/trace_processor/prelude/table_functions/tables_py.h",
+ ],
+)
+
+# GN target: //src/trace_processor/prelude/tables_views:sources
+perfetto_filegroup(
+ name = "src_trace_processor_prelude_tables_views_sources",
+ srcs = [
+ "src/trace_processor/prelude/tables_views/tables.sql",
+ "src/trace_processor/prelude/tables_views/views.sql",
+ ],
+)
+
+# GN target: //src/trace_processor/prelude/tables_views:tables_views
+perfetto_cc_amalgamated_sql(
+ name = "src_trace_processor_prelude_tables_views_tables_views",
+ deps = [
+ ":src_trace_processor_prelude_tables_views_sources",
+ ],
+ outs = [
+ "src/trace_processor/prelude/tables_views/tables_views.h",
+ ],
+ namespace = "prelude::tables_views",
+)
+
# GN target: //src/trace_processor/rpc:httpd
perfetto_filegroup(
name = "src_trace_processor_rpc_httpd",
@@ -1878,6 +2138,15 @@ perfetto_filegroup(
],
)
+# GN target: //src/trace_processor/sqlite:query_constraints
+perfetto_filegroup(
+ name = "src_trace_processor_sqlite_query_constraints",
+ srcs = [
+ "src/trace_processor/sqlite/query_constraints.cc",
+ "src/trace_processor/sqlite/query_constraints.h",
+ ],
+)
+
# GN target: //src/trace_processor/sqlite:sqlite
perfetto_filegroup(
name = "src_trace_processor_sqlite_sqlite",
@@ -1885,10 +2154,13 @@ perfetto_filegroup(
"src/trace_processor/sqlite/db_sqlite_table.cc",
"src/trace_processor/sqlite/db_sqlite_table.h",
"src/trace_processor/sqlite/query_cache.h",
+ "src/trace_processor/sqlite/scoped_db.h",
"src/trace_processor/sqlite/sql_stats_table.cc",
"src/trace_processor/sqlite/sql_stats_table.h",
- "src/trace_processor/sqlite/sqlite_raw_table.cc",
- "src/trace_processor/sqlite/sqlite_raw_table.h",
+ "src/trace_processor/sqlite/sqlite_engine.cc",
+ "src/trace_processor/sqlite/sqlite_engine.h",
+ "src/trace_processor/sqlite/sqlite_table.cc",
+ "src/trace_processor/sqlite/sqlite_table.h",
"src/trace_processor/sqlite/sqlite_utils.cc",
"src/trace_processor/sqlite/sqlite_utils.h",
"src/trace_processor/sqlite/stats_table.cc",
@@ -1896,19 +2168,6 @@ perfetto_filegroup(
],
)
-# GN target: //src/trace_processor/sqlite:sqlite_minimal
-perfetto_filegroup(
- name = "src_trace_processor_sqlite_sqlite_minimal",
- srcs = [
- "src/trace_processor/sqlite/query_constraints.cc",
- "src/trace_processor/sqlite/query_constraints.h",
- "src/trace_processor/sqlite/scoped_db.h",
- "src/trace_processor/sqlite/sqlite_table.cc",
- "src/trace_processor/sqlite/sqlite_table.h",
- "src/trace_processor/sqlite/sqlite_utils.h",
- ],
-)
-
# GN target: //src/trace_processor/stdlib/android/startup:startup
perfetto_filegroup(
name = "src_trace_processor_stdlib_android_startup_startup",
@@ -1925,10 +2184,13 @@ perfetto_filegroup(
name = "src_trace_processor_stdlib_android_android",
srcs = [
"src/trace_processor/stdlib/android/battery.sql",
+ "src/trace_processor/stdlib/android/battery_stats.sql",
"src/trace_processor/stdlib/android/binder.sql",
"src/trace_processor/stdlib/android/monitor_contention.sql",
+ "src/trace_processor/stdlib/android/network_packets.sql",
"src/trace_processor/stdlib/android/process_metadata.sql",
"src/trace_processor/stdlib/android/slices.sql",
+ "src/trace_processor/stdlib/android/statsd.sql",
],
)
@@ -1936,6 +2198,7 @@ perfetto_filegroup(
perfetto_filegroup(
name = "src_trace_processor_stdlib_chrome_chrome_sql",
srcs = [
+ "src/trace_processor/stdlib/chrome/chrome_scrolls.sql",
"src/trace_processor/stdlib/chrome/cpu_powerups.sql",
],
)
@@ -1945,6 +2208,7 @@ perfetto_filegroup(
name = "src_trace_processor_stdlib_common_common",
srcs = [
"src/trace_processor/stdlib/common/counters.sql",
+ "src/trace_processor/stdlib/common/cpus.sql",
"src/trace_processor/stdlib/common/metadata.sql",
"src/trace_processor/stdlib/common/percentiles.sql",
"src/trace_processor/stdlib/common/slices.sql",
@@ -2001,12 +2265,7 @@ perfetto_filegroup(
perfetto_filegroup(
name = "src_trace_processor_tables_tables",
srcs = [
- "src/trace_processor/tables/counter_tables.h",
- "src/trace_processor/tables/flow_tables.h",
- "src/trace_processor/tables/macros.h",
"src/trace_processor/tables/macros_internal.h",
- "src/trace_processor/tables/profiler_tables.h",
- "src/trace_processor/tables/slice_tables.h",
"src/trace_processor/tables/table_destructors.cc",
],
)
@@ -2051,7 +2310,6 @@ perfetto_filegroup(
"src/trace_processor/types/task_state.h",
"src/trace_processor/types/tcp_state.h",
"src/trace_processor/types/trace_processor_context.h",
- "src/trace_processor/types/variadic.cc",
"src/trace_processor/types/variadic.h",
"src/trace_processor/types/version_number.h",
],
@@ -2591,6 +2849,15 @@ perfetto_filegroup(
],
)
+# GN target: //src/tracing/core:zlib_compressor
+perfetto_filegroup(
+ name = "src_tracing_core_zlib_compressor",
+ srcs = [
+ "src/tracing/core/zlib_compressor.cc",
+ "src/tracing/core/zlib_compressor.h",
+ ],
+)
+
# GN target: //src/tracing/ipc/consumer:consumer
perfetto_filegroup(
name = "src_tracing_ipc_consumer_consumer",
@@ -3003,6 +3270,31 @@ perfetto_py_proto_library(
],
)
+# GN target: //protos/perfetto/cloud_trace_processor:lite
+perfetto_cc_proto_library(
+ name = "protos_perfetto_cloud_trace_processor_lite",
+ deps = [
+ ":protos_perfetto_cloud_trace_processor_protos",
+ ],
+)
+
+# GN target: //protos/perfetto/cloud_trace_processor:source_set
+perfetto_proto_library(
+ name = "protos_perfetto_cloud_trace_processor_protos",
+ srcs = [
+ "protos/perfetto/cloud_trace_processor/common.proto",
+ "protos/perfetto/cloud_trace_processor/orchestrator.proto",
+ "protos/perfetto/cloud_trace_processor/worker.proto",
+ ],
+ visibility = [
+ PERFETTO_CONFIG.proto_library_visibility,
+ ],
+ deps = [
+ ":protos_perfetto_common_protos",
+ ":protos_perfetto_trace_processor_protos",
+ ],
+)
+
# GN target: //protos/perfetto/common:cpp
perfetto_cc_protocpp_library(
name = "protos_perfetto_common_cpp",
@@ -3011,6 +3303,14 @@ perfetto_cc_protocpp_library(
],
)
+# GN target: //protos/perfetto/common:lite
+perfetto_cc_proto_library(
+ name = "protos_perfetto_common_lite",
+ deps = [
+ ":protos_perfetto_common_protos",
+ ],
+)
+
# GN target: //protos/perfetto/common:source_set
perfetto_proto_library(
name = "protos_perfetto_common_protos",
@@ -4152,6 +4452,14 @@ perfetto_cc_protozero_library(
],
)
+# GN target: //protos/perfetto/trace_processor:lite
+perfetto_cc_proto_library(
+ name = "protos_perfetto_trace_processor_lite",
+ deps = [
+ ":protos_perfetto_trace_processor_protos",
+ ],
+)
+
# GN target: //protos/perfetto/trace_processor:metrics_impl_source_set
perfetto_proto_library(
name = "protos_perfetto_trace_processor_metrics_impl_protos",
@@ -4175,7 +4483,6 @@ perfetto_cc_protozero_library(
perfetto_proto_library(
name = "protos_perfetto_trace_processor_protos",
srcs = [
- "protos/perfetto/trace_processor/cloud_trace_processor.proto",
"protos/perfetto/trace_processor/metatrace_categories.proto",
"protos/perfetto/trace_processor/stack.proto",
"protos/perfetto/trace_processor/trace_processor.proto",
@@ -4713,11 +5020,14 @@ perfetto_cc_library(
":src_trace_processor_metatrace",
":src_trace_processor_metrics_metrics",
":src_trace_processor_prelude_functions_functions",
+ ":src_trace_processor_prelude_functions_interface",
":src_trace_processor_prelude_operators_operators",
+ ":src_trace_processor_prelude_table_functions_interface",
":src_trace_processor_prelude_table_functions_table_functions",
+ ":src_trace_processor_prelude_table_functions_tables",
":src_trace_processor_sorter_sorter",
+ ":src_trace_processor_sqlite_query_constraints",
":src_trace_processor_sqlite_sqlite",
- ":src_trace_processor_sqlite_sqlite_minimal",
":src_trace_processor_storage_minimal",
":src_trace_processor_storage_storage",
":src_trace_processor_tables_tables",
@@ -4804,6 +5114,7 @@ perfetto_cc_library(
":src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
":src_trace_processor_metrics_gen_cc_metrics_descriptor",
":src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ ":src_trace_processor_prelude_tables_views_tables_views",
":src_trace_processor_stdlib_gen_amalgamated_stdlib",
] + PERFETTO_CONFIG.deps.jsoncpp +
PERFETTO_CONFIG.deps.sqlite +
@@ -4865,13 +5176,16 @@ perfetto_cc_binary(
":src_trace_processor_metatrace",
":src_trace_processor_metrics_metrics",
":src_trace_processor_prelude_functions_functions",
+ ":src_trace_processor_prelude_functions_interface",
":src_trace_processor_prelude_operators_operators",
+ ":src_trace_processor_prelude_table_functions_interface",
":src_trace_processor_prelude_table_functions_table_functions",
+ ":src_trace_processor_prelude_table_functions_tables",
":src_trace_processor_rpc_httpd",
":src_trace_processor_rpc_rpc",
":src_trace_processor_sorter_sorter",
+ ":src_trace_processor_sqlite_query_constraints",
":src_trace_processor_sqlite_sqlite",
- ":src_trace_processor_sqlite_sqlite_minimal",
":src_trace_processor_storage_minimal",
":src_trace_processor_storage_storage",
":src_trace_processor_tables_tables",
@@ -4948,6 +5262,7 @@ perfetto_cc_binary(
":src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
":src_trace_processor_metrics_gen_cc_metrics_descriptor",
":src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ ":src_trace_processor_prelude_tables_views_tables_views",
":src_trace_processor_stdlib_gen_amalgamated_stdlib",
] + PERFETTO_CONFIG.deps.jsoncpp +
PERFETTO_CONFIG.deps.linenoise +
@@ -5076,11 +5391,14 @@ perfetto_cc_binary(
":src_trace_processor_metatrace",
":src_trace_processor_metrics_metrics",
":src_trace_processor_prelude_functions_functions",
+ ":src_trace_processor_prelude_functions_interface",
":src_trace_processor_prelude_operators_operators",
+ ":src_trace_processor_prelude_table_functions_interface",
":src_trace_processor_prelude_table_functions_table_functions",
+ ":src_trace_processor_prelude_table_functions_tables",
":src_trace_processor_sorter_sorter",
+ ":src_trace_processor_sqlite_query_constraints",
":src_trace_processor_sqlite_sqlite",
- ":src_trace_processor_sqlite_sqlite_minimal",
":src_trace_processor_storage_minimal",
":src_trace_processor_storage_storage",
":src_trace_processor_tables_tables",
@@ -5157,6 +5475,7 @@ perfetto_cc_binary(
":src_trace_processor_metrics_gen_cc_all_webview_metrics_descriptor",
":src_trace_processor_metrics_gen_cc_metrics_descriptor",
":src_trace_processor_metrics_sql_gen_amalgamated_sql_metrics",
+ ":src_trace_processor_prelude_tables_views_tables_views",
":src_trace_processor_stdlib_gen_amalgamated_stdlib",
":src_traceconv_gen_cc_trace_descriptor",
] + PERFETTO_CONFIG.deps.jsoncpp +
diff --git a/BUILD.gn b/BUILD.gn
index 77bafbc5c..c48159e6a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -42,6 +42,7 @@ if (enable_perfetto_platform_services) {
}
if (enable_perfetto_trace_processor && enable_perfetto_trace_processor_sqlite) {
+ all_targets += [ "src/cloud_trace_processor" ]
all_targets += [ "src/trace_processor:trace_processor_shell" ]
}
diff --git a/CHANGELOG b/CHANGELOG
index c81ed7891..107a26b6c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,11 +1,27 @@
Unreleased:
Tracing service and probes:
+ * Compression has been moved from perfetto_cmd to traced. Now compression is
+ supported even with write_into_file. The `compress_from_cli` config option
+ can be used to restore the old behavior.
+ Trace Processor:
+ *
+ UI:
+ *
+ SDK:
+ *
+
+v34.0 - 2023-05-02:
+ Tracing service and probes:
* --continuous-dump in tools/java_heap_dump now keeps recording until it
receives CTRL+C.
+ * Add CLONE_SNAPSHOT triggers for non-destructive snapshots of the trace
+ buffer without tracing interruption.
Trace Processor:
*
UI:
- *
+ * Add support for parsing large integers from Trace Processor into
+ bigint. This is the default behaviour for unknown fields and can
+ be enabled specifically via the LONG and LONG_NULL column types.
SDK:
* Changed the type of the static constexpr metadata on protozero
generated bindings from a function returning the metadata to
@@ -19,6 +35,9 @@ Unreleased:
* The new DataSourceBase::OnFlush() method allows users to properly handle
Flush requests.
+v33.1 - 2023-03-03:
+ Identical to v33.0. Version was bumped to work around prebuilt infra failures.
+
v33.0 - 2023-03-02:
All:
* Switched to a C++17-only project by removing C++11 opt-out. This completes
diff --git a/bazel/deps.bzl b/bazel/deps.bzl
index 27c5c800f..a105a6330 100644
--- a/bazel/deps.bzl
+++ b/bazel/deps.bzl
@@ -67,10 +67,10 @@ def perfetto_deps():
)
_add_repo_if_not_existing(
- new_git_repository,
+ http_archive,
name = "perfetto_dep_zlib",
- remote = "https://android.googlesource.com/platform/external/zlib.git",
- commit = "6d3f6aa0f87c9791ca7724c279ef61384f331dfd",
+ url = "https://storage.googleapis.com/perfetto/zlib-6d3f6aa0f87c9791ca7724c279ef61384f331dfd.tar.gz",
+ sha256 = "e9a1d6e8c936de68628ffb83a13d28a40cd6b2def2ad9378e8b951d4b8f4df18",
build_file = "//bazel:zlib.BUILD",
)
diff --git a/bazel/rules.bzl b/bazel/rules.bzl
index 4021c58a6..79174bd33 100644
--- a/bazel/rules.bzl
+++ b/bazel/rules.bzl
@@ -308,7 +308,7 @@ def perfetto_cc_amalgamated_sql(name, deps, outs, namespace, **kwargs):
**kwargs,
)
-def perfetto_cc_tp_tables(name, srcs, outs, **kwargs):
+def perfetto_cc_tp_tables(name, srcs, outs, deps = [], **kwargs):
if PERFETTO_CONFIG.root[:2] != "//":
fail("Expected PERFETTO_CONFIG.root to start with //")
@@ -317,12 +317,21 @@ def perfetto_cc_tp_tables(name, srcs, outs, **kwargs):
else:
python_path = PERFETTO_CONFIG.root + "/python"
+ perfetto_py_library(
+ name = name + "_lib",
+ deps = [
+ python_path + ":trace_processor_table_generator",
+ ],
+ srcs = srcs,
+ )
+
perfetto_py_binary(
name = name + "_tool",
deps = [
+ ":" + name + "_lib",
python_path + ":trace_processor_table_generator",
- ],
- srcs = srcs + [
+ ] + [d + "_lib" for d in deps],
+ srcs = [
"tools/gen_tp_table_headers.py",
],
main = "tools/gen_tp_table_headers.py",
@@ -332,9 +341,9 @@ def perfetto_cc_tp_tables(name, srcs, outs, **kwargs):
cmd = ["$(location " + name + "_tool)"]
cmd += ["--gen-dir", "$(RULEDIR)"]
cmd += ["--inputs", "$(SRCS)"]
- cmd += ["--outputs", "$(OUTS)"]
if PERFETTO_CONFIG.root != "//":
- cmd += ["--header-prefix", PERFETTO_CONFIG.root[2:]]
+ cmd += ["--import-prefix", PERFETTO_CONFIG.root[2:]]
+ cmd += ["--relative-input-dir", PERFETTO_CONFIG.root[2:]]
perfetto_genrule(
name = name + "_gen",
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index 2ac2948cd..8eb19f7e1 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -129,6 +129,13 @@ config("protobuf_config") {
defines = [ "HAVE_PTHREAD=1" ]
cflags = []
+
+ # Fixed upstream in:
+ # https://github.com/protocolbuffers/protobuf/pull/10112
+ # But we don't have that yet.
+ if (is_mac) {
+ cflags += [ "-Wno-deprecated-declarations" ]
+ }
if (!is_clang && !is_win) { # implies gcc
cflags += [ "-Wno-stringop-overread" ]
}
diff --git a/docs/analysis/trace-processor.md b/docs/analysis/trace-processor.md
index eb022e04a..f1ef185f2 100644
--- a/docs/analysis/trace-processor.md
+++ b/docs/analysis/trace-processor.md
@@ -256,10 +256,10 @@ It takes an `arg_set_id` and `key` as input and returns the value looked
up in the `args` table.
For example, to retrieve the `prev_comm` field for `sched_switch` events in
-the `raw` table.
+the `ftrace_event` table.
```sql
SELECT EXTRACT_ARG(arg_set_id, 'prev_comm')
-FROM raw
+FROM ftrace_event
WHERE name = 'sched_switch'
```
@@ -271,7 +271,7 @@ SELECT
FROM args
WHERE key = 'prev_comm' AND args.arg_set_id = raw.arg_set_id
)
-FROM raw
+FROM ftrace_event
WHERE name = 'sched_switch'
```
diff --git a/docs/contributing/perfetto-in-the-press.md b/docs/contributing/perfetto-in-the-press.md
index 108849ab0..4546bd630 100644
--- a/docs/contributing/perfetto-in-the-press.md
+++ b/docs/contributing/perfetto-in-the-press.md
@@ -2,6 +2,8 @@
This a partial collection of the talks, blogposts, presentations, and articles that mention Perfetto.
+- [Google IO 2023 - What's new in Dart and Flutter](https://youtu.be/yRlwOdCK7Ho?t=798)
+- [Google IO 2023 - Debugging Jetpack Compose](https://youtu.be/Kp-aiSU8qCU?t=1092)
- [Performance: Perfetto Traceviewer - MAD Skills](https://www.youtube.com/watch?v=phhLFicMacY)
"On this episode of the MAD Skills series on Performance, Android Performance Engineer Carmen Jackson discusses the Perfetto traceviewer, an alternative to Android Studio for viewing system traces."
- [Performance and optimisation on the Meta Quest Platform](https://m.facebook.com/RealityLabs/videos/performance-and-optimization-on-meta-quest-platform/488126049869673/)
diff --git a/docs/data-sources/cpu-scheduling.md b/docs/data-sources/cpu-scheduling.md
index 062d9b983..b8447ffbc 100644
--- a/docs/data-sources/cpu-scheduling.md
+++ b/docs/data-sources/cpu-scheduling.md
@@ -16,12 +16,7 @@ This allows to get fine grained scheduling events such as:
## UI
-When zoomed out, the UI shows a quantized view of CPU usage, which collapses the
-scheduling information:
-
-![](/docs/images/cpu-bar-graphs.png "Quantized view of CPU run queues")
-
-However, by zooming in, the individual scheduling events become visible:
+The UI represents individual scheduling events as slices:
![](/docs/images/cpu-zoomed.png "Detailed view of CPU run queues")
diff --git a/docs/images/enable-profile-flame-graph.png b/docs/images/enable-profile-flame-graph.png
deleted file mode 100644
index 642ce73e3..000000000
--- a/docs/images/enable-profile-flame-graph.png
+++ /dev/null
Binary files differ
diff --git a/docs/instrumentation/tracing-sdk.md b/docs/instrumentation/tracing-sdk.md
index d4c72b087..809833bfb 100644
--- a/docs/instrumentation/tracing-sdk.md
+++ b/docs/instrumentation/tracing-sdk.md
@@ -30,7 +30,7 @@ repository](/examples/sdk/README.md).
To start using the Client API, first check out the latest SDK release:
```bash
-git clone https://android.googlesource.com/platform/external/perfetto -b v32.1
+git clone https://android.googlesource.com/platform/external/perfetto -b v34.0
```
The SDK consists of two files, `sdk/perfetto.h` and `sdk/perfetto.cc`. These are
diff --git a/docs/quickstart/callstack-sampling.md b/docs/quickstart/callstack-sampling.md
index e5da5b21e..cb47edc35 100644
--- a/docs/quickstart/callstack-sampling.md
+++ b/docs/quickstart/callstack-sampling.md
@@ -119,11 +119,6 @@ PERFETTO_SYMBOLIZER_MODE=index PERFETTO_BINARY_PATH=path/to/directory/with/symbo
## View profile
-Visualizing callstacks in the Perfetto UI is currently disabled behind a
-flag. Please enable it before proceeding further:
-
-![Enable flame graph flag](/docs/images/enable-profile-flame-graph.png)
-
Upload the `raw-trace` or `symbolized-trace` file from the output directory to
the [Perfetto UI](https://ui.perfetto.dev) and click and drag over one or more
of the diamond markers in the UI track named "Perf Samples" for the processes
diff --git a/docs/quickstart/chrome-tracing.md b/docs/quickstart/chrome-tracing.md
index 4e1717226..6786b4dd7 100644
--- a/docs/quickstart/chrome-tracing.md
+++ b/docs/quickstart/chrome-tracing.md
@@ -4,6 +4,8 @@ Perfetto can capture traces right from the Chrome browser on desktop. It capture
> To record traces from Chrome on Android, follow the [instructions for recording Android system traces](/docs/quickstart/android-tracing.md) and enable the Chrome probe.
+>> If you are using [user build of Android](https://source.android.com/docs/setup/build/building#lunch), you'll have to enable integration with system Perfetto by switching chrome://flags#enable-perfetto-system-tracing to "Enabled" and restarting Chrome.
+
## Recording a trace
1. Navigate to [ui.perfetto.dev](https://ui.perfetto.dev/) and select **"Record new trace"** from the left menu.
diff --git a/examples/sdk/README.md b/examples/sdk/README.md
index 238d50d6d..476ebbe81 100644
--- a/examples/sdk/README.md
+++ b/examples/sdk/README.md
@@ -15,7 +15,7 @@ Dependencies:
First, check out the latest Perfetto release:
```bash
-git clone https://android.googlesource.com/platform/external/perfetto -b v32.1
+git clone https://android.googlesource.com/platform/external/perfetto -b v34.0
```
Then, build using CMake:
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index 192ede856..749c2eef6 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -275,7 +275,7 @@ config("protobuf_gen_config") {
"GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
]
cflags = []
- if (!is_clang || !is_win) {
+ if (!is_clang && !is_win) {
cflags += [ "-Wno-deprecated-declarations" ]
}
if (is_clang && is_win) {
@@ -289,6 +289,10 @@ config("protobuf_gen_config") {
"-Wno-unused-parameter",
"-Wno-shadow-field-in-constructor",
"-Wno-zero-as-null-pointer-constant",
+
+ # Fixed in upstream protobuf v3.22.0
+ # d37cbfd4485f("Update inlined_string_field.h"), but we don't have that.
+ "-Wno-undef",
]
}
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index b778d887d..579fc0f6b 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -296,8 +296,9 @@ declare_args() {
enable_perfetto_trace_processor &&
(perfetto_build_standalone || perfetto_build_with_android)
- # Enables Zlib support. This is used both by the "perfetto" cmdline client
- # (for compressing traces) and by trace processor (for compressed traces).
+ # Enables Zlib support. This is used to compress traces (by the tracing
+ # service and by the "perfetto" cmdline client) and to decompress traces (by
+ # trace_processor).
enable_perfetto_zlib =
(enable_perfetto_trace_processor && !build_with_chromium) ||
enable_perfetto_platform_services
diff --git a/gn/perfetto_tp_tables.gni b/gn/perfetto_tp_tables.gni
index da8cfaeef..19a98c0fa 100644
--- a/gn/perfetto_tp_tables.gni
+++ b/gn/perfetto_tp_tables.gni
@@ -17,6 +17,10 @@ import("perfetto.gni")
template("perfetto_tp_tables") {
config_name = target_name + "_config"
action_name = target_name
+ relative_args = [
+ "--relative-input-dir",
+ rebase_path(perfetto_root_path, root_build_dir),
+ ]
config(config_name) {
include_dirs = [ root_gen_dir ]
@@ -32,15 +36,17 @@ template("perfetto_tp_tables") {
}
deps = [ "$perfetto_root_path/python:trace_processor_table_generator" ]
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
+ }
public_configs = [ ":$config_name" ]
gen_args = [
"--gen-dir",
- rebase_path("$root_gen_dir", root_build_dir),
+ rebase_path("$root_gen_dir/$perfetto_root_path", root_build_dir),
]
input_args = [ "--inputs" ] + rebase_path(invoker.sources, root_build_dir)
- output_args = [ "--outputs" ] + rebase_path(outputs, root_build_dir)
- args = gen_args + input_args + output_args
+ args = gen_args + input_args + relative_args
metadata = {
perfetto_action_type_for_generator = [ "tp_tables" ]
@@ -56,7 +62,7 @@ template("perfetto_tp_tables") {
deps = [ "$perfetto_root_path/python:trace_processor_table_generator" ]
outputs = [ "$target_gen_dir/$docs_name.json" ]
args = [ "--out" ] + rebase_path(outputs, root_build_dir) +
- rebase_path(invoker.sources, root_build_dir)
+ rebase_path(invoker.sources, root_build_dir) + relative_args
}
}
}
diff --git a/gn/perfetto_unittests.gni b/gn/perfetto_unittests.gni
index 76594fedd..b7b1e0177 100644
--- a/gn/perfetto_unittests.gni
+++ b/gn/perfetto_unittests.gni
@@ -72,12 +72,10 @@ if (enable_perfetto_traced_perf) {
if (enable_perfetto_trace_processor) {
perfetto_unittests_targets += [ "src/trace_processor:unittests" ]
-
- # TODO(mohitms): reenable this once we no longer link lite and full protobuf
- # simultaneously.
- # perfetto_unittests_targets += [ "src/traceconv:unittests" ]
+ perfetto_unittests_targets += [ "src/traceconv:unittests" ]
if (enable_perfetto_trace_processor_sqlite) {
perfetto_unittests_targets += [ "src/trace_processor/metrics:unittests" ]
+ perfetto_unittests_targets += [ "src/cloud_trace_processor:unittests" ]
}
}
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index d000f53ce..0af65510f 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -100,6 +100,18 @@ config("extra_warnings") {
# TODO(lalitm): remove this when we upgrade to a GCC version which is good
# enough to handle this.
cflags_cc += [ "-Wno-maybe-uninitialized" ]
+
+ # GCC's handling of detecting infinite recursion is flaky at best and
+ # causes some false positives.
+ # TODO(lalitm): remove this when we upgrade to a GCC version which is good
+ # enough to handle this.
+ cflags_cc += [ "-Wno-infinite-recursion" ]
+
+ # GCC's handling of detecting non null arguments is flaky at best and
+ # causes some false positives.
+ # TODO(lalitm): remove this when we upgrade to a GCC version which is good
+ # enough to handle this.
+ cflags_cc += [ "-Wno-nonnull" ]
}
}
diff --git a/gn/standalone/toolchain/win_find_msvc.py b/gn/standalone/toolchain/win_find_msvc.py
index 1628c0720..6f7eb8660 100644
--- a/gn/standalone/toolchain/win_find_msvc.py
+++ b/gn/standalone/toolchain/win_find_msvc.py
@@ -27,6 +27,7 @@ C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.
"""
import os
+import itertools
import subprocess
import sys
@@ -62,19 +63,19 @@ def main():
filt = lambda x: os.path.exists(os.path.join(x, 'ucrt', 'x64', 'ucrt.lib'))
out[1] = find_max_subdir(lib_base, filt)
- for year in ['2022', '2021', '2020', '2019']:
- for version in [
- 'BuildTools', 'Community', 'Professional', 'Enterprise', 'Preview'
- ]:
- msvc_base = ('C:\\Program Files (x86)\\Microsoft Visual Studio\\'
- f'{year}\\{version}\\VC\\Tools\\MSVC')
- if os.path.exists(msvc_base):
- filt = lambda x: os.path.exists(
- os.path.join(x, 'lib', 'x64', 'libcmt.lib'))
- max_msvc = find_max_subdir(msvc_base, filt)
- if max_msvc is not None:
- out[2] = os.path.join(msvc_base, max_msvc)
- break
+ for try_dir in itertools.product(
+ ['2022', '2021', '2020', '2019'],
+ ['BuildTools', 'Community', 'Professional', 'Enterprise', 'Preview'],
+ ['Program Files', 'Program Files (x86)']):
+ msvc_base = (f'C:\\{try_dir[2]}\\Microsoft Visual Studio\\'
+ f'{try_dir[0]}\\{try_dir[1]}\\VC\\Tools\\MSVC')
+ if os.path.exists(msvc_base):
+ filt = lambda x: os.path.exists(
+ os.path.join(x, 'lib', 'x64', 'libcmt.lib'))
+ max_msvc = find_max_subdir(msvc_base, filt)
+ if max_msvc is not None:
+ out[2] = os.path.join(msvc_base, max_msvc)
+ break
# Don't error in case of failure, GN scripts are supposed to deal with
# failures and allow the user to override the dirs.
diff --git a/include/perfetto/base/compiler.h b/include/perfetto/base/compiler.h
index 451e6d51f..22324ad7b 100644
--- a/include/perfetto/base/compiler.h
+++ b/include/perfetto/base/compiler.h
@@ -23,16 +23,6 @@
#include "perfetto/base/build_config.h"
#include "perfetto/public/compiler.h"
-#if __cplusplus >= 201703
-#define PERFETTO_IS_AT_LEAST_CPP17() 1
-#elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
-// Without additional flags, MSVC is not standard compliant and keeps
-// __cplusplus stuck at an old value, even with C++17
-#define PERFETTO_IS_AT_LEAST_CPP17() 1
-#else
-#define PERFETTO_IS_AT_LEAST_CPP17() 0
-#endif
-
// __has_attribute is supported only by clang and recent versions of GCC.
// Add a layer to wrap the __has_attribute macro.
#if defined(__has_attribute)
diff --git a/include/perfetto/ext/base/status_or.h b/include/perfetto/ext/base/status_or.h
index 46387d7e2..a6eda7e65 100644
--- a/include/perfetto/ext/base/status_or.h
+++ b/include/perfetto/ext/base/status_or.h
@@ -73,6 +73,10 @@ class StatusOr {
std::optional<T> value_;
};
+// Deduction guide to make returning StatusOr less verbose.
+template <typename T>
+StatusOr(T) -> StatusOr<T>;
+
} // namespace base
} // namespace perfetto
diff --git a/include/perfetto/ext/base/threading/util.h b/include/perfetto/ext/base/threading/util.h
index 7b2465e68..a08a4b038 100644
--- a/include/perfetto/ext/base/threading/util.h
+++ b/include/perfetto/ext/base/threading/util.h
@@ -136,9 +136,12 @@ Stream<T> RunOnThreadPool(ThreadPool* pool,
private:
void RunFn() {
- pool_->PostTask([channel = channel_, fn = fn_]() {
+ pool_->PostTask([channel = channel_, fn = fn_]() mutable {
auto opt_value = (*fn)();
if (!opt_value) {
+ // Clear out the function to ensure that any captured state is freed
+ // before we inform the caller.
+ fn.reset();
channel->Close();
return;
}
diff --git a/include/perfetto/ext/cloud_trace_processor/BUILD.gn b/include/perfetto/ext/cloud_trace_processor/BUILD.gn
new file mode 100644
index 000000000..be266cb25
--- /dev/null
+++ b/include/perfetto/ext/cloud_trace_processor/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source_set("cloud_trace_processor") {
+ sources = [
+ "environment.h",
+ "orchestrator.h",
+ "worker.h",
+ ]
+ deps = [
+ "../../../../gn:default_deps",
+ "../base",
+ "../base/threading",
+ ]
+}
diff --git a/include/perfetto/ext/cloud_trace_processor/environment.h b/include/perfetto/ext/cloud_trace_processor/environment.h
new file mode 100644
index 000000000..8b1fc01ea
--- /dev/null
+++ b/include/perfetto/ext/cloud_trace_processor/environment.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_ENVIRONMENT_H_
+#define INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_ENVIRONMENT_H_
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include "perfetto/base/status.h"
+#include "perfetto/base/task_runner.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/threading/stream.h"
+
+namespace perfetto {
+namespace cloud_trace_processor {
+
+// Shim interface allowing embedders to change how operations which interact
+// with the OS operate (e.g. IO, networking etc).
+class CtpEnvironment {
+ public:
+ virtual ~CtpEnvironment();
+
+ // Opens the file at |path| and reads the contents in chunks, returning the
+ // the chunks as a Stream. The size of the chunks is implementation defined
+ // but should be sized to balance memory use and syscall count.
+ virtual base::StatusOrStream<std::vector<uint8_t>> ReadFile(
+ const std::string& path) = 0;
+};
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_ENVIRONMENT_H_
diff --git a/include/perfetto/ext/cloud_trace_processor/orchestrator.h b/include/perfetto/ext/cloud_trace_processor/orchestrator.h
new file mode 100644
index 000000000..798316185
--- /dev/null
+++ b/include/perfetto/ext/cloud_trace_processor/orchestrator.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_ORCHESTRATOR_H_
+#define INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_ORCHESTRATOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/stream.h"
+
+namespace perfetto {
+namespace protos {
+class TracePoolCreateArgs;
+class TracePoolCreateResponse;
+
+class TracePoolSetTracesArgs;
+class TracePoolSetTracesResponse;
+
+class TracePoolQueryArgs;
+class TracePoolQueryResponse;
+
+class TracePoolDestroyArgs;
+class TracePoolDestroyResponse;
+} // namespace protos
+} // namespace perfetto
+
+namespace perfetto {
+namespace cloud_trace_processor {
+
+class Worker;
+
+// Interface for a CloudTraceProcessor "Orchestrator".
+//
+// See CloudTraceProcessorOrchestrator RPC service for high-level documentation.
+class Orchestrator {
+ public:
+ virtual ~Orchestrator();
+
+ // Returns an in-process implementation of the Orchestrator, given a group of
+ // workers which can be delegated to.
+ //
+ // Note that the passed workers instances can be "remote" (i.e. in another
+ // process or even on another machine); the returned manager will gracefully
+ // handle this.
+ static std::unique_ptr<Orchestrator> CreateInProcess(
+ std::vector<std::unique_ptr<Worker>> workers);
+
+ // Creates a TracePool with the specified arguments.
+ virtual base::StatusOrFuture<protos::TracePoolCreateResponse> TracePoolCreate(
+ const protos::TracePoolCreateArgs&) = 0;
+
+ // Associates the provided list of traces to this TracePoolShard.
+ virtual base::StatusOrFuture<protos::TracePoolSetTracesResponse>
+ TracePoolSetTraces(const protos::TracePoolSetTracesArgs&) = 0;
+
+ // Executes a SQL query on the specified TracePool.
+ virtual base::StatusOrStream<protos::TracePoolQueryResponse> TracePoolQuery(
+ const protos::TracePoolQueryArgs&) = 0;
+
+ // Destroys the TracePool with the specified id.
+ virtual base::StatusOrFuture<protos::TracePoolDestroyResponse>
+ TracePoolDestroy(const protos::TracePoolDestroyArgs&) = 0;
+};
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_ORCHESTRATOR_H_
diff --git a/include/perfetto/ext/cloud_trace_processor/worker.h b/include/perfetto/ext/cloud_trace_processor/worker.h
new file mode 100644
index 000000000..60dbe7763
--- /dev/null
+++ b/include/perfetto/ext/cloud_trace_processor/worker.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_WORKER_H_
+#define INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_WORKER_H_
+
+#include <memory>
+#include <vector>
+
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/stream.h"
+
+namespace perfetto {
+
+namespace base {
+class ThreadPool;
+}
+
+namespace protos {
+class TracePoolShardCreateArgs;
+class TracePoolShardCreateResponse;
+
+class TracePoolShardSetTracesArgs;
+class TracePoolShardSetTracesResponse;
+
+class TracePoolShardQueryArgs;
+class TracePoolShardQueryResponse;
+
+class TracePoolShardDestroyArgs;
+class TracePoolShardDestroyResponse;
+} // namespace protos
+
+namespace cloud_trace_processor {
+
+class CtpEnvironment;
+
+// Interface for a CloudTraceProcessor "Worker".
+//
+// See CloudTraceProcessorWorker RPC service for high-level documentation.
+class Worker {
+ public:
+ virtual ~Worker();
+
+ // Returns an in-process implementation of the Worker given an instance of
+ // |CtpEnvironment| and a |ThreadPool|. The |CtpEnvironment| will be used to
+ // perform any interaction with the OS (e.g. opening and reading files) and
+ // the |ThreadPool| will be used to dispatch requests to TraceProcessor.
+ static std::unique_ptr<Worker> CreateInProcesss(CtpEnvironment*,
+ base::ThreadPool*);
+
+ // Creates a TracePoolShard which will be owned by this worker.
+ virtual base::StatusOrFuture<protos::TracePoolShardCreateResponse>
+ TracePoolShardCreate(const protos::TracePoolShardCreateArgs&) = 0;
+
+ // Associates the provided list of traces to this TracePoolShard.
+ virtual base::StatusOrStream<protos::TracePoolShardSetTracesResponse>
+ TracePoolShardSetTraces(const protos::TracePoolShardSetTracesArgs&) = 0;
+
+ // Executes a SQL query on the specified TracePoolShard.
+ virtual base::StatusOrStream<protos::TracePoolShardQueryResponse>
+ TracePoolShardQuery(const protos::TracePoolShardQueryArgs&) = 0;
+
+ // Destroys the TracePoolShard with the specified id.
+ virtual base::StatusOrFuture<protos::TracePoolShardDestroyResponse>
+ TracePoolShardDestroy(const protos::TracePoolShardDestroyArgs&) = 0;
+};
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_CLOUD_TRACE_PROCESSOR_WORKER_H_
diff --git a/include/perfetto/ext/tracing/core/consumer.h b/include/perfetto/ext/tracing/core/consumer.h
index 7a7d81af1..f55b810df 100644
--- a/include/perfetto/ext/tracing/core/consumer.h
+++ b/include/perfetto/ext/tracing/core/consumer.h
@@ -20,6 +20,7 @@
#include <vector>
#include "perfetto/base/export.h"
+#include "perfetto/ext/base/uuid.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/observable_events.h"
#include "perfetto/tracing/core/forward_decls.h"
@@ -81,7 +82,12 @@ class PERFETTO_EXPORT_COMPONENT Consumer {
// Called back by the Service (or transport layer) after invoking
// TracingService::ConsumerEndpoint::CloneSession().
// TODO(primiano): make pure virtual after various 3way patches.
- virtual void OnSessionCloned(bool success, const std::string& error);
+ struct OnSessionClonedArgs {
+ bool success;
+ std::string error;
+ base::Uuid uuid; // UUID of the cloned session.
+ };
+ virtual void OnSessionCloned(const OnSessionClonedArgs&);
};
} // namespace perfetto
diff --git a/include/perfetto/ext/tracing/core/tracing_service.h b/include/perfetto/ext/tracing/core/tracing_service.h
index 82e53f7bf..b82a96a01 100644
--- a/include/perfetto/ext/tracing/core/tracing_service.h
+++ b/include/perfetto/ext/tracing/core/tracing_service.h
@@ -28,6 +28,7 @@
#include "perfetto/ext/base/sys_types.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/shared_memory.h"
+#include "perfetto/ext/tracing/core/trace_packet.h"
#include "perfetto/tracing/buffer_exhausted_policy.h"
#include "perfetto/tracing/core/forward_decls.h"
@@ -253,6 +254,14 @@ class PERFETTO_EXPORT_COMPONENT ConsumerEndpoint {
virtual void SaveTraceForBugreport(SaveTraceForBugreportCallback) = 0;
}; // class ConsumerEndpoint.
+struct PERFETTO_EXPORT_COMPONENT TracingServiceInitOpts {
+ // Function used by tracing service to compress packets. Takes a pointer to
+ // a vector of TracePackets and replaces the packets in the vector with
+ // compressed ones.
+ using CompressorFn = void (*)(std::vector<TracePacket>*);
+ CompressorFn compressor_fn = nullptr;
+};
+
// The public API of the tracing Service business logic.
//
// Exposed to:
@@ -267,6 +276,7 @@ class PERFETTO_EXPORT_COMPONENT TracingService {
public:
using ProducerEndpoint = perfetto::ProducerEndpoint;
using ConsumerEndpoint = perfetto::ConsumerEndpoint;
+ using InitOpts = TracingServiceInitOpts;
// Default sizes used by the service implementation and client library.
static constexpr size_t kDefaultShmPageSize = 4096ul;
@@ -286,10 +296,12 @@ class PERFETTO_EXPORT_COMPONENT TracingService {
kDisabled
};
- // Implemented in src/core/tracing_service_impl.cc .
+ // Implemented in src/core/tracing_service_impl.cc . CompressorFn can be
+ // nullptr, in which case TracingService will not support compression.
static std::unique_ptr<TracingService> CreateInstance(
std::unique_ptr<SharedMemory::Factory>,
- base::TaskRunner*);
+ base::TaskRunner*,
+ InitOpts init_opts = {});
virtual ~TracingService();
diff --git a/include/perfetto/ext/tracing/ipc/service_ipc_host.h b/include/perfetto/ext/tracing/ipc/service_ipc_host.h
index 5c51c4aab..b24ccb5af 100644
--- a/include/perfetto/ext/tracing/ipc/service_ipc_host.h
+++ b/include/perfetto/ext/tracing/ipc/service_ipc_host.h
@@ -23,6 +23,7 @@
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/unix_socket.h"
#include "perfetto/ext/tracing/core/basic_types.h"
+#include "perfetto/ext/tracing/core/tracing_service.h"
namespace perfetto {
namespace base {
@@ -33,8 +34,6 @@ namespace ipc {
class Host;
} // namespace ipc
-class TracingService;
-
// Creates an instance of the service (business logic + UNIX socket transport).
// Exposed to:
// The code in the tracing client that will host the service e.g., traced.
@@ -42,7 +41,9 @@ class TracingService;
// src/tracing/ipc/service/service_ipc_host_impl.cc
class PERFETTO_EXPORT_COMPONENT ServiceIPCHost {
public:
- static std::unique_ptr<ServiceIPCHost> CreateInstance(base::TaskRunner*);
+ static std::unique_ptr<ServiceIPCHost> CreateInstance(
+ base::TaskRunner*,
+ TracingService::InitOpts = {});
virtual ~ServiceIPCHost();
// Start listening on the Producer & Consumer ports. Returns false in case of
diff --git a/include/perfetto/protozero/proto_decoder.h b/include/perfetto/protozero/proto_decoder.h
index 2210532f3..c27fcadf2 100644
--- a/include/perfetto/protozero/proto_decoder.h
+++ b/include/perfetto/protozero/proto_decoder.h
@@ -340,7 +340,8 @@ class PERFETTO_EXPORT_COMPONENT TypedProtoDecoderBase : public ProtoDecoder {
uint32_t field_id,
bool* parse_error_location) const {
const Field& field = Get(field_id);
- if (field.valid()) {
+ if (field.valid() &&
+ field.type() == proto_utils::ProtoWireType::kLengthDelimited) {
return PackedRepeatedFieldIterator<wire_type, cpp_type>(
field.data(), field.size(), parse_error_location);
}
diff --git a/include/perfetto/tracing/core/trace_config.h b/include/perfetto/tracing/core/trace_config.h
index 3e2a83066..e9807ab56 100644
--- a/include/perfetto/tracing/core/trace_config.h
+++ b/include/perfetto/tracing/core/trace_config.h
@@ -25,4 +25,16 @@
#include "protos/perfetto/config/trace_config.gen.h"
+namespace perfetto {
+
+inline TraceConfig::TriggerConfig::TriggerMode GetTriggerMode(
+ const TraceConfig& cfg) {
+ auto mode = cfg.trigger_config().trigger_mode();
+ if (cfg.trigger_config().use_clone_snapshot_if_available())
+ mode = TraceConfig::TriggerConfig::CLONE_SNAPSHOT;
+ return mode;
+}
+
+} // namespace perfetto
+
#endif // INCLUDE_PERFETTO_TRACING_CORE_TRACE_CONFIG_H_
diff --git a/include/perfetto/tracing/data_source.h b/include/perfetto/tracing/data_source.h
index 95036d148..26525faae 100644
--- a/include/perfetto/tracing/data_source.h
+++ b/include/perfetto/tracing/data_source.h
@@ -105,7 +105,7 @@ class PERFETTO_EXPORT_COMPONENT DataSourceBase {
};
virtual void OnStart(const StartArgs&);
- class StopArgs {
+ class PERFETTO_EXPORT_COMPONENT StopArgs {
public:
virtual ~StopArgs();
@@ -190,6 +190,22 @@ struct DefaultDataSourceTraits {
}
};
+// Holds the type for a DataSource. Accessed by the static Trace() method
+// fastpaths. This allows redefinitions under a component where a component
+// specific export macro is used.
+// Due to C2086 (redefinition) error on MSVC/clang-cl, internal::DataSourceType
+// can't be a static data member. To avoid explicit specialization after
+// instantiation error, type() needs to be in a template helper class that's
+// instantiated independently from DataSource. See b/280777748.
+template <typename DerivedDataSource,
+ typename DataSourceTraits = DefaultDataSourceTraits>
+struct DataSourceHelper {
+ static internal::DataSourceType& type() {
+ static perfetto::internal::DataSourceType type_;
+ return type_;
+ }
+};
+
// Templated base class meant to be derived by embedders to create a custom data
// source. DerivedDataSource must be the type of the derived class itself, e.g.:
// class MyDataSource : public DataSource<MyDataSource> {...}.
@@ -200,6 +216,7 @@ template <typename DerivedDataSource,
typename DataSourceTraits = DefaultDataSourceTraits>
class DataSource : public DataSourceBase {
struct DefaultTracePointTraits;
+ using Helper = DataSourceHelper<DerivedDataSource, DataSourceTraits>;
public:
// The BufferExhaustedPolicy to use for TraceWriters of this DataSource.
@@ -286,7 +303,8 @@ class DataSource : public DataSourceBase {
// validity before using it. After checking, the handle is guaranteed to
// remain valid until the handle goes out of scope.
LockedHandle<DerivedDataSource> GetDataSourceLocked() const {
- auto* internal_state = type_.static_state()->TryGet(instance_index_);
+ auto* internal_state =
+ Helper::type().static_state()->TryGet(instance_index_);
if (!internal_state)
return LockedHandle<DerivedDataSource>();
std::unique_lock<std::recursive_mutex> lock(internal_state->lock);
@@ -304,7 +322,7 @@ class DataSource : public DataSourceBase {
typename DataSourceTraits::IncrementalStateType* GetIncrementalState() {
return static_cast<typename DataSourceTraits::IncrementalStateType*>(
- type_.GetIncrementalState(tls_inst_, instance_index_));
+ Helper::type().GetIncrementalState(tls_inst_, instance_index_));
}
private:
@@ -382,20 +400,20 @@ class DataSource : public DataSourceBase {
typename Traits::TracePointData trace_point_data = {}) {
PERFETTO_DCHECK(cached_instances);
- if (!type_.TracePrologue<DataSourceTraits, Traits>(
+ if (!Helper::type().template TracePrologue<DataSourceTraits, Traits>(
&tls_state_, &cached_instances, trace_point_data)) {
return;
}
for (internal::DataSourceType::InstancesIterator it =
- type_.BeginIteration<Traits>(cached_instances, tls_state_,
- trace_point_data);
- it.instance;
- type_.NextIteration<Traits>(&it, tls_state_, trace_point_data)) {
+ Helper::type().template BeginIteration<Traits>(
+ cached_instances, tls_state_, trace_point_data);
+ it.instance; Helper::type().template NextIteration<Traits>(
+ &it, tls_state_, trace_point_data)) {
tracing_fn(TraceContext(it.instance, it.i));
}
- type_.TraceEpilogue(tls_state_);
+ Helper::type().TraceEpilogue(tls_state_);
}
// Registers the data source on all tracing backends, including ones that
@@ -413,7 +431,6 @@ class DataSource : public DataSourceBase {
const Args&... constructor_args) {
// Silences -Wunused-variable warning in case the trace method is not used
// by the translation unit that declares the data source.
- (void)type_;
(void)tls_state_;
auto factory = [constructor_args...]() {
@@ -423,7 +440,7 @@ class DataSource : public DataSourceBase {
internal::DataSourceParams params{
DerivedDataSource::kSupportsMultipleInstances,
DerivedDataSource::kRequiresCallbacksUnderLock};
- return type_.Register(
+ return Helper::type().Register(
descriptor, factory, params, DerivedDataSource::kBufferExhaustedPolicy,
GetCreateTlsFn(
static_cast<typename DataSourceTraits::TlsStateType*>(nullptr)),
@@ -435,7 +452,7 @@ class DataSource : public DataSourceBase {
// Updates the data source descriptor.
static void UpdateDescriptor(const DataSourceDescriptor& descriptor) {
- type_.UpdateDescriptor(descriptor);
+ Helper::type().UpdateDescriptor(descriptor);
}
private:
@@ -456,7 +473,7 @@ class DataSource : public DataSourceBase {
// implement per-category enabled states.
struct TracePointData {};
static constexpr std::atomic<uint32_t>* GetActiveInstances(TracePointData) {
- return type_.valid_instances();
+ return Helper::type().valid_instances();
}
};
@@ -506,10 +523,6 @@ class DataSource : public DataSourceBase {
return nullptr;
}
- // The type of this data source. Accessed by the static Trace() method
- // fastpaths.
- static internal::DataSourceType type_;
-
// This TLS object is a cached raw pointer and has deliberately no destructor.
// The Platform implementation is supposed to create and manage the lifetime
// of the Platform::ThreadLocalObject and take care of destroying it.
@@ -522,9 +535,6 @@ class DataSource : public DataSourceBase {
// static
template <typename T, typename D>
-internal::DataSourceType DataSource<T, D>::type_;
-// static
-template <typename T, typename D>
PERFETTO_THREAD_LOCAL internal::DataSourceThreadLocalState*
DataSource<T, D>::tls_state_;
@@ -547,16 +557,11 @@ PERFETTO_THREAD_LOCAL internal::DataSourceThreadLocalState*
// where a component specific export macro is used.
#define PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(attrs, ...) \
template <> \
- attrs perfetto::internal::DataSourceType \
- perfetto::DataSource<__VA_ARGS__>::type_
+ attrs perfetto::internal::DataSourceType& \
+ perfetto::DataSourceHelper<__VA_ARGS__>::type()
// This macro must be used once for each data source in one source file to
// allocate static storage for the data source's static state.
-//
-// Note: if MSVC fails with a C2086 (redefinition) error here, use the
-// permissive- flag to enable standards-compliant mode. See
-// https://developercommunity.visualstudio.com/content/problem/319447/
-// explicit-specialization-of-static-data-member-inco.html.
#define PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(...) \
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS( \
PERFETTO_COMPONENT_EXPORT, __VA_ARGS__)
@@ -566,7 +571,11 @@ PERFETTO_THREAD_LOCAL internal::DataSourceThreadLocalState*
// where a component specific export macro is used.
#define PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(attrs, ...) \
template <> \
- attrs perfetto::internal::DataSourceType \
- perfetto::DataSource<__VA_ARGS__>::type_ {}
+ perfetto::internal::DataSourceType& \
+ perfetto::DataSourceHelper<__VA_ARGS__>::type() { \
+ static perfetto::internal::DataSourceType type_; \
+ return type_; \
+ } \
+ PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
#endif // INCLUDE_PERFETTO_TRACING_DATA_SOURCE_H_
diff --git a/include/perfetto/tracing/interceptor.h b/include/perfetto/tracing/interceptor.h
index b800cb32b..637c8bf2e 100644
--- a/include/perfetto/tracing/interceptor.h
+++ b/include/perfetto/tracing/interceptor.h
@@ -187,7 +187,7 @@ class PERFETTO_EXPORT_COMPONENT InterceptorBase {
// To define your own state, subclass this with the same name in the
// interceptor class. A reference to the state can then be looked up through
// context.GetThreadLocalState() in the trace packet interceptor function.
- class ThreadLocalState {
+ class PERFETTO_EXPORT_COMPONENT ThreadLocalState {
public:
virtual ~ThreadLocalState();
};
diff --git a/include/perfetto/tracing/internal/track_event_macros.h b/include/perfetto/tracing/internal/track_event_macros.h
index 6d2777ef3..f10ef398e 100644
--- a/include/perfetto/tracing/internal/track_event_macros.h
+++ b/include/perfetto/tracing/internal/track_event_macros.h
@@ -156,7 +156,7 @@
// C++17 doesn't like a move constructor being defined for the EventFinalizer
// class but C++11 and MSVC doesn't compile without it being defined so support
// both.
-#if PERFETTO_IS_AT_LEAST_CPP17() && !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC)
+#if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC)
#define PERFETTO_INTERNAL_EVENT_FINALIZER_KEYWORD delete
#else
#define PERFETTO_INTERNAL_EVENT_FINALIZER_KEYWORD default
diff --git a/protos/perfetto/cloud_trace_processor/BUILD.gn b/protos/perfetto/cloud_trace_processor/BUILD.gn
new file mode 100644
index 000000000..83464341c
--- /dev/null
+++ b/protos/perfetto/cloud_trace_processor/BUILD.gn
@@ -0,0 +1,38 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../../gn/proto_library.gni")
+
+SOURCES = [
+ "common.proto",
+ "orchestrator.proto",
+ "worker.proto",
+]
+
+perfetto_proto_library("@TYPE@") {
+ proto_generators = [
+ "lite",
+ "zero",
+ "source_set",
+ ]
+ deps = [ "../trace_processor:@TYPE@" ] # needed for descriptor.proto.
+ sources = SOURCES
+}
+
+if (enable_perfetto_grpc) {
+ perfetto_grpc_library("cloud_trace_processor_grpc") {
+ deps = [ ":lite" ]
+ sources = SOURCES
+ }
+}
diff --git a/protos/perfetto/cloud_trace_processor/common.proto b/protos/perfetto/cloud_trace_processor/common.proto
new file mode 100644
index 000000000..f2fd5cb9d
--- /dev/null
+++ b/protos/perfetto/cloud_trace_processor/common.proto
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+enum TracePoolType {
+ TYPE_UNKNOWN = 0;
+
+ // Indicates that the trace pool can be accessed by more than one user. This
+ // implies the pool is "stateless" (i.e. TraceProcessor instances do not
+ // retain state between RPCs).
+ SHARED = 1;
+
+ // Indicates that the trace pool is only accessible by a single user at a
+ // time. This implies the pool is "stateful" (i.e. TraceProcessor instances
+ // retain state across RPCs).
+ DEDICATED = 2;
+}
diff --git a/protos/perfetto/cloud_trace_processor/orchestrator.proto b/protos/perfetto/cloud_trace_processor/orchestrator.proto
new file mode 100644
index 000000000..2f16e2346
--- /dev/null
+++ b/protos/perfetto/cloud_trace_processor/orchestrator.proto
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+import "protos/perfetto/trace_processor/trace_processor.proto";
+import "protos/perfetto/cloud_trace_processor/common.proto";
+
+// RPC interface for a CloudTraceProcessor Orchestrator.
+//
+// Each CloudTraceProcessor instance has a single Orchestrator which is
+// responsible for receiving requests for loading and querying traces from
+// clients and shards these requests among a set of "Workers".
+service CloudTraceProcessorOrchestrator {
+ // Creates a TracePool with the specified arguments.
+ //
+ // A TracePool is a logical group of traces which can be addressed with a
+ // single id.
+ //
+ // Pools can be "shared" or "dedicated":
+ // a) a shared pool has the trace processor instances backing the pool shared
+ // among a group of users. This implicitly means that the pools are
+ // "stateless" (i.e. do not preserve trace processor state between RPCs) as
+ // the state of one user should not interfere with the state of another.
+ // b) a dedicated pool belongs to a single user and can only be accessed
+ // by that user. These pools are "stateful" i.e. preserve trace processor
+ // state between RPCs.
+ rpc TracePoolCreate(TracePoolCreateArgs) returns (TracePoolCreateResponse);
+
+ // Changes the set of traces associated with the specified TracePool.
+ //
+ // If this operation completes successfully, any future requests to this pool
+ // shard will refer to this set of traces.
+ rpc TracePoolSetTraces(TracePoolSetTracesArgs)
+ returns (TracePoolSetTracesResponse);
+
+ // Executes a SQL query on the specified TracePool and returns a stream
+ // with each element being the response for executing the query on the
+ // associated trace.
+ //
+ // Note that each trace can return >1 result due to chunking of protos at the
+ // TraceProcessor::QueryResult level.
+ rpc TracePoolQuery(TracePoolQueryArgs)
+ returns (stream TracePoolQueryResponse);
+
+ // Destroys the TracePool with the specified id.
+ //
+ // Any future requests to this pool will return an error. However, the
+ // same pool id (if a named pool) can be used to create a new pool.
+ rpc TracePoolDestroy(TracePoolDestroyArgs) returns (TracePoolDestroyResponse);
+}
+
+// Request/Response for Orchestrator::TracePoolCreate.
+message TracePoolCreateArgs {
+ optional TracePoolType pool_type = 1;
+
+ // If |pool_type| == SHARED, the name which should be refer to the pool. This
+ // name will form part of |pool_id|.
+ optional string shared_pool_name = 2;
+}
+message TracePoolCreateResponse {
+ // The id of the pool which should be used to reference the pool in all future
+ // RPCs. For shared pools, this id is expected to be a stable transformation
+ // of |shared_pool_name|.
+ optional string pool_id = 1;
+}
+
+// Request/Response for Orchestrator::TracePoolSetTraces.
+message TracePoolSetTracesArgs {
+ optional string pool_id = 1;
+
+ // The list of traces which should be associated with this pool. The existing
+ // loaded trace list will be diffed against this list. Traces not present in
+ // this list and loaded will be unloaded while traces present in this list
+ // and unloaded will be loaded.
+ repeated string traces = 2;
+}
+message TracePoolSetTracesResponse {}
+
+// Request/Response for Orchestrator::TracePoolQuery.
+message TracePoolQueryArgs {
+ optional string pool_id = 1;
+ optional string sql_query = 2;
+}
+message TracePoolQueryResponse {
+ optional string trace = 1;
+ optional QueryResult result = 2;
+}
+
+// Request/Response for Orchestrator::TracePoolDestroy.
+message TracePoolDestroyArgs {
+ optional string pool_id = 1;
+}
+message TracePoolDestroyResponse {}
diff --git a/protos/perfetto/cloud_trace_processor/worker.proto b/protos/perfetto/cloud_trace_processor/worker.proto
new file mode 100644
index 000000000..407ef90d3
--- /dev/null
+++ b/protos/perfetto/cloud_trace_processor/worker.proto
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+import "protos/perfetto/trace_processor/trace_processor.proto";
+import "protos/perfetto/cloud_trace_processor/common.proto";
+
+// Interface for a CloudTraceProcessor "Worker".
+//
+// Workers are are owned by a |Orchestrator| who assigns groups of traces to
+// them (known as a PoolShards) and forwards any requests from end users.
+// Workers are reponsible for loading assigned traces with TraceProcessor and
+// executing the requests.
+service CloudTraceProcessorWorker {
+ // Creates a TracePoolShard which will be owned by this worker and returns
+ // whether it was successfully created.
+ //
+ // Orchestrators are responsible for handling groups of traces which the user
+ // has requested to be loaded: these are known as TracePools. The orchestrator
+ // then breaks these pools into pieces and shards them out to workers, each of
+ // which is known as a TracePoolShard.
+ //
+ // Thus, a TracePoolShard is unique identified by the tuple (worker, pool id).
+ rpc TracePoolShardCreate(TracePoolShardCreateArgs)
+ returns (TracePoolShardCreateResponse);
+
+ // Associates the provided list of traces to this TracePoolShard and returns
+ // a stream with each element indicating the successful load of one trace
+ // (which allows monitoring the progress of loads) or a terminal error if the
+ // assignment of any trace failed.
+ //
+ // If this operation completes successfully, any future requests to this pool
+ // shard will refer to this set of traces.
+ rpc TracePoolShardSetTraces(TracePoolShardSetTracesArgs)
+ returns (stream TracePoolShardSetTracesResponse);
+
+ // Executes a SQL query on the specified TracePoolShard and returns a stream
+ // with each element being the response for executing the query on the
+ // associated trace.
+ //
+ // Note that each trace can return >1 result due to chunking of protos at the
+ // TraceProcessor::QueryResult level.
+ rpc TracePoolShardQuery(TracePoolShardQueryArgs)
+ returns (stream TracePoolShardQueryResponse);
+
+ // Destroys the TracePoolShard with the specified id.
+ //
+ // Any future requests to this shard id will return an error. However, the
+ // same pool id can be used to create a new shard.
+ rpc TracePoolShardDestroy(TracePoolShardDestroyArgs)
+ returns (TracePoolShardDestroyResponse);
+}
+
+// Request/Response for Worker::TracePoolShardCreate.
+message TracePoolShardCreateArgs {
+ optional string pool_id = 1;
+ optional TracePoolType pool_type = 2;
+}
+message TracePoolShardCreateResponse {}
+
+// Request/Response for Worker::TracePoolShardSetTraces.
+message TracePoolShardSetTracesArgs {
+ optional string pool_id = 1;
+
+ // The list of traces which should be associated with this shard. The existing
+ // loaded trace list will be diffed against this list. Traces not present in
+ // this list and loaded will be unloaded while traces present in this list
+ // and unloaded will be loaded.
+ repeated string traces = 2;
+}
+message TracePoolShardSetTracesResponse {
+ optional string trace = 1;
+}
+
+// Request/Response for Worker::TracePoolShardQuery.
+message TracePoolShardQueryArgs {
+ optional string pool_id = 1;
+ optional string sql_query = 2;
+}
+message TracePoolShardQueryResponse {
+ optional string trace = 1;
+ optional QueryResult result = 2;
+}
+
+// Request/Response for Worker::TracePoolShardDestroy.
+message TracePoolShardDestroyArgs {
+ optional string pool_id = 1;
+}
+message TracePoolShardDestroyResponse {}
diff --git a/protos/perfetto/common/observable_events.proto b/protos/perfetto/common/observable_events.proto
index 0bde227f0..85767a62a 100644
--- a/protos/perfetto/common/observable_events.proto
+++ b/protos/perfetto/common/observable_events.proto
@@ -35,6 +35,11 @@ message ObservableEvents {
// Introduced in Android 11 (R).
TYPE_ALL_DATA_SOURCES_STARTED = 2;
+ // When a tracing session has one or more triggers of type CLONE_SNAPSHOT
+ // and a matching trigger is hit, the service will send this notification to
+ // the consumer after |stop_delay_ms|.
+ TYPE_CLONE_TRIGGER_HIT = 4;
+
// Note: internally these are used as OR flags. Next values: 4, 8, 16, ...
// TODO(eseckler): Extend this for producer & data source registrations.
@@ -52,6 +57,15 @@ message ObservableEvents {
optional DataSourceInstanceState state = 3;
}
+ message CloneTriggerHit {
+ // The TracingSessionID of the original tracing session which had a
+ // CLONE_SNAPSHOT trigger defined. This is necessary just because the
+ // consumer has no idea of what is the TSID of its own tracing session and
+ // there is no other good way to plumb it.
+ optional int64 tracing_session_id = 1;
+ }
+
repeated DataSourceInstanceStateChange instance_state_changes = 1;
optional bool all_data_sources_started = 2;
+ optional CloneTriggerHit clone_trigger_hit = 3;
}
diff --git a/protos/perfetto/common/tracing_service_capabilities.proto b/protos/perfetto/common/tracing_service_capabilities.proto
index 123f9bf34..308f18df8 100644
--- a/protos/perfetto/common/tracing_service_capabilities.proto
+++ b/protos/perfetto/common/tracing_service_capabilities.proto
@@ -35,4 +35,7 @@ message TracingServiceCapabilities {
// Whether the service supports TraceConfig.output_path (for asking traced to
// create the output file instead of passing a file descriptor).
optional bool has_trace_config_output_path = 3;
+
+ // Whether the service supports CloneSession and CLONE_SNAPSHOT triggers.
+ optional bool has_clone_session = 4;
}
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 7b1171f4b..85f1de780 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -833,6 +833,7 @@ message ProcessStatsConfig {
// If > 0 samples counters (see process_stats.proto) from
// /proc/pid/status and oom_score_adj every X ms.
+ // It will also sample /proc/pid/smaps_rollup if scan_smaps_rollup = true.
// This is required to be > 100ms to avoid excessive CPU usage.
// TODO(primiano): add CPU cost for change this value.
optional uint32 proc_stats_poll_ms = 4;
@@ -861,6 +862,10 @@ message ProcessStatsConfig {
// new fds opened after initially scanning a process will not be
// recognized.
optional bool resolve_process_fds = 9;
+
+ // If enabled memory stats from /proc/pid/smaps_rollup will be included
+ // in process stats.
+ optional bool scan_smaps_rollup = 10;
}
// End of protos/perfetto/config/process_stats/process_stats_config.proto
@@ -2700,7 +2705,7 @@ message DataSourceConfig {
// It contains the general config for the logging buffer(s) and the configs for
// all the data source being enabled.
//
-// Next id: 37.
+// Next id: 38.
message TraceConfig {
message BufferConfig {
optional uint32 size_kb = 1;
@@ -2968,12 +2973,35 @@ message TraceConfig {
// consumer.
STOP_TRACING = 2;
- // NOTE: do not add new enum values here because of a subtle backward
- // compat bug which might cause indefinite tracing on older versions of
- // the service. See b/274931668 .
+ // When this mode is chosen, this causes a snapshot of the current tracing
+ // session to be created after |stop_delay_ms| while the current tracing
+ // session continues undisturbed (% an extra flush). This mode can be
+ // used only when the tracing session is handled by the "perfetto" cmdline
+ // client (which is true in 90% of cases). Part of the business logic
+ // necessary for this behavior, and ensuing file handling, lives in
+ // perfetto_cmd.cc . On other consumers, this causes only a notification
+ // of the trigger through a CloneTriggerHit ObservableEvent. The custom
+ // consumer is supposed to call CloneSession() itself after the event.
+ // Use use_clone_snapshot_if_available=true when targeting older versions
+ // of perfetto.
+ CLONE_SNAPSHOT = 3;
+
+ // NOTE: CLONE_SNAPSHOT should be used only when we targeting Android U+
+ // (14+) / Perfetto v34+. A bug in older versions of the tracing service
+ // might cause indefinitely long tracing sessions (see b/274931668).
}
optional TriggerMode trigger_mode = 1;
+ // This flag is really a workaround for b/274931668. This is needed only
+ // when deploying configs to different versions of the tracing service.
+ // When this is set to true this has the same effect of setting trigger_mode
+ // to CLONE_SNAPSHOT on newer versions of the service. This boolean has been
+ // introduced to allow to have configs that use CLONE_SNAPSHOT on newer
+ // versions of Android and fall back to STOP_TRACING on older versions where
+ // CLONE_SNAPSHOT did not exist.
+ // When using this flag, trigger_mode must be set to STOP_TRACING.
+ optional bool use_clone_snapshot_if_available = 4;
+
message Trigger {
// The producer must specify this name to activate the trigger.
optional string name = 1;
@@ -2985,6 +3013,8 @@ message TraceConfig {
// After a trigger is received either in START_TRACING or STOP_TRACING
// mode then the trace will end |stop_delay_ms| after triggering.
+ // In CLONE_SNAPSHOT mode, this is the delay between the trigger and the
+ // snapshot.
// If |prefer_suspend_clock_for_duration| is set, the duration will be
// based on wall-clock, counting also time in suspend.
optional uint32 stop_delay_ms = 3;
@@ -3064,6 +3094,11 @@ message TraceConfig {
}
optional CompressionType compression_type = 24;
+ // Use the legacy codepath that compresses from perfetto_cmd.cc instead of
+ // using the new codepath that compresses from tracing_service_impl.cc. This
+ // will be removed in the future.
+ optional bool compress_from_cli = 37;
+
// Android-only. Not for general use. If set, saves the trace into an
// incident. This field is read by perfetto_cmd, rather than the tracing
// service. This field must be set when passing the --upload flag to
diff --git a/protos/perfetto/config/process_stats/process_stats_config.proto b/protos/perfetto/config/process_stats/process_stats_config.proto
index d71e7d360..239513fed 100644
--- a/protos/perfetto/config/process_stats/process_stats_config.proto
+++ b/protos/perfetto/config/process_stats/process_stats_config.proto
@@ -41,6 +41,7 @@ message ProcessStatsConfig {
// If > 0 samples counters (see process_stats.proto) from
// /proc/pid/status and oom_score_adj every X ms.
+ // It will also sample /proc/pid/smaps_rollup if scan_smaps_rollup = true.
// This is required to be > 100ms to avoid excessive CPU usage.
// TODO(primiano): add CPU cost for change this value.
optional uint32 proc_stats_poll_ms = 4;
@@ -69,4 +70,8 @@ message ProcessStatsConfig {
// new fds opened after initially scanning a process will not be
// recognized.
optional bool resolve_process_fds = 9;
+
+ // If enabled memory stats from /proc/pid/smaps_rollup will be included
+ // in process stats.
+ optional bool scan_smaps_rollup = 10;
}
diff --git a/protos/perfetto/config/trace_config.proto b/protos/perfetto/config/trace_config.proto
index 04e637c0e..4fe3ea974 100644
--- a/protos/perfetto/config/trace_config.proto
+++ b/protos/perfetto/config/trace_config.proto
@@ -26,7 +26,7 @@ import "protos/perfetto/config/data_source_config.proto";
// It contains the general config for the logging buffer(s) and the configs for
// all the data source being enabled.
//
-// Next id: 37.
+// Next id: 38.
message TraceConfig {
message BufferConfig {
optional uint32 size_kb = 1;
@@ -294,12 +294,35 @@ message TraceConfig {
// consumer.
STOP_TRACING = 2;
- // NOTE: do not add new enum values here because of a subtle backward
- // compat bug which might cause indefinite tracing on older versions of
- // the service. See b/274931668 .
+ // When this mode is chosen, this causes a snapshot of the current tracing
+ // session to be created after |stop_delay_ms| while the current tracing
+ // session continues undisturbed (% an extra flush). This mode can be
+ // used only when the tracing session is handled by the "perfetto" cmdline
+ // client (which is true in 90% of cases). Part of the business logic
+ // necessary for this behavior, and ensuing file handling, lives in
+ // perfetto_cmd.cc . On other consumers, this causes only a notification
+ // of the trigger through a CloneTriggerHit ObservableEvent. The custom
+ // consumer is supposed to call CloneSession() itself after the event.
+ // Use use_clone_snapshot_if_available=true when targeting older versions
+ // of perfetto.
+ CLONE_SNAPSHOT = 3;
+
+ // NOTE: CLONE_SNAPSHOT should be used only when we targeting Android U+
+ // (14+) / Perfetto v34+. A bug in older versions of the tracing service
+ // might cause indefinitely long tracing sessions (see b/274931668).
}
optional TriggerMode trigger_mode = 1;
+ // This flag is really a workaround for b/274931668. This is needed only
+ // when deploying configs to different versions of the tracing service.
+ // When this is set to true this has the same effect of setting trigger_mode
+ // to CLONE_SNAPSHOT on newer versions of the service. This boolean has been
+ // introduced to allow to have configs that use CLONE_SNAPSHOT on newer
+ // versions of Android and fall back to STOP_TRACING on older versions where
+ // CLONE_SNAPSHOT did not exist.
+ // When using this flag, trigger_mode must be set to STOP_TRACING.
+ optional bool use_clone_snapshot_if_available = 4;
+
message Trigger {
// The producer must specify this name to activate the trigger.
optional string name = 1;
@@ -311,6 +334,8 @@ message TraceConfig {
// After a trigger is received either in START_TRACING or STOP_TRACING
// mode then the trace will end |stop_delay_ms| after triggering.
+ // In CLONE_SNAPSHOT mode, this is the delay between the trigger and the
+ // snapshot.
// If |prefer_suspend_clock_for_duration| is set, the duration will be
// based on wall-clock, counting also time in suspend.
optional uint32 stop_delay_ms = 3;
@@ -390,6 +415,11 @@ message TraceConfig {
}
optional CompressionType compression_type = 24;
+ // Use the legacy codepath that compresses from perfetto_cmd.cc instead of
+ // using the new codepath that compresses from tracing_service_impl.cc. This
+ // will be removed in the future.
+ optional bool compress_from_cli = 37;
+
// Android-only. Not for general use. If set, saves the trace into an
// incident. This field is read by perfetto_cmd, rather than the tracing
// service. This field must be set when passing the --upload flag to
diff --git a/protos/perfetto/ipc/consumer_port.proto b/protos/perfetto/ipc/consumer_port.proto
index d5a402573..2fdc91978 100644
--- a/protos/perfetto/ipc/consumer_port.proto
+++ b/protos/perfetto/ipc/consumer_port.proto
@@ -289,4 +289,8 @@ message CloneSessionResponse {
// the details about the failure.
optional bool success = 1;
optional string error = 2;
+
+ // The UUID of the cloned session.
+ optional int64 uuid_msb = 3;
+ optional int64 uuid_lsb = 4;
}
diff --git a/protos/perfetto/metrics/android/binder_metric.proto b/protos/perfetto/metrics/android/binder_metric.proto
index 5c4e66f5c..36c1abbff 100644
--- a/protos/perfetto/metrics/android/binder_metric.proto
+++ b/protos/perfetto/metrics/android/binder_metric.proto
@@ -56,6 +56,9 @@ message AndroidBinderMetric {
optional uint32 client_tid = 15;
optional uint32 server_tid = 16;
+
+ optional uint32 client_pid = 17;
+ optional uint32 server_pid = 18;
}
message ThreadStateBreakdown {
diff --git a/protos/perfetto/metrics/android/jank_cuj_metric.proto b/protos/perfetto/metrics/android/jank_cuj_metric.proto
index fa3a7b13b..007554ff6 100644
--- a/protos/perfetto/metrics/android/jank_cuj_metric.proto
+++ b/protos/perfetto/metrics/android/jank_cuj_metric.proto
@@ -61,7 +61,7 @@ message AndroidJankCujMetric {
optional string layer_name = 11;
}
- // Next id: 8
+ // Next id: 10
message Frame {
// Index of the frame within the single user journey.
optional int64 frame_number = 1;
@@ -79,9 +79,17 @@ message AndroidJankCujMetric {
// Whether SF missed the frame deadline.
optional bool sf_missed = 6;
+
+ // Whether the SF callback missed before emitting jank metrics.
+ // SF callback is used to get the jank classification.
+ optional bool sf_callback_missed = 8;
+
+ // Whether the HWUI callback missed before emitting jank metrics.
+ // HWUI callback is used to get the frame duration.
+ optional bool hwui_callback_missed = 9;
}
- // Next id: 16
+ // Next id: 18
message Metrics {
// Overall number of frames within the CUJ.
optional int64 total_frames = 1;
@@ -137,5 +145,11 @@ message AndroidJankCujMetric {
// P99 frame duration in milliseconds.
// Not available in counter_metrics.
optional double frame_dur_ms_p99 = 15;
+
+ // Number of frames with missed SF callback.
+ optional int64 sf_callback_missed_frames = 16;
+
+ // Number of frames with missed HWUI callback.
+ optional int64 hwui_callback_missed_frames = 17;
}
}
diff --git a/protos/perfetto/metrics/android/java_heap_stats.proto b/protos/perfetto/metrics/android/java_heap_stats.proto
index 2579888ee..10a0b8b57 100644
--- a/protos/perfetto/metrics/android/java_heap_stats.proto
+++ b/protos/perfetto/metrics/android/java_heap_stats.proto
@@ -26,7 +26,7 @@ message JavaHeapStats {
optional int64 obj_count = 3;
}
- // Next id: 10
+ // Next id: 11
message Sample {
optional int64 ts = 1;
// Size of the Java heap in bytes
@@ -45,6 +45,8 @@ message JavaHeapStats {
// ART root objects
repeated HeapRoots roots = 7;
+ // OOM adjustment score
+ optional int64 oom_score_adj = 10;
}
// Heap stats per process. One sample per dump (can be > 1 if continuous
diff --git a/protos/perfetto/metrics/android/monitor_contention_metric.proto b/protos/perfetto/metrics/android/monitor_contention_metric.proto
index 91122eb17..00585d861 100644
--- a/protos/perfetto/metrics/android/monitor_contention_metric.proto
+++ b/protos/perfetto/metrics/android/monitor_contention_metric.proto
@@ -21,28 +21,38 @@ package perfetto.protos;
// This metric provides information about the monitor contention graph in a
// trace
message AndroidMonitorContentionMetric {
+ // Next field id: 24
message Node {
+ // Global context
optional int64 node_parent_id = 1;
optional int64 node_id = 2;
optional int64 ts = 3;
optional int64 dur = 4;
+ optional string process_name = 14;
+ optional uint32 pid = 23;
+ optional uint32 waiter_count = 11;
+ repeated ThreadStateBreakdown thread_states = 19;
+ repeated BlockedFunctionBreakdown blocked_functions = 20;
+
+ // Blocking context
optional string blocking_method = 5;
- optional string blocked_method = 6;
optional string short_blocking_method = 7;
- optional string short_blocked_method = 8;
optional string blocking_src = 9;
+ optional string blocking_thread_name = 13;
+ optional bool is_blocking_thread_main = 16;
+ optional uint32 blocking_thread_tid = 22;
+
+ // Blocked context
+ optional string blocked_method = 6;
+ optional string short_blocked_method = 8;
optional string blocked_src = 10;
- optional uint32 waiter_count = 11;
optional string blocked_thread_name = 12;
- optional string blocking_thread_name = 13;
- optional string process_name = 14;
optional bool is_blocked_thread_main = 15;
- optional bool is_blocking_thread_main = 16;
+ optional uint32 blocked_thread_tid = 21;
+
+ // Binder context
optional int64 binder_reply_ts = 17;
optional uint32 binder_reply_tid = 18;
-
- repeated ThreadStateBreakdown thread_states = 19;
- repeated BlockedFunctionBreakdown blocked_functions = 20;
}
message ThreadStateBreakdown {
diff --git a/protos/perfetto/metrics/android/process_metadata.proto b/protos/perfetto/metrics/android/process_metadata.proto
index fd7fe7b5d..fa766bea9 100644
--- a/protos/perfetto/metrics/android/process_metadata.proto
+++ b/protos/perfetto/metrics/android/process_metadata.proto
@@ -44,5 +44,8 @@ message AndroidProcessMetadata {
// https://developer.android.com/guide/topics/manifest/manifest-element#uid
repeated Package packages_for_uid = 8;
+ // Pid of the process name.
+ optional int64 pid = 9;
+
reserved 3, 4, 5, 6;
}
diff --git a/protos/perfetto/metrics/android/startup_metric.proto b/protos/perfetto/metrics/android/startup_metric.proto
index 916a2121c..67c904470 100644
--- a/protos/perfetto/metrics/android/startup_metric.proto
+++ b/protos/perfetto/metrics/android/startup_metric.proto
@@ -47,7 +47,7 @@ message AndroidStartupMetric {
// Timing information spanning the intent received by the
// activity manager to the first frame drawn.
- // Next id: 33.
+ // Next id: 35.
message ToFirstFrame {
// The duration between the intent received and first frame.
optional int64 dur_ns = 1;
@@ -117,6 +117,14 @@ message AndroidStartupMetric {
// |time_lock_contention_thread_main|.
optional Slice time_monitor_contention_thread_main = 32;
+ // Time spent in opening dex files on the main thread of the process
+ // being started up.
+ optional Slice time_dex_open_thread_main = 33;
+
+ // Time spent in dlopening .so files on the main thread of the process
+ // being started up.
+ optional Slice time_dlopen_thread_main = 34;
+
// Removed: was other_process_to_activity_cpu_ratio.
reserved 12;
@@ -216,7 +224,7 @@ message AndroidStartupMetric {
optional int64 dex2oat_dur_ns = 7;
}
- // Next id: 20
+ // Next id: 21
message Startup {
// Random id uniquely identifying an app startup in this trace.
optional uint32 startup_id = 1;
@@ -272,6 +280,9 @@ message AndroidStartupMetric {
// Contains information about the class verification.
repeated VerifyClass verify_class = 19;
+ // Contains the dlopen file names.
+ repeated string dlopen_file = 20;
+
// Package name of startups running concurrent to the launch.
repeated string startup_concurrent_to_launch = 18;
diff --git a/protos/perfetto/metrics/android/surfaceflinger.proto b/protos/perfetto/metrics/android/surfaceflinger.proto
index 3cc2c9e08..1f81827e8 100644
--- a/protos/perfetto/metrics/android/surfaceflinger.proto
+++ b/protos/perfetto/metrics/android/surfaceflinger.proto
@@ -54,4 +54,32 @@ message AndroidSurfaceflingerMetric {
// This also equals to the total duration of
// "waiting for GPU completion <fence_num>" in SurfaceFlinger.
optional double total_non_empty_gpu_waiting_dur_ms = 9;
+
+ message MetricsPerDisplay {
+ // Display ID in SF
+ optional string display_id = 1;
+
+ // Counts the number of missed frames in the trace.
+ optional uint32 missed_frames = 2;
+
+ // Counts the number of missed HWC frames in the trace.
+ optional uint32 missed_hwc_frames = 3;
+
+ // Counts the number of missed GPU frames in the trace.
+ optional uint32 missed_gpu_frames = 4;
+
+ // Calculate the number of missed frames divided by
+ // total frames
+ optional double missed_frame_rate = 5;
+
+ // Calculate the number of missed HWC frames divided by
+ // total HWC frames
+ optional double missed_hwc_frame_rate = 6;
+
+ // Calculate the number of missed GPU frames divided by
+ // total GPU frames
+ optional double missed_gpu_frame_rate = 7;
+ }
+
+ repeated MetricsPerDisplay metrics_per_display = 10;
}
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 2fc2bae56..393095c36 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -42,6 +42,9 @@ message AndroidProcessMetadata {
// https://developer.android.com/guide/topics/manifest/manifest-element#uid
repeated Package packages_for_uid = 8;
+ // Pid of the process name.
+ optional int64 pid = 9;
+
reserved 3, 4, 5, 6;
}
@@ -222,6 +225,9 @@ message AndroidBinderMetric {
optional uint32 client_tid = 15;
optional uint32 server_tid = 16;
+
+ optional uint32 client_pid = 17;
+ optional uint32 server_pid = 18;
}
message ThreadStateBreakdown {
@@ -880,7 +886,7 @@ message AndroidJankCujMetric {
optional string layer_name = 11;
}
- // Next id: 8
+ // Next id: 10
message Frame {
// Index of the frame within the single user journey.
optional int64 frame_number = 1;
@@ -898,9 +904,17 @@ message AndroidJankCujMetric {
// Whether SF missed the frame deadline.
optional bool sf_missed = 6;
+
+ // Whether the SF callback missed before emitting jank metrics.
+ // SF callback is used to get the jank classification.
+ optional bool sf_callback_missed = 8;
+
+ // Whether the HWUI callback missed before emitting jank metrics.
+ // HWUI callback is used to get the frame duration.
+ optional bool hwui_callback_missed = 9;
}
- // Next id: 16
+ // Next id: 18
message Metrics {
// Overall number of frames within the CUJ.
optional int64 total_frames = 1;
@@ -956,6 +970,12 @@ message AndroidJankCujMetric {
// P99 frame duration in milliseconds.
// Not available in counter_metrics.
optional double frame_dur_ms_p99 = 15;
+
+ // Number of frames with missed SF callback.
+ optional int64 sf_callback_missed_frames = 16;
+
+ // Number of frames with missed HWUI callback.
+ optional int64 hwui_callback_missed_frames = 17;
}
}
@@ -1005,7 +1025,7 @@ message JavaHeapStats {
optional int64 obj_count = 3;
}
- // Next id: 10
+ // Next id: 11
message Sample {
optional int64 ts = 1;
// Size of the Java heap in bytes
@@ -1024,6 +1044,8 @@ message JavaHeapStats {
// ART root objects
repeated HeapRoots roots = 7;
+ // OOM adjustment score
+ optional int64 oom_score_adj = 10;
}
// Heap stats per process. One sample per dump (can be > 1 if continuous
@@ -1171,28 +1193,38 @@ message AndroidMemoryUnaggregatedMetric {
// This metric provides information about the monitor contention graph in a
// trace
message AndroidMonitorContentionMetric {
+ // Next field id: 24
message Node {
+ // Global context
optional int64 node_parent_id = 1;
optional int64 node_id = 2;
optional int64 ts = 3;
optional int64 dur = 4;
+ optional string process_name = 14;
+ optional uint32 pid = 23;
+ optional uint32 waiter_count = 11;
+ repeated ThreadStateBreakdown thread_states = 19;
+ repeated BlockedFunctionBreakdown blocked_functions = 20;
+
+ // Blocking context
optional string blocking_method = 5;
- optional string blocked_method = 6;
optional string short_blocking_method = 7;
- optional string short_blocked_method = 8;
optional string blocking_src = 9;
+ optional string blocking_thread_name = 13;
+ optional bool is_blocking_thread_main = 16;
+ optional uint32 blocking_thread_tid = 22;
+
+ // Blocked context
+ optional string blocked_method = 6;
+ optional string short_blocked_method = 8;
optional string blocked_src = 10;
- optional uint32 waiter_count = 11;
optional string blocked_thread_name = 12;
- optional string blocking_thread_name = 13;
- optional string process_name = 14;
optional bool is_blocked_thread_main = 15;
- optional bool is_blocking_thread_main = 16;
+ optional uint32 blocked_thread_tid = 21;
+
+ // Binder context
optional int64 binder_reply_ts = 17;
optional uint32 binder_reply_tid = 18;
-
- repeated ThreadStateBreakdown thread_states = 19;
- repeated BlockedFunctionBreakdown blocked_functions = 20;
}
message ThreadStateBreakdown {
@@ -1577,7 +1609,7 @@ message AndroidStartupMetric {
// Timing information spanning the intent received by the
// activity manager to the first frame drawn.
- // Next id: 33.
+ // Next id: 35.
message ToFirstFrame {
// The duration between the intent received and first frame.
optional int64 dur_ns = 1;
@@ -1647,6 +1679,14 @@ message AndroidStartupMetric {
// |time_lock_contention_thread_main|.
optional Slice time_monitor_contention_thread_main = 32;
+ // Time spent in opening dex files on the main thread of the process
+ // being started up.
+ optional Slice time_dex_open_thread_main = 33;
+
+ // Time spent in dlopening .so files on the main thread of the process
+ // being started up.
+ optional Slice time_dlopen_thread_main = 34;
+
// Removed: was other_process_to_activity_cpu_ratio.
reserved 12;
@@ -1746,7 +1786,7 @@ message AndroidStartupMetric {
optional int64 dex2oat_dur_ns = 7;
}
- // Next id: 20
+ // Next id: 21
message Startup {
// Random id uniquely identifying an app startup in this trace.
optional uint32 startup_id = 1;
@@ -1802,6 +1842,9 @@ message AndroidStartupMetric {
// Contains information about the class verification.
repeated VerifyClass verify_class = 19;
+ // Contains the dlopen file names.
+ repeated string dlopen_file = 20;
+
// Package name of startups running concurrent to the launch.
repeated string startup_concurrent_to_launch = 18;
@@ -1860,6 +1903,34 @@ message AndroidSurfaceflingerMetric {
// This also equals to the total duration of
// "waiting for GPU completion <fence_num>" in SurfaceFlinger.
optional double total_non_empty_gpu_waiting_dur_ms = 9;
+
+ message MetricsPerDisplay {
+ // Display ID in SF
+ optional string display_id = 1;
+
+ // Counts the number of missed frames in the trace.
+ optional uint32 missed_frames = 2;
+
+ // Counts the number of missed HWC frames in the trace.
+ optional uint32 missed_hwc_frames = 3;
+
+ // Counts the number of missed GPU frames in the trace.
+ optional uint32 missed_gpu_frames = 4;
+
+ // Calculate the number of missed frames divided by
+ // total frames
+ optional double missed_frame_rate = 5;
+
+ // Calculate the number of missed HWC frames divided by
+ // total HWC frames
+ optional double missed_hwc_frame_rate = 6;
+
+ // Calculate the number of missed GPU frames divided by
+ // total GPU frames
+ optional double missed_gpu_frame_rate = 7;
+ }
+
+ repeated MetricsPerDisplay metrics_per_display = 10;
}
// End of protos/perfetto/metrics/android/surfaceflinger.proto
diff --git a/protos/perfetto/metrics/webview/webview_jank_approximation.proto b/protos/perfetto/metrics/webview/webview_jank_approximation.proto
index 0d01a7797..cdf7299a3 100644
--- a/protos/perfetto/metrics/webview/webview_jank_approximation.proto
+++ b/protos/perfetto/metrics/webview/webview_jank_approximation.proto
@@ -19,9 +19,9 @@ syntax = "proto2";
package perfetto.protos;
message WebViewJankApproximation {
- required int32 webview_janks = 1;
- required int32 webview_janks_without_startup = 2;
- required int32 webview_app_janks = 3;
- required int32 webview_total_janks = 4;
- required int32 total_janks = 5;
+ optional int32 webview_janks = 1;
+ optional int32 webview_janks_without_startup = 2;
+ optional int32 webview_app_janks = 3;
+ optional int32 webview_total_janks = 4;
+ optional int32 total_janks = 5;
}
diff --git a/protos/perfetto/trace/ftrace/ftrace_event.proto b/protos/perfetto/trace/ftrace/ftrace_event.proto
index b86ad9f40..88d364178 100644
--- a/protos/perfetto/trace/ftrace/ftrace_event.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_event.proto
@@ -595,5 +595,7 @@ message FtraceEvent {
HostSmcFtraceEvent host_smc = 479;
HostMemAbortFtraceEvent host_mem_abort = 480;
SuspendResumeMinimalFtraceEvent suspend_resume_minimal = 481;
+ MaliMaliCSFINTERRUPTSTARTFtraceEvent mali_mali_CSF_INTERRUPT_START = 482;
+ MaliMaliCSFINTERRUPTENDFtraceEvent mali_mali_CSF_INTERRUPT_END = 483;
}
}
diff --git a/protos/perfetto/trace/ftrace/mali.proto b/protos/perfetto/trace/ftrace/mali.proto
index 0c59cd409..9d671666b 100644
--- a/protos/perfetto/trace/ftrace/mali.proto
+++ b/protos/perfetto/trace/ftrace/mali.proto
@@ -53,3 +53,13 @@ message MaliMaliKCPUFENCEWAITENDFtraceEvent {
optional uint32 kctx_id = 4;
optional uint32 id = 5;
}
+message MaliMaliCSFINTERRUPTSTARTFtraceEvent {
+ optional int32 kctx_tgid = 1;
+ optional uint32 kctx_id = 2;
+ optional uint64 info_val = 3;
+}
+message MaliMaliCSFINTERRUPTENDFtraceEvent {
+ optional int32 kctx_tgid = 1;
+ optional uint32 kctx_id = 2;
+ optional uint64 info_val = 3;
+}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 7b9279f28..e886311d7 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -833,6 +833,7 @@ message ProcessStatsConfig {
// If > 0 samples counters (see process_stats.proto) from
// /proc/pid/status and oom_score_adj every X ms.
+ // It will also sample /proc/pid/smaps_rollup if scan_smaps_rollup = true.
// This is required to be > 100ms to avoid excessive CPU usage.
// TODO(primiano): add CPU cost for change this value.
optional uint32 proc_stats_poll_ms = 4;
@@ -861,6 +862,10 @@ message ProcessStatsConfig {
// new fds opened after initially scanning a process will not be
// recognized.
optional bool resolve_process_fds = 9;
+
+ // If enabled memory stats from /proc/pid/smaps_rollup will be included
+ // in process stats.
+ optional bool scan_smaps_rollup = 10;
}
// End of protos/perfetto/config/process_stats/process_stats_config.proto
@@ -2700,7 +2705,7 @@ message DataSourceConfig {
// It contains the general config for the logging buffer(s) and the configs for
// all the data source being enabled.
//
-// Next id: 37.
+// Next id: 38.
message TraceConfig {
message BufferConfig {
optional uint32 size_kb = 1;
@@ -2968,12 +2973,35 @@ message TraceConfig {
// consumer.
STOP_TRACING = 2;
- // NOTE: do not add new enum values here because of a subtle backward
- // compat bug which might cause indefinite tracing on older versions of
- // the service. See b/274931668 .
+ // When this mode is chosen, this causes a snapshot of the current tracing
+ // session to be created after |stop_delay_ms| while the current tracing
+ // session continues undisturbed (% an extra flush). This mode can be
+ // used only when the tracing session is handled by the "perfetto" cmdline
+ // client (which is true in 90% of cases). Part of the business logic
+ // necessary for this behavior, and ensuing file handling, lives in
+ // perfetto_cmd.cc . On other consumers, this causes only a notification
+ // of the trigger through a CloneTriggerHit ObservableEvent. The custom
+ // consumer is supposed to call CloneSession() itself after the event.
+ // Use use_clone_snapshot_if_available=true when targeting older versions
+ // of perfetto.
+ CLONE_SNAPSHOT = 3;
+
+ // NOTE: CLONE_SNAPSHOT should be used only when we targeting Android U+
+ // (14+) / Perfetto v34+. A bug in older versions of the tracing service
+ // might cause indefinitely long tracing sessions (see b/274931668).
}
optional TriggerMode trigger_mode = 1;
+ // This flag is really a workaround for b/274931668. This is needed only
+ // when deploying configs to different versions of the tracing service.
+ // When this is set to true this has the same effect of setting trigger_mode
+ // to CLONE_SNAPSHOT on newer versions of the service. This boolean has been
+ // introduced to allow to have configs that use CLONE_SNAPSHOT on newer
+ // versions of Android and fall back to STOP_TRACING on older versions where
+ // CLONE_SNAPSHOT did not exist.
+ // When using this flag, trigger_mode must be set to STOP_TRACING.
+ optional bool use_clone_snapshot_if_available = 4;
+
message Trigger {
// The producer must specify this name to activate the trigger.
optional string name = 1;
@@ -2985,6 +3013,8 @@ message TraceConfig {
// After a trigger is received either in START_TRACING or STOP_TRACING
// mode then the trace will end |stop_delay_ms| after triggering.
+ // In CLONE_SNAPSHOT mode, this is the delay between the trigger and the
+ // snapshot.
// If |prefer_suspend_clock_for_duration| is set, the duration will be
// based on wall-clock, counting also time in suspend.
optional uint32 stop_delay_ms = 3;
@@ -3064,6 +3094,11 @@ message TraceConfig {
}
optional CompressionType compression_type = 24;
+ // Use the legacy codepath that compresses from perfetto_cmd.cc instead of
+ // using the new codepath that compresses from tracing_service_impl.cc. This
+ // will be removed in the future.
+ optional bool compress_from_cli = 37;
+
// Android-only. Not for general use. If set, saves the trace into an
// incident. This field is read by perfetto_cmd, rather than the tracing
// service. This field must be set when passing the --upload flag to
@@ -6776,6 +6811,16 @@ message MaliMaliKCPUFENCEWAITENDFtraceEvent {
optional uint32 kctx_id = 4;
optional uint32 id = 5;
}
+message MaliMaliCSFINTERRUPTSTARTFtraceEvent {
+ optional int32 kctx_tgid = 1;
+ optional uint32 kctx_id = 2;
+ optional uint64 info_val = 3;
+}
+message MaliMaliCSFINTERRUPTENDFtraceEvent {
+ optional int32 kctx_tgid = 1;
+ optional uint32 kctx_id = 2;
+ optional uint64 info_val = 3;
+}
// End of protos/perfetto/trace/ftrace/mali.proto
@@ -8279,6 +8324,8 @@ message FtraceEvent {
HostSmcFtraceEvent host_smc = 479;
HostMemAbortFtraceEvent host_mem_abort = 480;
SuspendResumeMinimalFtraceEvent suspend_resume_minimal = 481;
+ MaliMaliCSFINTERRUPTSTARTFtraceEvent mali_mali_CSF_INTERRUPT_START = 482;
+ MaliMaliCSFINTERRUPTENDFtraceEvent mali_mali_CSF_INTERRUPT_END = 483;
}
}
@@ -11204,6 +11251,13 @@ message ProcessStats {
optional uint32 chrome_peak_resident_set_kb = 14;
repeated FDInfo fds = 15;
+
+ // These fields are set only when scan_smaps_rollup=true
+ optional uint64 smr_rss_kb = 16;
+ optional uint64 smr_pss_kb = 17;
+ optional uint64 smr_pss_anon_kb = 18;
+ optional uint64 smr_pss_file_kb = 19;
+ optional uint64 smr_pss_shmem_kb = 20;
}
repeated Process processes = 1;
@@ -11290,7 +11344,7 @@ message ProcessTree {
// Deliberate empty message. See comment on StatsdAtom#atom below.
message Atom {}
-// One or more statsd atoms. Ideally this should continue to match:
+// One or more statsd atoms. This must continue to match:
// perfetto/protos/third_party/statsd/shell_data.proto
// So that we can efficiently add data from statsd directly to the
// trace.
diff --git a/protos/perfetto/trace/ps/process_stats.proto b/protos/perfetto/trace/ps/process_stats.proto
index 4ac0c40e6..03759b441 100644
--- a/protos/perfetto/trace/ps/process_stats.proto
+++ b/protos/perfetto/trace/ps/process_stats.proto
@@ -76,6 +76,13 @@ message ProcessStats {
optional uint32 chrome_peak_resident_set_kb = 14;
repeated FDInfo fds = 15;
+
+ // These fields are set only when scan_smaps_rollup=true
+ optional uint64 smr_rss_kb = 16;
+ optional uint64 smr_pss_kb = 17;
+ optional uint64 smr_pss_anon_kb = 18;
+ optional uint64 smr_pss_file_kb = 19;
+ optional uint64 smr_pss_shmem_kb = 20;
}
repeated Process processes = 1;
diff --git a/protos/perfetto/trace/statsd/statsd_atom.proto b/protos/perfetto/trace/statsd/statsd_atom.proto
index 026766db7..62ca960cd 100644
--- a/protos/perfetto/trace/statsd/statsd_atom.proto
+++ b/protos/perfetto/trace/statsd/statsd_atom.proto
@@ -20,7 +20,7 @@ package perfetto.protos;
// Deliberate empty message. See comment on StatsdAtom#atom below.
message Atom {}
-// One or more statsd atoms. Ideally this should continue to match:
+// One or more statsd atoms. This must continue to match:
// perfetto/protos/third_party/statsd/shell_data.proto
// So that we can efficiently add data from statsd directly to the
// trace.
diff --git a/protos/perfetto/trace_processor/BUILD.gn b/protos/perfetto/trace_processor/BUILD.gn
index 5e2f37632..2f6cb71c7 100644
--- a/protos/perfetto/trace_processor/BUILD.gn
+++ b/protos/perfetto/trace_processor/BUILD.gn
@@ -41,10 +41,3 @@ perfetto_proto_library("metrics_impl_@TYPE@") {
]
sources = [ "metrics_impl.proto" ]
}
-
-if (enable_perfetto_grpc) {
- perfetto_grpc_library("cloud_trace_processor_grpc") {
- deps = [ ":lite" ]
- sources = [ "cloud_trace_processor.proto" ]
- }
-}
diff --git a/protos/perfetto/trace_processor/proto_files.gni b/protos/perfetto/trace_processor/proto_files.gni
index 5f202b254..f211050d8 100644
--- a/protos/perfetto/trace_processor/proto_files.gni
+++ b/protos/perfetto/trace_processor/proto_files.gni
@@ -15,8 +15,7 @@
# This variable is used both by ./BUILD.gn (for the C++ proto codegen) and by
# //ui/BUIlD.gn (for the TypeScript/JS proto codegen).
trace_processor_protos = [
- "cloud_trace_processor",
- "trace_processor",
"metatrace_categories",
"stack",
+ "trace_processor",
]
diff --git a/protos/third_party/CHROMIUM_OWNERS b/protos/third_party/CHROMIUM_OWNERS
index 7cc656e22..826302dc8 100644
--- a/protos/third_party/CHROMIUM_OWNERS
+++ b/protos/third_party/CHROMIUM_OWNERS
@@ -14,3 +14,7 @@ mohitms@google.com
nuskos@google.com
oksamyt@google.com
kartarsingh@google.com
+jkoshy@google.com
+amanvr@google.com
+rasikan@google.com
+violettfaid@google.com
diff --git a/protos/third_party/chromium/chrome_track_event.proto b/protos/third_party/chromium/chrome_track_event.proto
index f19c1cf9a..cce5e7693 100644
--- a/protos/third_party/chromium/chrome_track_event.proto
+++ b/protos/third_party/chromium/chrome_track_event.proto
@@ -512,6 +512,12 @@ message BrowsingContextState {
// The ID of the BrowsingInstance that the BrowsingContextState belongs to.
optional int32 browsing_instance_id = 1;
+ // The ID of the CoopRelatedGroup that the BrowsingContextState belongs to.
+ optional int32 coop_related_group_id = 2 [deprecated = true];
+
+ // The token of the CoopRelatedGroup that the BrowsingContextState belongs to.
+ optional string coop_related_group_token = 3;
+
// Additional untyped debug information associated with this
// FrameTreeNode, populated via TracedProto::AddDebugAnnotations API.
repeated DebugAnnotation debug_annotations = 99;
@@ -734,6 +740,7 @@ message RendererMainThreadTaskExecution {
TASK_TYPE_INTERNAL_NAVIGATION_CANCELLATION = 80;
TASK_TYPE_LOW_PRIORITY_SCRIPT_EXECUTION = 81;
TASK_TYPE_STORAGE = 82;
+ TASK_TYPE_NETWORKING_UNFREEZABLE_IMAGE_LOADING = 83;
}
enum FrameType {
@@ -863,6 +870,7 @@ message SequenceManagerTask {
HIGH_PRIORITY_CONTINUATION = 8;
NORMAL_PRIORITY_CONTINUATION = 9;
LOW_PRIORITY_CONTINUATION = 10;
+ EXTREMELY_HIGH_PRIORITY = 11;
}
enum QueueName {
@@ -1031,11 +1039,25 @@ message BlinkExecutionContext {
SERVICE_WORKER = 5;
}
+ // Definition of world type.
+ enum WorldType {
+ WORLD_UNKNOWN = 0;
+ WORLD_MAIN = 1;
+ WORLD_ISOLATED = 2;
+ WORLD_INSPECTOR_ISOLATED = 3;
+ WORLD_REG_EXP = 4;
+ WORLD_FOR_V8_CONTEXT_SNAPSHOT_NON_MAIN = 5;
+ WORLD_WORKER = 6;
+ WORLD_SHADOW_REALM = 7;
+ }
+
optional ContextType type = 1;
// Contains url of frame or worker.
optional string url = 2;
// The origin of the execution context.
optional string origin = 3;
+ // The world type of the execution context.
+ optional WorldType world_type = 4;
}
// Serializes the blink::SourceLocation object.
@@ -1079,10 +1101,28 @@ message BlinkHighEntropyAPI {
// similar to "Navigator.languages.get".
optional string identifier = 1;
repeated JSFunctionArgument func_arguments = 2;
+
+ // Deprecated in favour of outer source_location.
optional BlinkSourceLocation source_location = 3;
}
optional BlinkExecutionContext execution_context = 1;
optional CalledJsApi called_api = 2;
+ optional BlinkSourceLocation source_location = 3;
+
+ // Describes lookup of a font.
+ message FontLookup {
+ enum FontLookupType {
+ FONT_LOOKUP_UNKNOWN_TYPE = 0;
+ FONT_LOOKUP_UNIQUE_OR_FAMILY_NAME = 1;
+ FONT_LOOKUP_UNIQUE_NAME_ONLY = 2;
+ }
+ optional FontLookupType type = 1;
+ optional string name = 2;
+ optional uint64 weight = 3;
+ optional uint64 width = 4;
+ optional uint64 slope = 5;
+ }
+ optional FontLookup font_lookup = 4;
}
// Contains information about a tab switch measurement.
diff --git a/protos/third_party/statsd/shell_data.proto b/protos/third_party/statsd/shell_data.proto
index e4c31bdd0..64551ea63 100644
--- a/protos/third_party/statsd/shell_data.proto
+++ b/protos/third_party/statsd/shell_data.proto
@@ -20,8 +20,8 @@ package perfetto.proto;
// This is a manual import of ShellData:
// https://cs.android.com/android/platform/superproject/+/master:packages/modules/StatsD/statsd/src/shell/shell_data.proto;l=27;drc=d2e51ecdf08753688fb889b657dcba60adb994f3
-
+// This must exactly match perfetto.protos.StatsdAtom.
message ShellData {
repeated bytes atom = 1;
- repeated int64 timestamp_nanos = 2 [packed = true];
+ repeated int64 timestamp_nanos = 2;
}
diff --git a/python/generators/stdlib_docs/parse.py b/python/generators/stdlib_docs/parse.py
index 79f4cfea6..bdef71773 100644
--- a/python/generators/stdlib_docs/parse.py
+++ b/python/generators/stdlib_docs/parse.py
@@ -42,6 +42,8 @@ def parse_columns(docs: Union['stdlib.TableViewDocs', 'stdlib.ViewFunctionDocs']
m = re.match(Pattern['column'], line)
if last_col:
cols[last_col] = ' '.join(last_desc)
+ if not m:
+ print(f'Expected line {line} to match @column format', file=sys.stderr)
last_col, last_desc = m.group(1), [m.group(2)]
cols[last_col] = ' '.join(last_desc)
@@ -79,6 +81,8 @@ def parse_ret(docs: "stdlib.FunctionDocs") -> Tuple[str, str]:
desc.append(get_text(line))
m = re.match(Pattern['return_arg'], line)
+ if not m:
+ print(f'Expected line {line} to match @ret format', file=sys.stderr)
ret_type, desc = m.group(1), [m.group(2)]
return (ret_type, ' '.join(desc))
diff --git a/python/generators/trace_processor_table/public.py b/python/generators/trace_processor_table/public.py
index abd0aec09..c8bdb0be5 100644
--- a/python/generators/trace_processor_table/public.py
+++ b/python/generators/trace_processor_table/public.py
@@ -119,6 +119,8 @@ class Table:
Representation of of a C++ table.
Attributes:
+ python_module: Path to the Python module this table is defined in. Always
+ pass __file__.
class_name: Name of the C++ table class.
sql_name: Name of the table in SQL.
columns: The columns in this table.
@@ -129,6 +131,7 @@ class Table:
specified table.
wrapping_sql_view: See |WrappingSqlView|.
"""
+ python_module: str
class_name: str
sql_name: str
columns: List[Column]
diff --git a/python/generators/trace_processor_table/serialize.py b/python/generators/trace_processor_table/serialize.py
index 0a8715cb9..1b498c3a2 100644
--- a/python/generators/trace_processor_table/serialize.py
+++ b/python/generators/trace_processor_table/serialize.py
@@ -19,6 +19,8 @@ from python.generators.trace_processor_table.public import Alias
from python.generators.trace_processor_table.public import ColumnFlag
from python.generators.trace_processor_table.util import ParsedTable
from python.generators.trace_processor_table.util import ParsedColumn
+from python.generators.trace_processor_table.util import parse_type
+from python.generators.trace_processor_table.util import typed_column_type
class ColumnSerializer:
@@ -30,8 +32,9 @@ class ColumnSerializer:
self.col = self.parsed_col.column
self.name = self.col.name
self.flags = self.col.flags
- self.typed_column_type = table.typed_column_type(self.parsed_col)
- self.cpp_type = table.parse_type(self.col.type).cpp_type_with_optionality()
+ self.typed_column_type = typed_column_type(table.table, self.parsed_col)
+ self.cpp_type = parse_type(table.table,
+ self.col.type).cpp_type_with_optionality()
self.is_implicit_id = self.parsed_col.is_implicit_id
self.is_implicit_type = self.parsed_col.is_implicit_type
@@ -114,7 +117,7 @@ class ColumnSerializer:
return f'''
columns_.emplace_back("{self.name}", &{self.name}_, ColumnFlag::{self.name},
this, static_cast<uint32_t>(columns_.size()),
- overlay_idx);
+ olay_idx);
'''
def shrink_to_fit(self) -> Optional[str]:
@@ -180,11 +183,11 @@ class ColumnSerializer:
if self.is_implicit_id or self.is_implicit_type:
return None
return f'''
- schema.columns.emplace_back(Table::Schema::Column{{
- "{self.name}", ColumnType::{self.name}::SqlValueType(), false,
- {str(ColumnFlag.SORTED in self.flags).lower()},
- {str(ColumnFlag.HIDDEN in self.flags).lower()},
- {str(ColumnFlag.SET_ID in self.flags).lower()}}});
+ schema.columns.emplace_back(Table::Schema::Column{{
+ "{self.name}", ColumnType::{self.name}::SqlValueType(), false,
+ {str(ColumnFlag.SORTED in self.flags).lower()},
+ {str(ColumnFlag.HIDDEN in self.flags).lower()},
+ {str(ColumnFlag.SET_ID in self.flags).lower()}}});
'''
def row_eq(self) -> Optional[str]:
@@ -192,6 +195,42 @@ class ColumnSerializer:
return None
return f'ColumnType::{self.name}::Equals({self.name}, other.{self.name})'
+ def extend_parent_param(self) -> Optional[str]:
+ if self.is_implicit_id or self.is_implicit_type:
+ return None
+ if self.is_ancestor:
+ return None
+ return f'ColumnStorage<ColumnType::{self.name}::stored_type> {self.name}'
+
+ def extend_parent_param_arg(self) -> Optional[str]:
+ if self.is_implicit_id or self.is_implicit_type:
+ return None
+ if self.is_ancestor:
+ return None
+ return f'std::move({self.name})'
+
+ def static_assert_flags(self) -> Optional[str]:
+ if self.is_implicit_id or self.is_implicit_type:
+ return None
+ if self.is_ancestor:
+ return None
+ return f'''
+ static_assert(
+ Column::IsFlagsAndTypeValid<ColumnType::{self.name}::stored_type>(
+ ColumnFlag::{self.name}),
+ "Column type and flag combination is not valid");
+ '''
+
+ def extend_nullable_vector(self) -> Optional[str]:
+ if self.is_implicit_id or self.is_implicit_type:
+ return None
+ if self.is_ancestor:
+ return None
+ return f'''
+ PERFETTO_DCHECK({self.name}.size() == parent_overlay.size());
+ {self.name}_ = std::move({self.name});
+ '''
+
class TableSerializer(object):
"""Functions for seralizing a single Table into C++."""
@@ -243,12 +282,13 @@ class TableSerializer(object):
ColumnSerializer.parent_row_initializer, delimiter=', ')
row_init = self.foreach_col(
ColumnSerializer.row_initializer, delimiter=',\n ')
+ parent_separator = ',' if row_init else ''
row_eq = self.foreach_col(ColumnSerializer.row_eq, delimiter=' &&\n ')
return f'''
struct Row : public {self.parent_class_name}::Row {{
Row({param},
std::nullptr_t = nullptr)
- : {self.parent_class_name}::Row({parent_row_init}),
+ : {self.parent_class_name}::Row({parent_row_init}){parent_separator}
{row_init} {{
type_ = "{self.table.sql_name}";
}}
@@ -297,22 +337,28 @@ class TableSerializer(object):
'''
def constructor(self) -> str:
- col_init = self.foreach_col(
+ storage_init = self.foreach_col(
ColumnSerializer.storage_init, delimiter=',\n ')
if self.table.parent:
parent_param = f', {self.parent_class_name}* parent'
parent_arg = 'parent'
- parent_init = 'parent_(parent), '
+ parent_init = 'parent_(parent)' + (', ' if storage_init else '')
else:
parent_param = ''
parent_arg = 'nullptr'
parent_init = ''
+ col_init = self.foreach_col(ColumnSerializer.column_init)
+ if col_init:
+ olay = 'uint32_t olay_idx = static_cast<uint32_t>(overlays_.size()) - 1;'
+ else:
+ olay = ''
return f'''
explicit {self.table_name}(StringPool* pool{parent_param})
: macros_internal::MacroTable(pool, {parent_arg}),
- {parent_init}{col_init} {{
- uint32_t overlay_idx = static_cast<uint32_t>(overlays_.size()) - 1;
- {self.foreach_col(ColumnSerializer.column_init)}
+ {parent_init}{storage_init} {{
+ {self.foreach_col(ColumnSerializer.static_assert_flags)}
+ {olay}
+ {col_init}
}}
'''
@@ -383,6 +429,60 @@ class TableSerializer(object):
}};
'''
+ def extend(self) -> str:
+ if not self.table.parent:
+ return ''
+ params = self.foreach_col(
+ ColumnSerializer.extend_parent_param, delimiter='\n, ')
+ args = self.foreach_col(
+ ColumnSerializer.extend_parent_param_arg, delimiter=', ')
+ delim = ',' if params else ''
+ return f'''
+ static std::unique_ptr<Table> ExtendParent(
+ const {self.parent_class_name}& parent{delim}
+ {params}) {{
+ return std::unique_ptr<Table>(new {self.table_name}(
+ parent.string_pool(), parent, RowMap(0, parent.row_count()){delim}
+ {args}));
+ }}
+
+ static std::unique_ptr<Table> SelectAndExtendParent(
+ const {self.parent_class_name}& parent,
+ std::vector<{self.parent_class_name}::RowNumber> parent_overlay{delim}
+ {params}) {{
+ std::vector<uint32_t> prs_untyped(parent_overlay.size());
+ for (uint32_t i = 0; i < parent_overlay.size(); ++i) {{
+ prs_untyped[i] = parent_overlay[i].row_number();
+ }}
+ return std::unique_ptr<Table>(new {self.table_name}(
+ parent.string_pool(), parent, RowMap(std::move(prs_untyped)){delim}
+ {args}));
+ }}
+ '''
+
+ def extend_constructor(self) -> str:
+ if not self.table.parent:
+ return ''
+ params = self.foreach_col(
+ ColumnSerializer.extend_parent_param, delimiter='\n, ')
+ if params:
+ olay = 'uint32_t olay_idx = static_cast<uint32_t>(overlays_.size()) - 1;'
+ else:
+ olay = ''
+ return f'''
+ {self.table_name}(StringPool* pool,
+ const {self.parent_class_name}& parent,
+ const RowMap& parent_overlay{',' if params else ''}
+ {params})
+ : macros_internal::MacroTable(pool, parent, parent_overlay) {{
+ {self.foreach_col(ColumnSerializer.static_assert_flags)}
+ {self.foreach_col(ColumnSerializer.extend_nullable_vector)}
+
+ {olay}
+ {self.foreach_col(ColumnSerializer.column_init)}
+ }}
+ '''
+
def serialize(self) -> str:
return f'''
class {self.table_name} : public macros_internal::MacroTable {{
@@ -482,11 +582,14 @@ class {self.table_name} : public macros_internal::MacroTable {{
RowNumber(row_number)}};
}}
+ {self.extend().strip()}
+
{self.foreach_col(ColumnSerializer.accessor)}
{self.foreach_col(ColumnSerializer.mutable_accessor)}
private:
+ {self.extend_constructor().strip()}
{self.parent_field().strip()}
{self.foreach_col(ColumnSerializer.storage)}
}};
@@ -502,7 +605,7 @@ def serialize_header(ifdef_guard: str, tables: List[ParsedTable],
#ifndef {ifdef_guard}
#define {ifdef_guard}
-#include "src/trace_processor/tables/macros.h"
+#include "src/trace_processor/tables/macros_internal.h"
{include_paths_str}
diff --git a/python/generators/trace_processor_table/util.py b/python/generators/trace_processor_table/util.py
index 015f02c71..1f0dc0ce8 100644
--- a/python/generators/trace_processor_table/util.py
+++ b/python/generators/trace_processor_table/util.py
@@ -14,7 +14,8 @@
import dataclasses
from dataclasses import dataclass
-import runpy
+import importlib
+import sys
from typing import Dict
from typing import List
from typing import Set
@@ -92,71 +93,78 @@ class ParsedTable:
table: Table
columns: List[ParsedColumn]
- input_path: str
-
- def parse_type(self, col_type: CppColumnType) -> ParsedType:
- """Parses a CppColumnType into its constiuent parts."""
-
- if isinstance(col_type, CppInt64):
- return ParsedType('int64_t')
- if isinstance(col_type, CppInt32):
- return ParsedType('int32_t')
- if isinstance(col_type, CppUint32):
- return ParsedType('uint32_t')
- if isinstance(col_type, CppDouble):
- return ParsedType('double')
- if isinstance(col_type, CppString):
- return ParsedType('StringPool::Id')
-
- if isinstance(col_type, Alias):
- col = next(c for c in self.columns
- if c.column.name == col_type.underlying_column)
- return ParsedType(
- self.parse_type(col.column.type).cpp_type,
- is_alias=True,
- alias_underlying_name=col.column.name)
-
- if isinstance(col_type, CppTableId):
- return ParsedType(
- f'{col_type.table.class_name}::Id', id_table=col_type.table)
-
- if isinstance(col_type, CppSelfTableId):
- return ParsedType(
- f'{self.table.class_name}::Id', is_self_id=True, id_table=self.table)
-
- if isinstance(col_type, CppOptional):
- inner = self.parse_type(col_type.inner)
- assert not inner.is_optional, 'Nested optional not allowed'
- return dataclasses.replace(inner, is_optional=True)
-
- raise Exception(f'Unknown type {col_type}')
-
- def typed_column_type(self, col: ParsedColumn) -> str:
- """Returns the TypedColumn/IdColumn C++ type for a given column."""
-
- parsed = self.parse_type(col.column.type)
- if col.is_implicit_id:
- return f'IdColumn<{parsed.cpp_type}>'
- return f'TypedColumn<{parsed.cpp_type_with_optionality()}>'
-
- def find_table_deps(self) -> Set[str]:
- """Finds all the other table class names this table depends on.
-
- By "depends", we mean this table in C++ would need the dependency to be
- defined (or included) before this table is defined."""
-
- deps: Set[str] = set()
- if self.table.parent:
- deps.add(self.table.parent.class_name)
- for c in self.table.columns:
- # Aliases cannot have dependencies so simply ignore them: trying to parse
- # them before adding implicit columns can cause issues.
- if isinstance(c.type, Alias):
- continue
- id_table = self.parse_type(c.type).id_table
- if id_table:
- deps.add(id_table.class_name)
- return deps
+
+
+def parse_type_with_cols(table: Table, cols: List[Column],
+ col_type: CppColumnType) -> ParsedType:
+ """Parses a CppColumnType into its constiuent parts."""
+
+ if isinstance(col_type, CppInt64):
+ return ParsedType('int64_t')
+ if isinstance(col_type, CppInt32):
+ return ParsedType('int32_t')
+ if isinstance(col_type, CppUint32):
+ return ParsedType('uint32_t')
+ if isinstance(col_type, CppDouble):
+ return ParsedType('double')
+ if isinstance(col_type, CppString):
+ return ParsedType('StringPool::Id')
+
+ if isinstance(col_type, Alias):
+ col = next(c for c in cols if c.name == col_type.underlying_column)
+ return ParsedType(
+ parse_type(table, col.type).cpp_type,
+ is_alias=True,
+ alias_underlying_name=col.name)
+
+ if isinstance(col_type, CppTableId):
+ return ParsedType(
+ f'{col_type.table.class_name}::Id', id_table=col_type.table)
+
+ if isinstance(col_type, CppSelfTableId):
+ return ParsedType(
+ f'{table.class_name}::Id', is_self_id=True, id_table=table)
+
+ if isinstance(col_type, CppOptional):
+ inner = parse_type(table, col_type.inner)
+ assert not inner.is_optional, 'Nested optional not allowed'
+ return dataclasses.replace(inner, is_optional=True)
+
+ raise Exception(f'Unknown type {col_type}')
+
+
+def parse_type(table: Table, col_type: CppColumnType) -> ParsedType:
+ """Parses a CppColumnType into its constiuent parts."""
+ return parse_type_with_cols(table, table.columns, col_type)
+
+
+def typed_column_type(table: Table, col: ParsedColumn) -> str:
+ """Returns the TypedColumn/IdColumn C++ type for a given column."""
+
+ parsed = parse_type(table, col.column.type)
+ if col.is_implicit_id:
+ return f'IdColumn<{parsed.cpp_type}>'
+ return f'TypedColumn<{parsed.cpp_type_with_optionality()}>'
+
+
+def find_table_deps(table: Table) -> List[Table]:
+ """Finds all the other table class names this table depends on.
+
+ By "depends", we mean this table in C++ would need the dependency to be
+ defined (or included) before this table is defined."""
+
+ deps: Dict[str, Table] = {}
+ if table.parent:
+ deps[table.parent.class_name] = table.parent
+ for c in table.columns:
+ # Aliases cannot have dependencies so simply ignore them: trying to parse
+ # them before adding implicit columns can cause issues.
+ if isinstance(c.type, Alias):
+ continue
+ id_table = parse_type(table, c.type).id_table
+ if id_table:
+ deps[id_table.class_name] = id_table
+ return list(deps.values())
def public_sql_name(table: Table) -> str:
@@ -165,10 +173,9 @@ def public_sql_name(table: Table) -> str:
wrapping_view = table.wrapping_sql_view
return wrapping_view.view_name if wrapping_view else table.sql_name
-def _create_implicit_columns_for_root(parsed: ParsedTable
- ) -> List[ParsedColumn]:
+
+def _create_implicit_columns_for_root(table: Table) -> List[ParsedColumn]:
"""Given a root table, returns the implicit id and type columns."""
- table = parsed.table
assert table.parent is None
sql_name = public_sql_name(table)
@@ -191,26 +198,25 @@ def _create_implicit_columns_for_root(parsed: ParsedTable
]
-def _topological_sort_tables(parsed: List[ParsedTable]) -> List[ParsedTable]:
+def _topological_sort_table_and_deps(parsed: List[Table]) -> List[Table]:
"""Topologically sorts a list of tables (i.e. dependenices appear earlier).
See [1] for information on a topological sort. We do this to allow
dependencies to be processed and appear ealier than their dependents.
[1] https://en.wikipedia.org/wiki/Topological_sorting"""
- table_to_parsed_table = {p.table.class_name: p for p in parsed}
visited: Set[str] = set()
- result: List[ParsedTable] = []
+ result: List[Table] = []
# Topological sorting is really just a DFS where we put the nodes in the list
# after any dependencies.
- def dfs(t: ParsedTable):
- if t.table.class_name in visited:
+ def dfs(t: Table):
+ if t.class_name in visited:
return
- visited.add(t.table.class_name)
+ visited.add(t.class_name)
- for dep in t.find_table_deps():
- dfs(table_to_parsed_table[dep])
+ for dep in find_table_deps(t):
+ dfs(dep)
result.append(t)
for p in parsed:
@@ -226,26 +232,27 @@ def _to_column_doc(doc: Union[ColumnDoc, str, None]) -> Optional[ColumnDoc]:
return ColumnDoc(doc=doc)
-def parse_tables_from_files(input_paths: List[str]) -> List[ParsedTable]:
+def parse_tables_from_modules(modules: List[str]) -> List[ParsedTable]:
"""Creates a list of tables with the associated paths."""
# Create a mapping from the table to a "parsed" version of the table.
+ tables: Dict[str, Table] = {}
+ for module in modules:
+ imported = importlib.import_module(module)
+ run_tables: List[Table] = imported.__dict__['ALL_TABLES']
+ for table in run_tables:
+ existing_table = tables.get(table.class_name)
+ assert not existing_table or existing_table == table
+ tables[table.class_name] = table
+
+ # Sort all the tables: note that this list may include tables which are not
+ # in |tables| dictionary due to dependencies on tables which live in a file
+ # not covered by |input_paths|.
+ sorted_tables = _topological_sort_table_and_deps(list(tables.values()))
+
parsed_tables: Dict[str, ParsedTable] = {}
- for in_path in input_paths:
- tables: List[Table] = runpy.run_path(in_path)['ALL_TABLES']
- for table in tables:
- existing_table = parsed_tables.get(table.class_name)
- assert not existing_table or existing_table.table == table
- parsed_tables[table.class_name] = ParsedTable(table, [], in_path)
-
- # Sort all the tables to be in order.
- sorted_tables = _topological_sort_tables(list(parsed_tables.values()))
-
- # Create the list of parsed columns
- for i, parsed in enumerate(sorted_tables):
+ for table in sorted_tables:
parsed_columns: List[ParsedColumn]
- table = parsed.table
-
if table.parent:
parsed_parent = parsed_tables[table.parent.class_name]
parsed_columns = [
@@ -253,13 +260,17 @@ def parse_tables_from_files(input_paths: List[str]) -> List[ParsedTable]:
for c in parsed_parent.columns
]
else:
- parsed_columns = _create_implicit_columns_for_root(parsed)
+ parsed_columns = _create_implicit_columns_for_root(table)
for c in table.columns:
doc = table.tabledoc.columns.get(c.name) if table.tabledoc else None
parsed_columns.append(ParsedColumn(c, _to_column_doc(doc)))
+ parsed_tables[table.class_name] = ParsedTable(table, parsed_columns)
- sorted_tables[i] = dataclasses.replace(parsed, columns=parsed_columns)
- parsed_tables[parsed.table.class_name] = sorted_tables[i]
-
- return sorted_tables
+ # Only return tables which come directly from |input_paths|. This stops us
+ # generating tables which were not requested.
+ return [
+ parsed_tables[p.class_name]
+ for p in sorted_tables
+ if p.class_name in tables
+ ]
diff --git a/python/perfetto/prebuilts/manifests/trace_processor_shell.py b/python/perfetto/prebuilts/manifests/trace_processor_shell.py
index 85fb30efd..2e9e82606 100755
--- a/python/perfetto/prebuilts/manifests/trace_processor_shell.py
+++ b/python/perfetto/prebuilts/manifests/trace_processor_shell.py
@@ -1,15 +1,15 @@
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACE_PROCESSOR_SHELL_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'trace_processor_shell',
'file_size':
- 8583152,
+ 8714576,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/trace_processor_shell',
'sha256':
- '35673d3546dec894b5d55147da2fad523a8f5917b42ec1c327c940b82d3ce565',
+ '9bdb89493f0f00db5d3a73166450ac2f6ee830de16415e79c5a0234990caa644',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 7303384,
+ 7286968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/trace_processor_shell',
'sha256':
- 'a4d301cf8c0c01d328a9253d5ba78f4249333d4b04236cf8be0c7dad2a65e7e0',
+ '948536035fbe680b47b94a99d320ff459450738e4aeeb16cef18364f0023622b',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 8991600,
+ 8576688,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/trace_processor_shell',
'sha256':
- 'e8dd82c1ec73fbbf4165ab0d9cbbb750cff5bcf723a1eab51adc9382bf652361',
+ '493698c81fffcabc340c72831b175962dba5a31dfe8572a6d5af083a116af4f8',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 7117104,
+ 6125384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/trace_processor_shell',
'sha256':
- 'bbfde44ec004815a36cecdc1dbc135f815f46ac6a3989c87cb0c577510c1c8fe',
+ '53f1e27603695cf92d22519993b6eafa9c60957d9cb33bd0b300df8573b87ebb',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 8384816,
+ 8036288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/trace_processor_shell',
'sha256':
- 'c4f9a499e8c443961725448aabc04cd7dc18cb79883f6b8b615fd8f4ed7c8c16',
+ '2a2cda222c9d5e18b638057688babb00a3a975ccd4b7dd65f26211c2cb7767f9',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,55 +75,55 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 5823560,
+ 5813384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/trace_processor_shell',
'sha256':
- 'ec5d23fc761021fe10a7cdb66d35590dab0216b2305f5163ace98da28b535fb8'
+ 'f3ec4c194d0b06af5b296c1c479e6b29090e6b7cc7e58fbd55ca2919a126f0ee'
}, {
'arch':
'android-arm64',
'file_name':
'trace_processor_shell',
'file_size':
- 7474864,
+ 7294768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/trace_processor_shell',
'sha256':
- 'f4877f51d0fbb8e9ead576e746a7adf7806b5cb2dffc4373a55ceeec21f615ff'
+ 'f44f47d4b873ec68b6fa4f4c69a3e5a13d58b4d9cb2ec591fa687d4480c1950b'
}, {
'arch':
'android-x86',
'file_name':
'trace_processor_shell',
'file_size':
- 8436764,
+ 8090716,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/trace_processor_shell',
'sha256':
- '68ad60af32890f903afb7cbee7cc8f0f4f4b18dea7ab077cb1d807ea80053dcb'
+ '5636d8251747376787640bc3a4894ecf3091e4bf3d38b007003e1992fc5792df'
}, {
'arch':
'android-x64',
'file_name':
'trace_processor_shell',
'file_size':
- 8781544,
+ 8359784,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/trace_processor_shell',
'sha256':
- 'edf5efca4cf46ffbd3586592490b14d61758198c7d46c1bc8e083b1ab19382f5'
+ '50440fa055ab998f6cf24f9a9a7388520cc854708735521505e10291bc52f3d0'
}, {
'arch':
'windows-amd64',
'file_name':
'trace_processor_shell.exe',
'file_size':
- 8252928,
+ 8130560,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/windows-amd64/trace_processor_shell.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/windows-amd64/trace_processor_shell.exe',
'sha256':
- '323a210f857ce840c4d69dfa7f9b0a32501ffa4a856e5667a0916e3f8006a5d0',
+ '5cbcf98e29a2d989523235e11e4e0dade692a295ebf47a6c93a09a050ce9bc91',
'platform':
'win32',
'machine': ['amd64']
diff --git a/python/perfetto/prebuilts/manifests/tracebox.py b/python/perfetto/prebuilts/manifests/tracebox.py
index effd4d1e6..46b064a6d 100755
--- a/python/perfetto/prebuilts/manifests/tracebox.py
+++ b/python/perfetto/prebuilts/manifests/tracebox.py
@@ -1,15 +1,15 @@
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1415776,
+ 1432064,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/tracebox',
'sha256':
- '860cccef002f1a7216d301a09b97d7276b8a57c8d85ad1c3aa4697bb115ffca7',
+ '4ceb7646cd99303224ab5e7ff0a9f84c04f3c5466fff65a55dab65171ae9d482',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1309272,
+ 1325704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/tracebox',
'sha256':
- '9c079ac561064c33e9bdfe2e23e92fb95c025603e545c1aae31b2bd7de0398ad',
+ '2c560fcce5e19eb692e50487af134e2078347cdb79decba0c572917860528388',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 2137040,
+ 2155496,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/tracebox',
'sha256':
- '9eb9ce1a14432c284fecce7886786bb2555bcb6dfb4f00a2df2885984961a5fc',
+ '10b92180bb461a7e21be3f8b3d4640430a98d0547238ce095709213b378217d2',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1277896,
+ 1288764,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/tracebox',
'sha256':
- '60c71b39be7e04d9d0278e36e7e4d33c32a03d6cc8a3782a9e5ed2484f3f2082',
+ 'fa28950ce2b7a9345fbb9272f2dd04d3d4eb2a87f021df25e1e649840eae60b5',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 2065704,
+ 2082704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/tracebox',
'sha256':
- 'a8d9e9e186b5daf45ec80b975b9a3ad04cb578890beda136b821c80b9cc74995',
+ '85c371d79b8e23d22a293c29e6399dc311d891a6bd85d7eeaf2cb0179c69eb27',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,42 +75,42 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1161172,
+ 1169364,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/tracebox',
'sha256':
- 'f9dac5df26d471d1cf0aff942d7249da6b4122543e003813203ef128a15f93fd'
+ '40a3f31600f02dea10e290134d5c862e0e717f4f039756889a4e72c60f1591b6'
}, {
'arch':
'android-arm64',
'file_name':
'tracebox',
'file_size':
- 1764008,
+ 1776296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/tracebox',
'sha256':
- '3b325a09b6efae0939b73d4d74e6e01e3735508ed31b774f3a21765efab95099'
+ '562505fca18b34a97687dc002aeebcbf20acef68c8a8e48bed6d618c20e07c92'
}, {
'arch':
'android-x86',
'file_name':
'tracebox',
'file_size':
- 1755052,
+ 1767340,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/tracebox',
'sha256':
- '86e31fa7e2b476187a0222ac2cf6a4ee7e5f8fb5b0e019c1349d14534343a581'
+ 'eb47eb43ba93403557dd15a61196799e945ec324d96109db2f155fb131f9996a'
}, {
'arch':
'android-x64',
'file_name':
'tracebox',
'file_size':
- 2034344,
+ 2054824,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/tracebox',
'sha256':
- '7692f6ceaa5d2eb9da42486262610a1820a9b31d46255f624407bf712eff021d'
+ 'a3ae6d108e041ba368a9770f952772f111865d4eff7c8e4e4e2f653f45017948'
}]
diff --git a/python/perfetto/prebuilts/manifests/traceconv.py b/python/perfetto/prebuilts/manifests/traceconv.py
index fad02d9c0..b093ac6cf 100755
--- a/python/perfetto/prebuilts/manifests/traceconv.py
+++ b/python/perfetto/prebuilts/manifests/traceconv.py
@@ -1,15 +1,15 @@
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7822272,
+ 7904536,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/traceconv',
'sha256':
- '2b1bae4755ee0dd7f3a8e55653f8a7c344f688ea29700064ef8211c55bb4ae9f',
+ '037f84ac943f3f4d75447c668cc49c966fe3d85eca3a455c958b24fc6a9e314a',
'platform':
'darwin',
'machine': ['x86_64']
@@ -19,11 +19,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6604056,
+ 6554600,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/traceconv',
'sha256':
- 'c0bd6d1ebe2c61ffeefbd4f01426e9b853c81daf70530be7e78c97a4d3af100c',
+ 'eda545ef4fa37fdfa1b47ced7cbbe0aa3c0df9bd161cacd7c78e6c55aef98d20',
'platform':
'darwin',
'machine': ['arm64']
@@ -33,11 +33,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 8122112,
+ 7664384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/traceconv',
'sha256':
- 'c4c57d8e7b435822a1437b2dc7f7154f6ff2e197deff1f9284bbd36bbedb004f',
+ '24285e6e0e873d393fa5a993bac18ec8e1ab5fae6f4e3453214e095ef36e4c45',
'platform':
'linux',
'machine': ['x86_64']
@@ -47,11 +47,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6692016,
+ 5657944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/traceconv',
'sha256':
- 'da666eb9f80bcbec4c959f4adf493a59ff89e4106666fe1884291078dba0243b',
+ 'c9af3d976f849fc75e96c2c552cb14fcc9eacce6fe7c45c4a8289080b0f66706',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -61,11 +61,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 7575344,
+ 7184224,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/traceconv',
'sha256':
- '8ca00c39c5ec7bd78576f64c4ab05e663d803b06b36fbddf968825edbe236fca',
+ 'c6dc936492d58a40cd8e0b58abc46bd479e0c1c387cd1ba29198a6c9b2000d7a',
'platform':
'linux',
'machine': ['aarch64']
@@ -75,55 +75,55 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 5376396,
+ 5325260,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/traceconv',
'sha256':
- 'b77e7f0274ba45ff32d34df347845bc996763291fcc6b2a697f56c0c9a543150'
+ '963267dcb58cdde9f61a952e5cb7f3557833209d3251e7fdcefc3b52db54f77b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 6793744,
+ 6572688,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/traceconv',
'sha256':
- 'e83f3d43f8782cb57e9d3e8a3cd31826c9713da9f92bd8d8be2c48872ed423eb'
+ '87373c351fe5e947826cd957438cab8a37a352bf83b1cbbb15fe276eee9d873a'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 7694692,
+ 7303588,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/traceconv',
'sha256':
- 'c9ee2c3c91d6c68cb7f52a626767bde5e267f34c6ddf987ff73eec3d813c0a2c'
+ 'dfc4e714963b5ed662d29d6028ffa69e67f8cd2f9a28223f715437a260fd456f'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7940680,
+ 7482056,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/traceconv',
'sha256':
- 'f75122ca3e6bbe393b705c3bc5514d81c57f38bf408d857d89c4268b79a39e08'
+ '79c666c629fcffd810635270b45e58b40ed253d22650f41550057e5d8f8c49a7'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7239168,
+ 7072768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/windows-amd64/traceconv.exe',
'sha256':
- '5be5d698f69d44b4baa8ae1f21955becad9d0e6774e967f923b8386744002cfe',
+ '40fac80fdeae443a924e160650c94629e6463c1fb5a4f04f4ef6e9e5e72a3965',
'platform':
'win32',
'machine': ['amd64']
diff --git a/python/perfetto/trace_processor/metrics.descriptor b/python/perfetto/trace_processor/metrics.descriptor
index 9aa5fe554..536dff949 100644
--- a/python/perfetto/trace_processor/metrics.descriptor
+++ b/python/perfetto/trace_processor/metrics.descriptor
@@ -1,11 +1,12 @@
-À
-6protos/perfetto/metrics/android/process_metadata.protoperfetto.protos"ô
+Ò
+6protos/perfetto/metrics/android/process_metadata.protoperfetto.protos"†
AndroidProcessMetadata
name ( Rname
uid (RuidI
package ( 2/.perfetto.protos.AndroidProcessMetadata.PackageRpackageY
-packages_for_uid ( 2/.perfetto.protos.AndroidProcessMetadata.PackageRpackagesForUidv
+packages_for_uid ( 2/.perfetto.protos.AndroidProcessMetadata.PackageRpackagesForUid
+pid (Rpidv
Package!
package_name ( R packageName(
apk_version_code (RapkVersionCode
@@ -359,8 +360,8 @@ maxRuntime
totalCountc
threshold_metric ( 28.perfetto.protos.AndroidIrqRuntimeMetric.ThresholdMetricRthresholdMetric_
longest_irq_slices ( 21.perfetto.protos.AndroidIrqRuntimeMetric.IrqSliceRlongestIrqSlices
-5protos/perfetto/metrics/android/jank_cuj_metric.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"¿
+œ
+5protos/perfetto/metrics/android/jank_cuj_metric.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"™
AndroidJankCujMetric;
cuj ( 2).perfetto.protos.AndroidJankCujMetric.CujRcuj¾
Cuj
@@ -376,7 +377,7 @@ totalCountc
timeline_metrics ( 2-.perfetto.protos.AndroidJankCujMetric.MetricsRtimelineMetricsR
trace_metrics ( 2-.perfetto.protos.AndroidJankCujMetric.MetricsR traceMetrics
-layer_name ( R layerNameÁ
+layer_name ( R layerName¡
Frame!
frame_number (R frameNumber
vsync (Rvsync
@@ -385,7 +386,9 @@ layer_name ( R layerNameÁ
dur_expected (R durExpected
app_missed (R appMissed
- sf_missed (RsfMissedä
+ sf_missed (RsfMissed,
+sf_callback_missed (RsfCallbackMissed0
+hwui_callback_missed (RhwuiCallbackMissedÞ
Metrics!
total_frames (R totalFrames#
missed_frames (R missedFrames*
@@ -402,7 +405,9 @@ app_missed (R appMissed
frame_dur_ms_p50 (R frameDurMsP50'
frame_dur_ms_p90 (R frameDurMsP90'
frame_dur_ms_p95 (R frameDurMsP95'
-frame_dur_ms_p99 (R frameDurMsP99
+frame_dur_ms_p99 (R frameDurMsP999
+sf_callback_missed_frames (RsfCallbackMissedFrames=
+hwui_callback_missed_frames (RhwuiCallbackMissedFrames
À
9protos/perfetto/metrics/android/java_heap_histogram.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"¹
JavaHeapHistogramW
@@ -424,14 +429,14 @@ type_count ( 2,.perfetto.protos.JavaHeapHistogram.TypeCountR typeCount«
upid ( RupidA
process ( 2'.perfetto.protos.AndroidProcessMetadataRprocessC
samples ( 2).perfetto.protos.JavaHeapHistogram.SampleRsamples
-…
-5protos/perfetto/metrics/android/java_heap_stats.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"‚
+©
+5protos/perfetto/metrics/android/java_heap_stats.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"¦
JavaHeapStatsS
instance_stats ( 2,.perfetto.protos.JavaHeapStats.InstanceStatsR instanceStatsb
HeapRoots
root_type ( RrootType
type_name ( RtypeName
- obj_count (RobjCount
+ obj_count (RobjCount±
Sample
ts (Rts
heap_size (RheapSize(
@@ -441,7 +446,9 @@ type_count ( 2,.perfetto.protos.JavaHeapHistogram.TypeCountR typeCount«
reachable_heap_native_size (RreachableHeapNativeSize.
reachable_obj_count (RreachableObjCount2
anon_rss_and_swap_size (RanonRssAndSwapSize>
-roots ( 2(.perfetto.protos.JavaHeapStats.HeapRootsRroots§
+roots ( 2(.perfetto.protos.JavaHeapStats.HeapRootsRroots"
+ oom_score_adj
+ (R oomScoreAdj§
InstanceStats
upid ( RupidA
process ( 2'.perfetto.protos.AndroidProcessMetadataRprocess?
@@ -673,8 +680,8 @@ maxRuntime$
name ( RnameY
threads ( 2?.perfetto.protos.AndroidSimpleperfMetric.PerfEventMetric.ThreadRthreads
total (Rtotal
-è,
-4protos/perfetto/metrics/android/startup_metric.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"æ+
+Ô.
+4protos/perfetto/metrics/android/startup_metric.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"Ò-
AndroidStartupMetricG
startup ( 2-.perfetto.protos.AndroidStartupMetric.StartupRstartupó
TaskStateBreakdown$
@@ -691,7 +698,7 @@ maxRuntime$
unknown (Runknown5
Slice
dur_ns (RdurNs
-dur_ms (RdurMsÏ
+dur_ms (RdurMsš
ToFirstFrame
dur_ns (RdurNs
dur_ms (RdurMsr
@@ -722,7 +729,9 @@ toPostForkb
time_gc_total ( 2+.perfetto.protos.AndroidStartupMetric.SliceR timeGcTotalP
time_gc_on_cpu ( 2+.perfetto.protos.AndroidStartupMetric.SliceR timeGcOnCpus
time_lock_contention_thread_main ( 2+.perfetto.protos.AndroidStartupMetric.SliceRtimeLockContentionThreadMainy
-#time_monitor_contention_thread_main ( 2+.perfetto.protos.AndroidStartupMetric.SliceRtimeMonitorContentionThreadMainJ  J JJ\
+#time_monitor_contention_thread_main ( 2+.perfetto.protos.AndroidStartupMetric.SliceRtimeMonitorContentionThreadMaine
+time_dex_open_thread_main! ( 2+.perfetto.protos.AndroidStartupMetric.SliceRtimeDexOpenThreadMainb
+time_dlopen_thread_main" ( 2+.perfetto.protos.AndroidStartupMetric.SliceRtimeDlopenThreadMainJ  J JJ\
HscMetricsN
full_startup ( 2+.perfetto.protos.AndroidStartupMetric.SliceR fullStartupd
@@ -758,7 +767,8 @@ firstFrame÷
broadcast_received_count (RbroadcastReceivedCountF
most_active_non_launch_processes ( RmostActiveNonLaunchProcesses&
installd_dur_ns (R installdDurNs$
-dex2oat_dur_ns (R dex2oatDurNsï
+dex2oat_dur_ns (R dex2oatDurNs
+
Startup
startup_id ( R startupId!
@@ -777,13 +787,15 @@ activitiesq
hsc ( 20.perfetto.protos.AndroidStartupMetric.HscMetricsRhscY
report_fully_drawn ( 2+.perfetto.protos.AndroidStartupMetric.SliceRreportFullyDrawni
optimization_status ( 28.perfetto.protos.AndroidStartupMetric.OptimizationStatusRoptimizationStatusT
- verify_class ( 21.perfetto.protos.AndroidStartupMetric.VerifyClassR verifyClass?
+ verify_class ( 21.perfetto.protos.AndroidStartupMetric.VerifyClassR verifyClass
+ dlopen_file ( R
+dlopenFile?
startup_concurrent_to_launch ( RstartupConcurrentToLaunchT
system_state ( 21.perfetto.protos.AndroidStartupMetric.SystemStateR systemState*
slow_start_reason ( RslowStartReasonJ

-
-4protos/perfetto/metrics/android/surfaceflinger.protoperfetto.protos"Ó
+Ñ
+4protos/perfetto/metrics/android/surfaceflinger.protoperfetto.protos"‡
AndroidSurfaceflingerMetric#
missed_frames ( R missedFrames*
missed_hwc_frames ( RmissedHwcFrames*
@@ -793,7 +805,18 @@ activitiesq
missed_gpu_frame_rate (RmissedGpuFrameRate'
gpu_invocations ( RgpuInvocations2
avg_gpu_waiting_dur_ms (RavgGpuWaitingDurMsH
-"total_non_empty_gpu_waiting_dur_ms (RtotalNonEmptyGpuWaitingDurMs
+"total_non_empty_gpu_waiting_dur_ms (RtotalNonEmptyGpuWaitingDurMsn
+metrics_per_display
+ ( 2>.perfetto.protos.AndroidSurfaceflingerMetric.MetricsPerDisplayRmetricsPerDisplayÁ
+MetricsPerDisplay
+
+display_id ( R displayId#
+ missed_frames ( R missedFrames*
+missed_hwc_frames ( RmissedHwcFrames*
+missed_gpu_frames ( RmissedGpuFrames*
+missed_frame_rate (RmissedFrameRate1
+missed_hwc_frame_rate (RmissedHwcFrameRate1
+missed_gpu_frame_rate (RmissedGpuFrameRate
»
0protos/perfetto/metrics/android/task_names.protoperfetto.protos"õ
AndroidTaskNamesC
@@ -823,8 +846,8 @@ m
build_id ( RbuildId
address (Raddress(
google_lookup_id ( RgoogleLookupId
-3protos/perfetto/metrics/android/binder_metric.protoperfetto.protos"œ
+3protos/perfetto/metrics/android/binder_metric.protoperfetto.protos"Ú
AndroidBinderMetrice
process_breakdown ( 28.perfetto.protos.AndroidBinderMetric.PerProcessBreakdownRprocessBreakdown{
unaggregated_txn_breakdown ( 2=.perfetto.protos.AndroidBinderMetric.UnaggregatedTxnBreakdownRunaggregatedTxnBreakdown
@@ -833,7 +856,7 @@ m
pid ( Rpid
slice_name ( R sliceName
-count ( Rcountƒ
+count ( RcountÁ
UnaggregatedTxnBreakdown
aidl_name ( RaidlName%
client_process ( R clientProcess#
@@ -853,7 +876,11 @@ server_dur (R serverDur^
client_tid ( R clientTid
-server_tid ( R serverTidJJ ½
+server_tid ( R serverTid
+
+client_pid ( R clientPid
+
+server_pid ( R serverPidJJ ½
ThreadStateBreakdown*
thread_state_type ( RthreadStateType!
thread_state ( R threadState(
@@ -864,34 +891,36 @@ server_tid ( R serverTidJJ ½
blocked_function ( RblockedFunction0
blocked_function_dur (RblockedFunctionDur4
blocked_function_count (RblockedFunctionCount
-?protos/perfetto/metrics/android/monitor_contention_metric.protoperfetto.protos"Ú
-
+?protos/perfetto/metrics/android/monitor_contention_metric.protoperfetto.protos"Ê
AndroidMonitorContentionMetricH
-node ( 24.perfetto.protos.AndroidMonitorContentionMetric.NodeRnode©
+node ( 24.perfetto.protos.AndroidMonitorContentionMetric.NodeRnode™
Node$
node_parent_id (R nodeParentId
node_id (RnodeId
ts (Rts
-dur (Rdur'
-blocking_method ( RblockingMethod%
-blocked_method ( R blockedMethod2
-short_blocking_method ( RshortBlockingMethod0
-short_blocked_method ( RshortBlockedMethod!
- blocking_src ( R blockingSrc
+dur (Rdur!
+ process_name ( R processName
+pid ( Rpid!
+ waiter_count ( R waiterCounti
+ thread_states ( 2D.perfetto.protos.AndroidMonitorContentionMetric.ThreadStateBreakdownR threadStatesu
+blocked_functions ( 2H.perfetto.protos.AndroidMonitorContentionMetric.BlockedFunctionBreakdownRblockedFunctions'
+blocking_method ( RblockingMethod2
+short_blocking_method ( RshortBlockingMethod!
+ blocking_src ( R blockingSrc0
+blocking_thread_name ( RblockingThreadName5
+is_blocking_thread_main (RisBlockingThreadMain.
+blocking_thread_tid ( RblockingThreadTid%
+blocked_method ( R blockedMethod0
+short_blocked_method ( RshortBlockedMethod
blocked_src
( R
-blockedSrc!
- waiter_count ( R waiterCount.
-blocked_thread_name ( RblockedThreadName0
-blocking_thread_name ( RblockingThreadName!
- process_name ( R processName3
-is_blocked_thread_main (RisBlockedThreadMain5
-is_blocking_thread_main (RisBlockingThreadMain&
+blockedSrc.
+blocked_thread_name ( RblockedThreadName3
+is_blocked_thread_main (RisBlockedThreadMain,
+blocked_thread_tid ( RblockedThreadTid&
binder_reply_ts (R binderReplyTs(
-binder_reply_tid ( RbinderReplyTidi
- thread_states ( 2D.perfetto.protos.AndroidMonitorContentionMetric.ThreadStateBreakdownR threadStatesu
-blocked_functions ( 2H.perfetto.protos.AndroidMonitorContentionMetric.BlockedFunctionBreakdownRblockedFunctions‘
+binder_reply_tid ( RbinderReplyTid‘
ThreadStateBreakdown!
thread_state ( R threadState(
thread_state_dur (RthreadStateDur,
diff --git a/python/perfetto/trace_processor/metrics.descriptor.sha1 b/python/perfetto/trace_processor/metrics.descriptor.sha1
deleted file mode 100644
index 0a69bdf19..000000000
--- a/python/perfetto/trace_processor/metrics.descriptor.sha1
+++ /dev/null
@@ -1,6 +0,0 @@
-
-// SHA1(tools/gen_binary_descriptors)
-// 6886b319e65925c037179e71a803b8473d06dc7d
-// SHA1(protos/perfetto/metrics/metrics.proto)
-// b07fa0b4ad2deed79d2d8cc320f70502e19eee0c
- \ No newline at end of file
diff --git a/python/perfetto/trace_processor/trace_processor.descriptor.sha1 b/python/perfetto/trace_processor/trace_processor.descriptor.sha1
deleted file mode 100644
index 7f7827f2f..000000000
--- a/python/perfetto/trace_processor/trace_processor.descriptor.sha1
+++ /dev/null
@@ -1,6 +0,0 @@
-
-// SHA1(tools/gen_binary_descriptors)
-// 6886b319e65925c037179e71a803b8473d06dc7d
-// SHA1(protos/perfetto/trace_processor/trace_processor.proto)
-// 59f86a32aa28f29e290d8ce3f97461725aa8b9f8
- \ No newline at end of file
diff --git a/src/android_stats/perfetto_atoms.h b/src/android_stats/perfetto_atoms.h
index e9ef08e4f..122dfad75 100644
--- a/src/android_stats/perfetto_atoms.h
+++ b/src/android_stats/perfetto_atoms.h
@@ -47,6 +47,7 @@ enum class PerfettoStatsdAtom {
// they log the trigger name.
kTracedTriggerStartTracing = 41,
kTracedTriggerStopTracing = 42,
+ kTracedTriggerCloneSnapshot = 53,
// Guardrails inside traced.
kTracedEnableTracingExistingTraceSession = 18,
diff --git a/src/base/http/BUILD.gn b/src/base/http/BUILD.gn
index e0861347c..dda19a743 100644
--- a/src/base/http/BUILD.gn
+++ b/src/base/http/BUILD.gn
@@ -40,8 +40,11 @@ perfetto_unittest_source_set("unittests") {
"../../../gn:default_deps",
"../../../gn:gtest_and_gmock",
]
- sources = [
- "http_server_unittest.cc",
- "sha1_unittest.cc",
- ]
+ sources = [ "sha1_unittest.cc" ]
+
+ # The HTTP server unittests cannot be run in parallel. Chromium runs tests
+ # in parallel on some bots so exclude all of these ones.
+ if (!build_with_chromium) {
+ sources += [ "http_server_unittest.cc" ]
+ }
}
diff --git a/src/base/metatrace.cc b/src/base/metatrace.cc
index 1464ed384..51b8b8301 100644
--- a/src/base/metatrace.cc
+++ b/src/base/metatrace.cc
@@ -36,13 +36,6 @@ std::atomic<uint64_t> RingBuffer::rd_index_;
std::atomic<bool> RingBuffer::has_overruns_;
Record RingBuffer::bankruptcy_record_;
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-constexpr size_t RingBuffer::kCapacity;
-constexpr uint16_t Record::kTypeMask;
-constexpr uint16_t Record::kTypeCounter;
-constexpr uint16_t Record::kTypeEvent;
-#endif
-
namespace {
// std::function<> is not trivially de/constructible. This struct wraps it in a
diff --git a/src/cloud_trace_processor/BUILD.gn b/src/cloud_trace_processor/BUILD.gn
new file mode 100644
index 000000000..e9a4bfca5
--- /dev/null
+++ b/src/cloud_trace_processor/BUILD.gn
@@ -0,0 +1,64 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../gn/perfetto.gni")
+import("../../gn/test.gni")
+
+assert(
+ enable_perfetto_trace_processor && enable_perfetto_trace_processor_sqlite)
+
+# The "core" business logic of cloud trace processor which is agnostic to the
+# RPC transport. Allows wrapping with any RPC framework capable of handling
+# protobufs.
+static_library("cloud_trace_processor") {
+ complete_static_lib = true
+ deps = [ ":sources" ]
+ public_deps = [ "../../include/perfetto/ext/cloud_trace_processor" ]
+}
+
+source_set("sources") {
+ sources = [
+ "orchestrator_impl.cc",
+ "orchestrator_impl.h",
+ "trace_processor_wrapper.cc",
+ "trace_processor_wrapper.h",
+ "worker_impl.cc",
+ "worker_impl.h",
+ ]
+ deps = [
+ "../../gn:default_deps",
+ "../../include/perfetto/ext/cloud_trace_processor",
+ "../../protos/perfetto/cloud_trace_processor:lite",
+ "../base",
+ "../base/threading",
+ "../protozero",
+ "../protozero:proto_ring_buffer",
+ "../trace_processor:lib",
+ "../trace_processor/rpc",
+ "../trace_processor/util",
+ ]
+}
+
+perfetto_unittest_source_set("unittests") {
+ testonly = true
+ sources = [ "trace_processor_wrapper_unittest.cc" ]
+ deps = [
+ ":sources",
+ "../../gn:default_deps",
+ "../../gn:gtest_and_gmock",
+ "../../protos/perfetto/cloud_trace_processor:lite",
+ "../base",
+ "../base/threading",
+ ]
+}
diff --git a/src/cloud_trace_processor/orchestrator_impl.cc b/src/cloud_trace_processor/orchestrator_impl.cc
new file mode 100644
index 000000000..69b831fad
--- /dev/null
+++ b/src/cloud_trace_processor/orchestrator_impl.cc
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/cloud_trace_processor/orchestrator_impl.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/stream.h"
+#include "perfetto/ext/cloud_trace_processor/worker.h"
+#include "protos/perfetto/cloud_trace_processor/common.pb.h"
+#include "protos/perfetto/cloud_trace_processor/orchestrator.pb.h"
+#include "protos/perfetto/cloud_trace_processor/worker.pb.h"
+#include "src/trace_processor/util/status_macros.h"
+
+namespace perfetto {
+namespace cloud_trace_processor {
+namespace {
+
+base::Future<base::Status> CreateResponseToStatus(
+ base::StatusOr<protos::TracePoolShardCreateResponse> response_or) {
+ return response_or.status();
+}
+
+base::Future<base::Status> SetTracesResponseToStatus(
+ base::StatusOr<protos::TracePoolShardSetTracesResponse> response_or) {
+ return response_or.status();
+}
+
+base::Future<base::StatusOr<protos::TracePoolQueryResponse>>
+RpcResponseToPoolResponse(
+ base::StatusOr<protos::TracePoolShardQueryResponse> resp) {
+ RETURN_IF_ERROR(resp.status());
+ protos::TracePoolQueryResponse ret;
+ ret.set_trace(std::move(resp->trace()));
+ *ret.mutable_result() = std::move(*resp->mutable_result());
+ return ret;
+}
+
+base::StatusOrStream<protos::TracePoolShardSetTracesResponse>
+RoundRobinSetTraces(const std::vector<std::unique_ptr<Worker>>& workers,
+ const std::vector<std::string>& traces) {
+ uint32_t worker_idx = 0;
+ std::vector<protos::TracePoolShardSetTracesArgs> protos;
+ protos.resize(workers.size());
+ for (const auto& trace : traces) {
+ protos[worker_idx].add_traces(trace);
+ worker_idx = (worker_idx + 1) % workers.size();
+ }
+
+ using ShardResponse = protos::TracePoolShardSetTracesResponse;
+ std::vector<base::StatusOrStream<ShardResponse>> streams;
+ for (uint32_t i = 0; i < protos.size(); ++i) {
+ streams.emplace_back(workers[i]->TracePoolShardSetTraces(protos[i]));
+ }
+ return base::FlattenStreams(std::move(streams));
+}
+} // namespace
+
+Orchestrator::~Orchestrator() = default;
+
+std::unique_ptr<Orchestrator> Orchestrator::CreateInProcess(
+ std::vector<std::unique_ptr<Worker>> workers) {
+ return std::unique_ptr<Orchestrator>(
+ new OrchestratorImpl(std::move(workers)));
+}
+
+OrchestratorImpl::OrchestratorImpl(std::vector<std::unique_ptr<Worker>> workers)
+ : workers_(std::move(workers)) {}
+
+base::StatusOrFuture<protos::TracePoolCreateResponse>
+OrchestratorImpl::TracePoolCreate(const protos::TracePoolCreateArgs& args) {
+ if (args.pool_type() != protos::TracePoolType::SHARED) {
+ return base::StatusOr<protos::TracePoolCreateResponse>(
+ base::ErrStatus("Currently only SHARED pools are supported"));
+ }
+ if (!args.has_shared_pool_name()) {
+ return base::StatusOr<protos::TracePoolCreateResponse>(
+ base::ErrStatus("Pool name must be provided for SHARED pools"));
+ }
+
+ std::string id = "shared:" + args.shared_pool_name();
+ TracePool* exist = pools_.Find(id);
+ if (exist) {
+ return base::StatusOr<protos::TracePoolCreateResponse>(
+ base::ErrStatus("Pool %s already exists", id.c_str()));
+ }
+ protos::TracePoolShardCreateArgs group_args;
+ group_args.set_pool_id(id);
+ group_args.set_pool_type(args.pool_type());
+
+ using ShardResponse = protos::TracePoolShardCreateResponse;
+ std::vector<base::StatusOrStream<ShardResponse>> shards;
+ for (uint32_t i = 0; i < workers_.size(); ++i) {
+ shards.emplace_back(
+ base::StreamFromFuture(workers_[i]->TracePoolShardCreate(group_args)));
+ }
+ return base::FlattenStreams(std::move(shards))
+ .MapFuture(&CreateResponseToStatus)
+ .Collect(base::AllOkCollector())
+ .ContinueWith(
+ [this, id](base::StatusOr<ShardResponse> resp)
+ -> base::StatusOrFuture<protos::TracePoolCreateResponse> {
+ RETURN_IF_ERROR(resp.status());
+ auto it_and_inserted = pools_.Insert(id, TracePool());
+ if (!it_and_inserted.second) {
+ return base::ErrStatus("Unable to insert pool %s", id.c_str());
+ }
+ return protos::TracePoolCreateResponse();
+ });
+}
+
+base::StatusOrFuture<protos::TracePoolSetTracesResponse>
+OrchestratorImpl::TracePoolSetTraces(
+ const protos::TracePoolSetTracesArgs& args) {
+ std::string id = args.pool_id();
+ TracePool* pool = pools_.Find(id);
+ if (!pool) {
+ return base::StatusOr<protos::TracePoolSetTracesResponse>(
+ base::ErrStatus("Unable to find pool %s", id.c_str()));
+ }
+ if (!pool->loaded_traces.empty()) {
+ return base::StatusOr<protos::TracePoolSetTracesResponse>(base::ErrStatus(
+ "Incrementally adding/removing items to pool not currently supported"));
+ }
+ pool->loaded_traces.assign(args.traces().begin(), args.traces().end());
+ return RoundRobinSetTraces(workers_, pool->loaded_traces)
+ .MapFuture(&SetTracesResponseToStatus)
+ .Collect(base::AllOkCollector())
+ .ContinueWith(
+ [](base::Status status)
+ -> base::StatusOrFuture<protos::TracePoolSetTracesResponse> {
+ RETURN_IF_ERROR(status);
+ return protos::TracePoolSetTracesResponse();
+ });
+}
+
+base::StatusOrStream<protos::TracePoolQueryResponse>
+OrchestratorImpl::TracePoolQuery(const protos::TracePoolQueryArgs& args) {
+ TracePool* pool = pools_.Find(args.pool_id());
+ if (!pool) {
+ return base::StreamOf(base::StatusOr<protos::TracePoolQueryResponse>(
+ base::ErrStatus("Unable to find pool %s", args.pool_id().c_str())));
+ }
+ protos::TracePoolShardQueryArgs shard_args;
+ *shard_args.mutable_pool_id() = args.pool_id();
+ *shard_args.mutable_sql_query() = args.sql_query();
+
+ using ShardResponse = protos::TracePoolShardQueryResponse;
+ std::vector<base::StatusOrStream<ShardResponse>> streams;
+ for (uint32_t i = 0; i < workers_.size(); ++i) {
+ streams.emplace_back(workers_[i]->TracePoolShardQuery(shard_args));
+ }
+ return base::FlattenStreams(std::move(streams))
+ .MapFuture(&RpcResponseToPoolResponse);
+}
+
+base::StatusOrFuture<protos::TracePoolDestroyResponse>
+OrchestratorImpl::TracePoolDestroy(const protos::TracePoolDestroyArgs& args) {
+ std::string id = args.pool_id();
+ TracePool* pool = pools_.Find(id);
+ if (!pool) {
+ return base::StatusOr<protos::TracePoolDestroyResponse>(
+ base::ErrStatus("Unable to find pool %s", id.c_str()));
+ }
+ protos::TracePoolShardDestroyArgs shard_args;
+ *shard_args.mutable_pool_id() = id;
+
+ using ShardResponse = protos::TracePoolShardDestroyResponse;
+ std::vector<base::StatusOrStream<ShardResponse>> streams;
+ for (uint32_t i = 0; i < workers_.size(); ++i) {
+ streams.emplace_back(
+ base::StreamFromFuture(workers_[i]->TracePoolShardDestroy(shard_args)));
+ }
+ return base::FlattenStreams(std::move(streams))
+ .MapFuture(
+ [](base::StatusOr<ShardResponse> resp) -> base::Future<base::Status> {
+ return resp.status();
+ })
+ .Collect(base::AllOkCollector())
+ .ContinueWith(
+ [this, id](base::Status status)
+ -> base::StatusOrFuture<protos::TracePoolDestroyResponse> {
+ RETURN_IF_ERROR(status);
+ PERFETTO_CHECK(pools_.Erase(id));
+ return protos::TracePoolDestroyResponse();
+ });
+}
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
diff --git a/src/cloud_trace_processor/orchestrator_impl.h b/src/cloud_trace_processor/orchestrator_impl.h
new file mode 100644
index 000000000..eef55e574
--- /dev/null
+++ b/src/cloud_trace_processor/orchestrator_impl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_CLOUD_TRACE_PROCESSOR_ORCHESTRATOR_IMPL_H_
+#define SRC_CLOUD_TRACE_PROCESSOR_ORCHESTRATOR_IMPL_H_
+
+#include <memory>
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/cloud_trace_processor/orchestrator.h"
+
+namespace perfetto {
+namespace protos {
+class TracePoolShardCreateArgs;
+}
+
+namespace cloud_trace_processor {
+
+class OrchestratorImpl : public Orchestrator {
+ public:
+ explicit OrchestratorImpl(std::vector<std::unique_ptr<Worker>> workers);
+
+ base::StatusOrStream<protos::TracePoolQueryResponse> TracePoolQuery(
+ const protos::TracePoolQueryArgs&) override;
+
+ base::StatusOrFuture<protos::TracePoolCreateResponse> TracePoolCreate(
+ const protos::TracePoolCreateArgs&) override;
+
+ base::StatusOrFuture<protos::TracePoolSetTracesResponse> TracePoolSetTraces(
+ const protos::TracePoolSetTracesArgs&) override;
+
+ base::StatusOrFuture<protos::TracePoolDestroyResponse> TracePoolDestroy(
+ const protos::TracePoolDestroyArgs&) override;
+
+ private:
+ struct TracePool {
+ std::vector<std::string> loaded_traces;
+ };
+ std::vector<std::unique_ptr<Worker>> workers_;
+ base::FlatHashMap<std::string, TracePool> pools_;
+};
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
+
+#endif // SRC_CLOUD_TRACE_PROCESSOR_ORCHESTRATOR_IMPL_H_
diff --git a/src/cloud_trace_processor/trace_processor_wrapper.cc b/src/cloud_trace_processor/trace_processor_wrapper.cc
new file mode 100644
index 000000000..5093e5285
--- /dev/null
+++ b/src/cloud_trace_processor/trace_processor_wrapper.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/cloud_trace_processor/trace_processor_wrapper.h"
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/poll.h"
+#include "perfetto/ext/base/threading/stream.h"
+#include "perfetto/ext/base/threading/thread_pool.h"
+#include "perfetto/ext/base/threading/util.h"
+#include "perfetto/protozero/proto_utils.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "perfetto/trace_processor/trace_blob.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
+#include "perfetto/trace_processor/trace_processor.h"
+#include "protos/perfetto/cloud_trace_processor/worker.pb.h"
+#include "src/protozero/proto_ring_buffer.h"
+#include "src/trace_processor/rpc/query_result_serializer.h"
+#include "src/trace_processor/util/status_macros.h"
+
+namespace perfetto {
+namespace cloud_trace_processor {
+namespace {
+
+using trace_processor::QueryResultSerializer;
+using trace_processor::TraceBlob;
+using trace_processor::TraceBlobView;
+using trace_processor::TraceProcessor;
+using Statefulness = TraceProcessorWrapper::Statefulness;
+
+struct QueryRunner {
+ QueryRunner(std::shared_ptr<TraceProcessor> _tp,
+ std::string _query,
+ std::string _trace_path,
+ Statefulness _statefulness)
+ : tp(std::move(_tp)),
+ query(std::move(_query)),
+ trace_path(std::move(_trace_path)),
+ statefulness(_statefulness) {}
+
+ std::optional<protos::TracePoolShardQueryResponse> operator()() {
+ if (!has_more) {
+ if (statefulness == Statefulness::kStateless) {
+ tp->RestoreInitialTables();
+ }
+ return std::nullopt;
+ }
+ // If the serializer does not exist yet, that means we have not yet run
+ // the query so make sure to do that first.
+ EnsureSerializerExists();
+ has_more = serializer->Serialize(&result);
+
+ protos::TracePoolShardQueryResponse resp;
+ *resp.mutable_trace() = trace_path;
+ resp.mutable_result()->ParseFromArray(result.data(),
+ static_cast<int>(result.size()));
+ result.clear();
+ return std::make_optional(std::move(resp));
+ }
+
+ void EnsureSerializerExists() {
+ if (serializer) {
+ return;
+ }
+ auto it = tp->ExecuteQuery(query);
+ serializer.reset(new QueryResultSerializer(std::move(it)));
+ }
+
+ std::shared_ptr<TraceProcessor> tp;
+ std::string query;
+ std::string trace_path;
+ TraceProcessorWrapper::Statefulness statefulness;
+
+ // shared_ptr to allow copying when this type is coerced to std::function.
+ std::shared_ptr<QueryResultSerializer> serializer;
+ std::vector<uint8_t> result;
+ bool has_more = true;
+};
+
+} // namespace
+
+TraceProcessorWrapper::TraceProcessorWrapper(std::string trace_path,
+ base::ThreadPool* thread_pool,
+ Statefulness statefulness)
+ : trace_path_(std::move(trace_path)),
+ thread_pool_(thread_pool),
+ statefulness_(statefulness) {
+ trace_processor::Config config;
+ config.ingest_ftrace_in_raw_table = false;
+ trace_processor_ = TraceProcessor::CreateInstance(config);
+}
+
+base::StatusFuture TraceProcessorWrapper::LoadTrace(
+ base::StatusOrStream<std::vector<uint8_t>> file_stream) {
+ if (trace_processor_.use_count() != 1) {
+ return base::ErrStatus("Request is already in flight");
+ }
+ return std::move(file_stream)
+ .MapFuture(
+ [this](base::StatusOr<std::vector<uint8_t>> d) -> base::StatusFuture {
+ RETURN_IF_ERROR(d.status());
+ return base::RunOnceOnThreadPool<base::Status>(
+ thread_pool_, [res = std::move(*d), tp = trace_processor_] {
+ return tp->Parse(TraceBlobView(
+ TraceBlob::CopyFrom(res.data(), res.size())));
+ });
+ })
+ .Collect(base::AllOkCollector())
+ .ContinueWith([this](base::Status status) -> base::StatusFuture {
+ RETURN_IF_ERROR(status);
+ return base::RunOnceOnThreadPool<base::Status>(
+ thread_pool_, [tp = trace_processor_] {
+ tp->NotifyEndOfFile();
+ return base::OkStatus();
+ });
+ });
+}
+
+base::StatusOrStream<protos::TracePoolShardQueryResponse>
+TraceProcessorWrapper::Query(const std::string& query) {
+ using StatusOrResponse = base::StatusOr<protos::TracePoolShardQueryResponse>;
+ if (trace_processor_.use_count() != 1) {
+ return base::StreamOf<StatusOrResponse>(
+ base::ErrStatus("Request is already in flight"));
+ }
+ return base::RunOnThreadPool<StatusOrResponse>(
+ thread_pool_,
+ QueryRunner(trace_processor_, query, trace_path_, statefulness_));
+}
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
diff --git a/src/cloud_trace_processor/trace_processor_wrapper.h b/src/cloud_trace_processor/trace_processor_wrapper.h
new file mode 100644
index 000000000..9916b7225
--- /dev/null
+++ b/src/cloud_trace_processor/trace_processor_wrapper.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_CLOUD_TRACE_PROCESSOR_TRACE_PROCESSOR_WRAPPER_H_
+#define SRC_CLOUD_TRACE_PROCESSOR_TRACE_PROCESSOR_WRAPPER_H_
+
+#include "perfetto/ext/base/threading/future.h"
+#include "perfetto/ext/base/threading/stream.h"
+#include "perfetto/ext/base/threading/thread_pool.h"
+#include "perfetto/trace_processor/trace_processor.h"
+#include "src/trace_processor/rpc/query_result_serializer.h"
+
+namespace perfetto {
+namespace protos {
+
+class TracePoolShardQueryResponse;
+
+} // namespace protos
+} // namespace perfetto
+
+namespace perfetto {
+namespace cloud_trace_processor {
+
+// Wrapper class around an instance of TraceProcessor to adapt it for the needs
+// of a CloudTraceProcessor Worker.
+class TraceProcessorWrapper {
+ public:
+ enum Statefulness {
+ // Indicates that the state of the trace processor instance should be purged
+ // after every query.
+ kStateless,
+
+ // Indicates that the state of the trace processor instance should be
+ // preserved across queries.
+ kStateful,
+ };
+
+ TraceProcessorWrapper(std::string trace_path,
+ base::ThreadPool*,
+ Statefulness);
+
+ // Loads the trace given a stream of chunks to parse.
+ base::StatusFuture LoadTrace(
+ base::StatusOrStream<std::vector<uint8_t>> file_stream);
+
+ // Executes the given query on the trace processor and returns the results
+ // as a stream.
+ base::StatusOrStream<protos::TracePoolShardQueryResponse> Query(
+ const std::string& sql);
+
+ private:
+ using TraceProcessor = trace_processor::TraceProcessor;
+
+ TraceProcessorWrapper(const TraceProcessorWrapper&) = delete;
+ TraceProcessorWrapper& operator=(const TraceProcessorWrapper&) = delete;
+
+ TraceProcessorWrapper(TraceProcessorWrapper&&) = delete;
+ TraceProcessorWrapper& operator=(TraceProcessorWrapper&&) = delete;
+
+ const std::string trace_path_;
+ base::ThreadPool* thread_pool_ = nullptr;
+ const Statefulness statefulness_ = Statefulness::kStateless;
+ std::shared_ptr<TraceProcessor> trace_processor_;
+};
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
+
+#endif // SRC_CLOUD_TRACE_PROCESSOR_TRACE_PROCESSOR_WRAPPER_H_
diff --git a/src/cloud_trace_processor/trace_processor_wrapper_unittest.cc b/src/cloud_trace_processor/trace_processor_wrapper_unittest.cc
new file mode 100644
index 000000000..8739783db
--- /dev/null
+++ b/src/cloud_trace_processor/trace_processor_wrapper_unittest.cc
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/cloud_trace_processor/trace_processor_wrapper.h"
+#include <cstdint>
+#include <vector>
+
+#include "perfetto/base/flat_set.h"
+#include "perfetto/base/platform_handle.h"
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/string_view.h"
+#include "perfetto/ext/base/threading/stream.h"
+#include "perfetto/ext/base/threading/thread_pool.h"
+#include "perfetto/ext/base/threading/util.h"
+#include "protos/perfetto/cloud_trace_processor/worker.pb.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace cloud_trace_processor {
+namespace {
+
+using SF = TraceProcessorWrapper::Statefulness;
+
+const char kSimpleSystrace[] = R"--(# tracer
+ surfaceflinger-598 ( 598) [004] .... 10852.771242: tracing_mark_write: B|598|some event
+ surfaceflinger-598 ( 598) [004] .... 10852.771245: tracing_mark_write: E|598
+)--";
+
+base::StatusOr<std::vector<uint8_t>> SimpleSystrace() {
+ return std::vector<uint8_t>(kSimpleSystrace,
+ kSimpleSystrace + strlen(kSimpleSystrace));
+}
+
+std::vector<base::StatusOr<std::vector<uint8_t>>> SimpleSystraceChunked() {
+ std::string systrace(kSimpleSystrace);
+ std::vector<base::StatusOr<std::vector<uint8_t>>> chunks;
+ for (auto& chunk : base::SplitString(systrace, "\n")) {
+ auto with_newline = chunk + "\n";
+ chunks.push_back(std::vector<uint8_t>(
+ with_newline.data(), with_newline.data() + with_newline.size()));
+ }
+
+ return chunks;
+}
+
+template <typename T>
+T WaitForFutureReady(base::Future<T>& future) {
+ base::FlatSet<base::PlatformHandle> ready;
+ base::FlatSet<base::PlatformHandle> interested;
+ base::PollContext ctx(&interested, &ready);
+ auto res = future.Poll(&ctx);
+ for (; res.IsPending(); res = future.Poll(&ctx)) {
+ PERFETTO_CHECK(interested.size() == 1);
+ base::BlockUntilReadableFd(*interested.begin());
+ interested = {};
+ }
+ return res.item();
+}
+
+template <typename T>
+std::optional<T> WaitForStreamReady(base::Stream<T>& stream) {
+ base::FlatSet<base::PlatformHandle> ready;
+ base::FlatSet<base::PlatformHandle> interested;
+ base::PollContext ctx(&interested, &ready);
+ auto res = stream.PollNext(&ctx);
+ for (; res.IsPending(); res = stream.PollNext(&ctx)) {
+ PERFETTO_CHECK(interested.size() == 1);
+ base::BlockUntilReadableFd(*interested.begin());
+ interested = {};
+ }
+ return res.IsDone() ? std::nullopt : std::make_optional(res.item());
+}
+
+TEST(TraceProcessorWrapperUnittest, Stateful) {
+ base::ThreadPool pool(1);
+ TraceProcessorWrapper wrapper("foobar", &pool, SF::kStateful);
+ {
+ auto load = wrapper.LoadTrace(base::StreamOf(SimpleSystrace()));
+ base::Status status = WaitForFutureReady(load);
+ ASSERT_TRUE(status.ok()) << status.message();
+ }
+ {
+ auto stream = wrapper.Query("CREATE VIEW foo AS SELECT ts, dur FROM slice");
+ auto proto = WaitForStreamReady(stream);
+ ASSERT_TRUE(proto.has_value());
+ ASSERT_TRUE(proto->ok()) << proto->status().message();
+
+ ASSERT_FALSE(WaitForStreamReady(stream).has_value());
+ }
+ {
+ auto stream = wrapper.Query("SELECT ts, dur FROM foo");
+ auto proto = WaitForStreamReady(stream);
+
+ ASSERT_TRUE(proto.has_value());
+ ASSERT_TRUE(proto->ok()) << proto->status().message();
+
+ ASSERT_EQ(proto->value().trace(), "foobar");
+
+ auto& result = proto.value()->result();
+ ASSERT_EQ(result.batch_size(), 1);
+ ASSERT_EQ(result.batch(0).cells_size(), 2);
+
+ ASSERT_EQ(result.batch(0).cells(0),
+ protos::QueryResult::CellsBatch::CELL_VARINT);
+ ASSERT_EQ(result.batch(0).cells(1),
+ protos::QueryResult::CellsBatch::CELL_VARINT);
+ ASSERT_EQ(result.batch(0).varint_cells(0), 10852771242000);
+ ASSERT_EQ(result.batch(0).varint_cells(1), 3000);
+
+ ASSERT_FALSE(WaitForStreamReady(stream).has_value());
+ }
+}
+
+TEST(TraceProcessorWrapperUnittest, Stateless) {
+ base::ThreadPool pool(1);
+ TraceProcessorWrapper wrapper("foobar", &pool, SF::kStateless);
+ {
+ auto load = wrapper.LoadTrace(base::StreamOf(SimpleSystrace()));
+ base::Status status = WaitForFutureReady(load);
+ ASSERT_TRUE(status.ok()) << status.message();
+ }
+ {
+ auto stream = wrapper.Query("CREATE VIEW foo AS SELECT ts, dur FROM slice");
+ auto proto = WaitForStreamReady(stream);
+ ASSERT_TRUE(proto.has_value());
+ ASSERT_TRUE(proto->ok()) << proto->status().message();
+
+ ASSERT_FALSE(WaitForStreamReady(stream).has_value());
+ }
+
+ // Second CREATE VIEW should also succeed because the first one should have
+ // been wiped.
+ {
+ auto stream = wrapper.Query("CREATE VIEW foo AS SELECT ts, dur FROM slice");
+ auto proto = WaitForStreamReady(stream);
+ ASSERT_TRUE(proto.has_value());
+ ASSERT_TRUE(proto->ok()) << proto->status().message();
+
+ ASSERT_FALSE(WaitForStreamReady(stream).has_value());
+ }
+
+ // Selecting from it should return an error.
+ {
+ auto stream = wrapper.Query("SELECT ts, dur FROM foo");
+ auto proto = WaitForStreamReady(stream);
+ ASSERT_TRUE(proto.has_value());
+ ASSERT_TRUE(proto->ok()) << proto->status().message();
+ ASSERT_TRUE(proto->value().result().has_error());
+
+ ASSERT_FALSE(WaitForStreamReady(stream).has_value());
+ }
+}
+
+TEST(TraceProcessorWrapperUnittest, Chunked) {
+ base::ThreadPool pool(1);
+ TraceProcessorWrapper wrapper("foobar", &pool, SF::kStateless);
+ {
+ auto chunked = SimpleSystraceChunked();
+ ASSERT_EQ(chunked.size(), 3u);
+ auto load = wrapper.LoadTrace(base::StreamFrom(chunked));
+ base::Status status = WaitForFutureReady(load);
+ ASSERT_TRUE(status.ok()) << status.message();
+ }
+ {
+ auto stream = wrapper.Query("SELECT ts, dur FROM slice");
+ auto proto = WaitForStreamReady(stream);
+
+ ASSERT_TRUE(proto.has_value());
+ ASSERT_TRUE(proto->ok()) << proto->status().message();
+
+ ASSERT_EQ(proto->value().trace(), "foobar");
+
+ auto& result = proto.value()->result();
+ ASSERT_EQ(result.batch_size(), 1);
+ ASSERT_EQ(result.batch(0).cells_size(), 2);
+
+ ASSERT_EQ(result.batch(0).cells(0),
+ protos::QueryResult::CellsBatch::CELL_VARINT);
+ ASSERT_EQ(result.batch(0).cells(1),
+ protos::QueryResult::CellsBatch::CELL_VARINT);
+ ASSERT_EQ(result.batch(0).varint_cells(0), 10852771242000);
+ ASSERT_EQ(result.batch(0).varint_cells(1), 3000);
+
+ ASSERT_FALSE(WaitForStreamReady(stream).has_value());
+ }
+}
+
+} // namespace
+} // namespace cloud_trace_processor
+} // namespace perfetto
diff --git a/src/cloud_trace_processor/worker_impl.cc b/src/cloud_trace_processor/worker_impl.cc
new file mode 100644
index 000000000..6f115601d
--- /dev/null
+++ b/src/cloud_trace_processor/worker_impl.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/cloud_trace_processor/worker_impl.h"
+
+#include <memory>
+
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/threading/stream.h"
+#include "perfetto/ext/base/uuid.h"
+#include "protos/perfetto/cloud_trace_processor/common.pb.h"
+#include "protos/perfetto/cloud_trace_processor/orchestrator.pb.h"
+#include "protos/perfetto/cloud_trace_processor/worker.pb.h"
+#include "src/cloud_trace_processor/trace_processor_wrapper.h"
+#include "src/trace_processor/util/status_macros.h"
+
+namespace perfetto {
+namespace cloud_trace_processor {
+
+Worker::~Worker() = default;
+
+std::unique_ptr<Worker> Worker::CreateInProcesss(CtpEnvironment* environment,
+ base::ThreadPool* pool) {
+ return std::make_unique<WorkerImpl>(environment, pool);
+}
+
+WorkerImpl::WorkerImpl(CtpEnvironment* environment, base::ThreadPool* pool)
+ : environment_(environment), thread_pool_(pool) {}
+
+base::StatusOrFuture<protos::TracePoolShardCreateResponse>
+WorkerImpl::TracePoolShardCreate(const protos::TracePoolShardCreateArgs& args) {
+ if (args.pool_type() == protos::TracePoolType::DEDICATED) {
+ return base::ErrStatus("Dedicated pools are not currently supported");
+ }
+ auto it_and_inserted = shards_.Insert(args.pool_id(), TracePoolShard());
+ if (!it_and_inserted.second) {
+ return base::ErrStatus("Shard for pool %s already exists",
+ args.pool_id().c_str());
+ }
+ return base::StatusOr(protos::TracePoolShardCreateResponse());
+}
+
+base::StatusOrStream<protos::TracePoolShardSetTracesResponse>
+WorkerImpl::TracePoolShardSetTraces(
+ const protos::TracePoolShardSetTracesArgs& args) {
+ using Response = protos::TracePoolShardSetTracesResponse;
+ using StatusOrResponse = base::StatusOr<Response>;
+
+ TracePoolShard* shard = shards_.Find(args.pool_id());
+ if (!shard) {
+ return base::StreamOf<StatusOrResponse>(base::ErrStatus(
+ "Unable to find shard for pool %s", args.pool_id().c_str()));
+ }
+
+ std::vector<base::StatusOrStream<Response>> streams;
+ for (const std::string& trace : args.traces()) {
+ // TODO(lalitm): add support for stateful trace processor in dedicated
+ // pools.
+ auto tp = std::make_unique<TraceProcessorWrapper>(
+ trace, thread_pool_, TraceProcessorWrapper::Statefulness::kStateless);
+ auto load_trace_future =
+ tp->LoadTrace(environment_->ReadFile(trace))
+ .ContinueWith(
+ [trace](base::Status status) -> base::Future<StatusOrResponse> {
+ RETURN_IF_ERROR(status);
+ protos::TracePoolShardSetTracesResponse resp;
+ *resp.mutable_trace() = trace;
+ return resp;
+ });
+ streams.emplace_back(base::StreamFromFuture(std::move(load_trace_future)));
+ shard->tps.emplace_back(std::move(tp));
+ }
+ return base::FlattenStreams(std::move(streams));
+}
+
+base::StatusOrStream<protos::TracePoolShardQueryResponse>
+WorkerImpl::TracePoolShardQuery(const protos::TracePoolShardQueryArgs& args) {
+ using Response = protos::TracePoolShardQueryResponse;
+ using StatusOrResponse = base::StatusOr<Response>;
+ TracePoolShard* shard = shards_.Find(args.pool_id());
+ if (!shard) {
+ return base::StreamOf<StatusOrResponse>(base::ErrStatus(
+ "Unable to find shard for pool %s", args.pool_id().c_str()));
+ }
+ std::vector<base::StatusOrStream<Response>> streams;
+ streams.reserve(shard->tps.size());
+ for (std::unique_ptr<TraceProcessorWrapper>& tp : shard->tps) {
+ streams.emplace_back(tp->Query(args.sql_query()));
+ }
+ return base::FlattenStreams(std::move(streams));
+}
+
+base::StatusOrFuture<protos::TracePoolShardDestroyResponse>
+WorkerImpl::TracePoolShardDestroy(
+ const protos::TracePoolShardDestroyArgs& args) {
+ if (!shards_.Erase(args.pool_id())) {
+ return base::ErrStatus("Unable to find shard for pool %s",
+ args.pool_id().c_str());
+ }
+ return base::StatusOr(protos::TracePoolShardDestroyResponse());
+}
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
diff --git a/src/cloud_trace_processor/worker_impl.h b/src/cloud_trace_processor/worker_impl.h
new file mode 100644
index 000000000..c7dc7548d
--- /dev/null
+++ b/src/cloud_trace_processor/worker_impl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_CLOUD_TRACE_PROCESSOR_WORKER_IMPL_H_
+#define SRC_CLOUD_TRACE_PROCESSOR_WORKER_IMPL_H_
+
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/threading/thread_pool.h"
+#include "perfetto/ext/cloud_trace_processor/environment.h"
+#include "perfetto/ext/cloud_trace_processor/worker.h"
+#include "src/cloud_trace_processor/trace_processor_wrapper.h"
+
+namespace perfetto {
+namespace protos {
+
+enum GroupType : int;
+
+} // namespace protos
+} // namespace perfetto
+
+namespace perfetto {
+namespace cloud_trace_processor {
+
+class WorkerImpl : public Worker {
+ public:
+ explicit WorkerImpl(CtpEnvironment*, base::ThreadPool*);
+
+ base::StatusOrFuture<protos::TracePoolShardCreateResponse>
+ TracePoolShardCreate(const protos::TracePoolShardCreateArgs&) override;
+
+ base::StatusOrStream<protos::TracePoolShardSetTracesResponse>
+ TracePoolShardSetTraces(const protos::TracePoolShardSetTracesArgs&) override;
+
+ base::StatusOrStream<protos::TracePoolShardQueryResponse> TracePoolShardQuery(
+ const protos::TracePoolShardQueryArgs&) override;
+
+ base::StatusOrFuture<protos::TracePoolShardDestroyResponse>
+ TracePoolShardDestroy(const protos::TracePoolShardDestroyArgs&) override;
+
+ private:
+ struct TracePoolShard {
+ std::vector<std::unique_ptr<TraceProcessorWrapper>> tps;
+ };
+ CtpEnvironment* const environment_;
+ base::ThreadPool* const thread_pool_;
+ base::FlatHashMap<std::string, TracePoolShard> shards_;
+};
+
+} // namespace cloud_trace_processor
+} // namespace perfetto
+
+#endif // SRC_CLOUD_TRACE_PROCESSOR_WORKER_IMPL_H_
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 4a2b0813e..3052341f3 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -19,6 +19,7 @@
#include "perfetto/base/build_config.h"
#include "perfetto/base/proc_utils.h"
#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/string_splitter.h"
#include <fcntl.h>
#include <stdio.h>
@@ -201,15 +202,17 @@ void ReportFinalizeTraceUuidToAtrace(const base::Uuid& uuid) {
const char* kStateDir = "/data/misc/perfetto-traces";
PerfettoCmd::PerfettoCmd() {
- PERFETTO_DCHECK(!g_perfetto_cmd);
- g_perfetto_cmd = this;
+ // Only the main thread instance on the main thread will receive ctrl-c.
+ if (!g_perfetto_cmd)
+ g_perfetto_cmd = this;
}
PerfettoCmd::~PerfettoCmd() {
- PERFETTO_DCHECK(g_perfetto_cmd == this);
- g_perfetto_cmd = nullptr;
- if (ctrl_c_handler_installed_) {
- task_runner_.RemoveFileDescriptorWatch(ctrl_c_evt_.fd());
+ if (g_perfetto_cmd == this) {
+ g_perfetto_cmd = nullptr;
+ if (ctrl_c_handler_installed_) {
+ task_runner_.RemoveFileDescriptorWatch(ctrl_c_evt_.fd());
+ }
}
}
@@ -228,6 +231,9 @@ Usage: %s
session, identified by its ID (see --query).
--config -c : /path/to/trace/config/file or - for stdin
--out -o : /path/to/out/trace/file or - for stdout
+ If using CLONE_SNAPSHOT triggers, each snapshot
+ will be saved in a new file with a counter suffix
+ (e.g., file.0, file.1, file.2).
--txt : Parse config as pbtxt. Not for production use.
Not a stable API.
--query : Queries the service state and prints it as
@@ -339,6 +345,7 @@ std::optional<int> PerfettoCmd::ParseCmdlineAndMaybeDaemonize(int argc,
return 1;
}
+ optind = 1; // Reset getopt state. It's reused by the snapshot thread.
for (;;) {
int option =
getopt_long(argc, argv, "hc:o:dDt:b:s:a:", long_options, nullptr);
@@ -365,6 +372,14 @@ std::optional<int> PerfettoCmd::ParseCmdlineAndMaybeDaemonize(int argc,
opts.categories.emplace_back("power/gpu_frequency");
PERFETTO_CHECK(CreateConfigFromOptions(opts, &test_config));
trace_config_raw = test_config.SerializeAsString();
+ } else if (strcmp(optarg, ":mem") == 0) {
+ // This is used by OnCloneSnapshotTriggerReceived(), which passes the
+ // original trace config as a member field. This is needed because, in
+ // the new PerfettoCmd instance, we need to know upfront trace config
+ // fields that affect the behaviour of perfetto_cmd, e.g., the guardrail
+ // overrides, the unique_session_name, the reporter API package etc.
+ PERFETTO_CHECK(!snapshot_config_.empty());
+ trace_config_raw = snapshot_config_;
} else {
if (!base::ReadFile(optarg, &trace_config_raw)) {
PERFETTO_PLOG("Could not open %s", optarg);
@@ -573,7 +588,7 @@ std::optional<int> PerfettoCmd::ParseCmdlineAndMaybeDaemonize(int argc,
bool parsed = false;
const bool will_trace_or_trigger = !is_attach() && !query_service_;
- if (!will_trace_or_trigger || clone_tsid_) {
+ if (!will_trace_or_trigger) {
if ((!trace_config_raw.empty() || has_config_options)) {
PERFETTO_ELOG("Cannot specify a trace config with this option");
return 1;
@@ -587,7 +602,7 @@ std::optional<int> PerfettoCmd::ParseCmdlineAndMaybeDaemonize(int argc,
}
parsed = CreateConfigFromOptions(config_options, trace_config_.get());
} else {
- if (trace_config_raw.empty()) {
+ if (trace_config_raw.empty() && !clone_tsid_) {
PERFETTO_ELOG("The TraceConfig is empty");
return 1;
}
@@ -784,8 +799,12 @@ std::optional<int> PerfettoCmd::ParseCmdlineAndMaybeDaemonize(int argc,
packet_writer_ = CreateFilePacketWriter(trace_out_stream_.get());
}
- if (trace_config_->compression_type() ==
- TraceConfig::COMPRESSION_TYPE_DEFLATE) {
+ // TODO(b/281043457): this code path will go away after Android U. Compression
+ // has been moved to the service. This code is here only as a fallback in case
+ // of bugs in the U timeframe.
+ if (trace_config_->compress_from_cli() &&
+ trace_config_->compression_type() ==
+ TraceConfig::COMPRESSION_TYPE_DEFLATE) {
if (packet_writer_) {
#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
packet_writer_ = CreateZipPacketWriter(std::move(packet_writer_));
@@ -819,6 +838,7 @@ std::optional<int> PerfettoCmd::ParseCmdlineAndMaybeDaemonize(int argc,
#endif
}
+ PERFETTO_CHECK(!snapshot_thread_); // No threads before demonization.
base::Daemonize([this]() -> int {
background_wait_pipe_.wr.reset();
@@ -992,9 +1012,16 @@ void PerfettoCmd::OnConnect() {
connected_ = true;
LogUploadEvent(PerfettoStatsdAtom::kOnConnect);
+ uint32_t events_mask = 0;
+ if (GetTriggerMode(*trace_config_) ==
+ TraceConfig::TriggerConfig::CLONE_SNAPSHOT) {
+ events_mask |= ObservableEvents::TYPE_CLONE_TRIGGER_HIT;
+ }
if (background_wait_) {
- consumer_endpoint_->ObserveEvents(
- perfetto::ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED);
+ events_mask |= ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED;
+ }
+ if (events_mask) {
+ consumer_endpoint_->ObserveEvents(events_mask);
}
if (query_service_) {
@@ -1119,6 +1146,14 @@ void PerfettoCmd::ReadbackTraceDataAndQuit(const std::string& error) {
// be marked as "E" in the event log. Hence why LOG and not ELOG here.
PERFETTO_LOG("Service error: %s", error.c_str());
+ // In case of errors don't leave a partial file around. This happens
+ // frequently in the case of --save-for-bugreport if there is no eligible
+ // trace. See also b/279753347 .
+ if (bytes_written_ == 0 && !trace_out_path_.empty() &&
+ trace_out_path_ != "-") {
+ remove(trace_out_path_.c_str());
+ }
+
// Update guardrail state even if we failed. This is for two
// reasons:
// 1. Keeps compatibility with pre-stats code which used to
@@ -1214,6 +1249,9 @@ bool PerfettoCmd::OpenOutputFile() {
}
void PerfettoCmd::SetupCtrlCSignalHandler() {
+ // Only the main thread instance should handle CTRL+C.
+ if (g_perfetto_cmd != this)
+ return;
ctrl_c_handler_installed_ = true;
base::InstallCtrlCHandler([] {
if (!g_perfetto_cmd)
@@ -1282,17 +1320,18 @@ void PerfettoCmd::OnTraceStats(bool /*success*/,
// TODO(eseckler): Support GetTraceStats().
}
-void PerfettoCmd::OnSessionCloned(bool success, const std::string& error) {
+void PerfettoCmd::OnSessionCloned(const OnSessionClonedArgs& args) {
PERFETTO_DLOG("Cloned tracing session %" PRIu64 ", success=%d",
- clone_tsid_.value_or(0), success);
+ clone_tsid_.value_or(0), args.success);
std::string full_error;
- if (!success) {
+ if (!args.success) {
full_error = "Failed to clone tracing session " +
- std::to_string(clone_tsid_.value_or(0)) + ": " + error;
+ std::to_string(clone_tsid_.value_or(0)) + ": " + args.error;
}
// Kick off the readback and file finalization (as if we started tracing and
// reached the duration_ms timeout).
+ uuid_ = args.uuid.ToString();
ReadbackTraceDataAndQuit(full_error);
}
@@ -1413,6 +1452,69 @@ void PerfettoCmd::OnObservableEvents(
if (observable_events.all_data_sources_started()) {
NotifyBgProcessPipe(kBackgroundOk);
}
+ if (observable_events.has_clone_trigger_hit()) {
+ int64_t tsid = observable_events.clone_trigger_hit().tracing_session_id();
+ OnCloneSnapshotTriggerReceived(static_cast<TracingSessionID>(tsid));
+ }
+}
+
+void PerfettoCmd::OnCloneSnapshotTriggerReceived(TracingSessionID tsid) {
+ PERFETTO_DLOG("Creating snapshot for tracing session %" PRIu64, tsid);
+
+ // Only the main thread instance should be handling snapshots.
+ // We should never end up in a state where each secondary PerfettoCmd
+ // instance handles other snapshots and creates other threads.
+ PERFETTO_CHECK(g_perfetto_cmd == this);
+
+ std::string cmdline;
+ auto add_argv = [&cmdline](const std::string& str) {
+ cmdline.append(str);
+ cmdline.append("\0", 1);
+ };
+ add_argv("perfetto");
+ add_argv("--config");
+ add_argv(":mem"); // Use the copied config from `snapshot_config_`.
+ add_argv("--clone");
+ add_argv(std::to_string(tsid));
+ if (upload_flag_) {
+ add_argv("--upload");
+ } else if (!trace_out_path_.empty()) {
+ add_argv("--out");
+ add_argv(trace_out_path_ + "." + std::to_string(snapshot_count_++));
+ } else {
+ PERFETTO_FATAL("Cannot use CLONE_SNAPSHOT with the current cmdline args");
+ }
+
+ if (!snapshot_thread_) {
+ // The destructor of the main-thread's PerfettoCmdMain will destroy and
+ // join the secondary thread that we are crating here.
+ snapshot_thread_.reset(new base::ThreadTaskRunner(
+ base::ThreadTaskRunner::CreateAndStart("snapshot")));
+ }
+
+ // We need to pass a copy of the trace config to the new PerfettoCmd instance
+ // because the trace config defines a bunch of properties that are used by the
+ // cmdline client (reporter API package, guardrails, etc).
+ std::string trace_config_copy = trace_config_->SerializeAsString();
+
+ snapshot_thread_->PostTask([tsid, cmdline, trace_config_copy] {
+ int argc = 0;
+ char* argv[32];
+ // `splitter` needs to live on the stack for the whole scope as it owns the
+ // underlying string storage (that gets std::moved) passed PerfettoCmd.
+ base::StringSplitter splitter(std::move(cmdline), '\0');
+ while (splitter.Next()) {
+ argv[argc++] = splitter.cur_token();
+ PERFETTO_CHECK(static_cast<size_t>(argc) < base::ArraySize(argv));
+ }
+ perfetto::PerfettoCmd cmd;
+ cmd.snapshot_config_ = std::move(trace_config_copy);
+ auto cmdline_res = cmd.ParseCmdlineAndMaybeDaemonize(argc, argv);
+ PERFETTO_CHECK(!cmdline_res.has_value()); // No daemonization expected.
+ int res = cmd.ConnectToServiceRunAndMaybeNotify();
+ if (res)
+ PERFETTO_ELOG("Cloning session %" PRIu64 " failed (%d)", tsid, res);
+ });
}
void PerfettoCmd::LogUploadEvent(PerfettoStatsdAtom atom) {
diff --git a/src/perfetto_cmd/perfetto_cmd.h b/src/perfetto_cmd/perfetto_cmd.h
index 9504ca5fa..b55cbc8c2 100644
--- a/src/perfetto_cmd/perfetto_cmd.h
+++ b/src/perfetto_cmd/perfetto_cmd.h
@@ -28,6 +28,7 @@
#include "perfetto/ext/base/event_fd.h"
#include "perfetto/ext/base/pipe.h"
#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/thread_task_runner.h"
#include "perfetto/ext/base/unix_task_runner.h"
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/tracing/core/consumer.h"
@@ -67,7 +68,7 @@ class PerfettoCmd : public Consumer {
void OnAttach(bool, const TraceConfig&) override;
void OnTraceStats(bool, const TraceStats&) override;
void OnObservableEvents(const ObservableEvents&) override;
- void OnSessionCloned(bool, const std::string&) override;
+ void OnSessionCloned(const OnSessionClonedArgs&) override;
void SignalCtrlC() { ctrl_c_evt_.Notify(); }
@@ -116,6 +117,8 @@ class PerfettoCmd : public Consumer {
// will have no effect.
void NotifyBgProcessPipe(BgProcessStatus status);
+ void OnCloneSnapshotTriggerReceived(TracingSessionID);
+
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
static base::ScopedFile CreateUnlinkedTmpFile();
void SaveTraceIntoIncidentOrCrash();
@@ -162,6 +165,14 @@ class PerfettoCmd : public Consumer {
// How long we expect to trace for or 0 if the trace is indefinite.
uint32_t expected_duration_ms_ = 0;
bool trace_data_timeout_armed_ = false;
+
+ // The aux thread that is used to invoke secondary instances of PerfettoCmd
+ // to create snapshots. This is used only when the trace config involves a
+ // CLONE_SNAPSHOT trigger.
+ std::unique_ptr<base::ThreadTaskRunner> snapshot_thread_;
+ int snapshot_count_ = 0;
+ std::string snapshot_config_;
+
base::WeakPtrFactory<PerfettoCmd> weak_factory_{this};
};
diff --git a/src/profiling/perf/perf_producer.cc b/src/profiling/perf/perf_producer.cc
index 0fb7be314..fec5b6dcd 100644
--- a/src/profiling/perf/perf_producer.cc
+++ b/src/profiling/perf/perf_producer.cc
@@ -16,8 +16,10 @@
#include "src/profiling/perf/perf_producer.h"
+#include <optional>
#include <random>
#include <utility>
+#include <vector>
#include <unistd.h>
@@ -26,7 +28,9 @@
#include "perfetto/base/logging.h"
#include "perfetto/base/task_runner.h"
+#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/metatrace.h"
+#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/tracing/core/basic_types.h"
@@ -80,6 +84,35 @@ size_t NumberOfCpus() {
return static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
}
+std::vector<uint32_t> GetOnlineCpus() {
+ size_t cpu_count = NumberOfCpus();
+ if (cpu_count == 0) {
+ return {};
+ }
+
+ static constexpr char kOnlineValue[] = "1\n";
+ std::vector<uint32_t> online_cpus;
+ online_cpus.reserve(cpu_count);
+ for (uint32_t cpu = 0; cpu < cpu_count; ++cpu) {
+ std::string res;
+ base::StackString<1024> path("/sys/devices/system/cpu/cpu%u/online", cpu);
+ if (!base::ReadFile(path.c_str(), &res)) {
+ // Always consider CPU 0 to be online if the "online" file does not exist
+ // for it. There seem to be several assumptions in the kernel which make
+ // CPU 0 special so this is a pretty safe bet.
+ if (cpu != 0) {
+ return {};
+ }
+ res = kOnlineValue;
+ }
+ if (res != kOnlineValue) {
+ continue;
+ }
+ online_cpus.push_back(cpu);
+ }
+ return online_cpus;
+}
+
int32_t ToBuiltinClock(int32_t clockid) {
switch (clockid) {
case CLOCK_REALTIME:
@@ -394,9 +427,14 @@ void PerfProducer::StartDataSource(DataSourceInstanceID ds_id,
return;
}
- size_t num_cpus = NumberOfCpus();
+ std::vector<uint32_t> online_cpus = GetOnlineCpus();
+ if (online_cpus.empty()) {
+ PERFETTO_ELOG("No online CPUs found.");
+ return;
+ }
+
std::vector<EventReader> per_cpu_readers;
- for (uint32_t cpu = 0; cpu < num_cpus; cpu++) {
+ for (uint32_t cpu : online_cpus) {
std::optional<EventReader> event_reader =
EventReader::ConfigureEvents(cpu, event_config.value());
if (!event_reader.has_value()) {
diff --git a/src/protozero/filtering/filter_util.cc b/src/protozero/filtering/filter_util.cc
index 8e81cb040..d17a36b10 100644
--- a/src/protozero/filtering/filter_util.cc
+++ b/src/protozero/filtering/filter_util.cc
@@ -67,9 +67,13 @@ void MultiFileErrorCollectorImpl::AddWarning(const std::string& filename,
FilterUtil::FilterUtil() = default;
FilterUtil::~FilterUtil() = default;
-bool FilterUtil::LoadMessageDefinition(const std::string& proto_file,
- const std::string& root_message,
- const std::string& proto_dir_path) {
+bool FilterUtil::LoadMessageDefinition(
+ const std::string& proto_file,
+ const std::string& root_message,
+ const std::string& proto_dir_path,
+ const std::set<std::string>& passthrough_fields) {
+ passthrough_fields_ = passthrough_fields;
+ passthrough_fields_seen_.clear();
// The protobuf compiler doesn't like backslashes and prints an error like:
// Error C:\it7mjanpw3\perfetto-a16500 -1:0: Backslashes, consecutive slashes,
// ".", or ".." are not allowed in the virtual path.
@@ -122,6 +126,22 @@ bool FilterUtil::LoadMessageDefinition(const std::string& proto_file,
// future without realizing) when performing the Dedupe() pass.
DescriptorsByNameMap descriptors_by_full_name;
ParseProtoDescriptor(root_msg, &descriptors_by_full_name);
+
+ // If the user specified a set of fields to pass through, print an error and
+ // fail if any of the passed fields have not been seen while recursing in the
+ // schema. This is to avoid typos or naming changes to be silently ignored.
+ std::vector<std::string> unused_passthrough;
+ std::set_difference(passthrough_fields_.begin(), passthrough_fields_.end(),
+ passthrough_fields_seen_.begin(),
+ passthrough_fields_seen_.end(),
+ std::back_inserter(unused_passthrough));
+ for (const std::string& message_and_field : unused_passthrough) {
+ PERFETTO_ELOG("Field not found %s", message_and_field.c_str());
+ }
+ if (!unused_passthrough.empty()) {
+ PERFETTO_ELOG("Syntax: perfetto.protos.MessageName:field_name");
+ return false;
+ }
return true;
}
@@ -145,7 +165,15 @@ FilterUtil::Message* FilterUtil::ParseProtoDescriptor(
auto& field = msg->fields[field_id];
field.name = proto_field->name();
field.type = proto_field->type_name();
- if (proto_field->message_type()) {
+
+ std::string message_and_field = msg->full_name + ":" + field.name;
+ bool passthrough = false;
+ if (passthrough_fields_.count(message_and_field)) {
+ field.type = "bytes";
+ passthrough = true;
+ passthrough_fields_seen_.insert(message_and_field);
+ }
+ if (proto_field->message_type() && !passthrough) {
msg->has_nested_fields = true;
// Recurse.
field.nested_type = ParseProtoDescriptor(proto_field->message_type(),
@@ -253,8 +281,11 @@ void FilterUtil::PrintAsText(std::optional<std::string> filter_bytecode) {
}
const Message* nested_type = id_and_field.second.nested_type;
+ bool passthrough = false;
if (nested_type) {
- PERFETTO_CHECK(!result.simple_field() || !filter_bytecode);
+ // result.simple_field might be true if the generated bytecode is
+ // passing through a whole submessage without recursing.
+ passthrough = result.simple_field();
if (seen_msgs.find(nested_type) == seen_msgs.end()) {
seen_msgs.insert(nested_type);
queue.emplace_back(result.nested_msg_index, nested_type);
@@ -267,6 +298,8 @@ void FilterUtil::PrintAsText(std::optional<std::string> filter_bytecode) {
std::string stripped_nested =
nested_type ? " " + StripPrefix(nested_type->full_name, root_prefix)
: "";
+ if (passthrough)
+ stripped_nested += " # PASSTHROUGH";
fprintf(print_stream_, "%-60s %3u %-8s %-32s%s\n", stripped_name.c_str(),
field_id, field.type.c_str(), field.name.c_str(),
stripped_nested.c_str());
diff --git a/src/protozero/filtering/filter_util.h b/src/protozero/filtering/filter_util.h
index 0c5e74fe4..276ec6ddc 100644
--- a/src/protozero/filtering/filter_util.h
+++ b/src/protozero/filtering/filter_util.h
@@ -22,6 +22,7 @@
#include <list>
#include <map>
#include <optional>
+#include <set>
#include <string>
// We include this intentionally instead of forward declaring to allow
@@ -46,9 +47,14 @@ class FilterUtil {
// root_message: fully qualified message name (e.g., perfetto.protos.Trace).
// If empty, the first message in the file will be used.
// proto_dir_path: the root for .proto includes. If empty uses CWD.
- bool LoadMessageDefinition(const std::string& proto_file,
- const std::string& root_message,
- const std::string& proto_dir_path);
+ // passthrough: an optional set of fields that should be transparently passed
+ // through without recursing further.
+ // Syntax: "perfetto.protos.TracePacket:trace_config"
+ bool LoadMessageDefinition(
+ const std::string& proto_file,
+ const std::string& root_message,
+ const std::string& proto_dir_path,
+ const std::set<std::string>& passthrough_fields = {});
// Deduplicates leaf messages having the same sets of field ids.
// It changes the internal state and affects the behavior of next calls to
@@ -103,6 +109,12 @@ class FilterUtil {
// list<> because pointers need to be stable.
std::list<Message> descriptors_;
+ std::set<std::string> passthrough_fields_;
+
+ // Used only for debugging aid, to print out an error message when the user
+ // specifies a field to pass through but it doesn't exist.
+ std::set<std::string> passthrough_fields_seen_;
+
FILE* print_stream_ = stdout;
};
diff --git a/src/protozero/filtering/filter_util_unittest.cc b/src/protozero/filtering/filter_util_unittest.cc
index 7ad4d6f5f..2b13ae664 100644
--- a/src/protozero/filtering/filter_util_unittest.cc
+++ b/src/protozero/filtering/filter_util_unittest.cc
@@ -302,5 +302,42 @@ Child2.Nested 1 int64 f1
FilterToText(filter, bytecode));
}
+TEST(SchemaParserTest, Passthrough) {
+ auto schema = MkTemp(R"(
+ syntax = "proto2";
+ message Root {
+ optional int32 i32 = 13;
+ optional TracePacket packet = 7;
+ }
+ message TraceConfig {
+ optional int32 f3 = 3;
+ optional int64 f4 = 4;
+ }
+ message TracePacket {
+ optional int32 f1 = 3;
+ optional int64 f2 = 4;
+ optional TraceConfig cfg = 5;
+ }
+ )");
+
+ FilterUtil filter;
+ std::set<std::string> passthrough{"TracePacket:cfg"};
+ ASSERT_TRUE(
+ filter.LoadMessageDefinition(schema.path(), "Root", "", passthrough));
+
+ EXPECT_EQ(R"(Root 7 message packet TracePacket
+Root 13 int32 i32
+TracePacket 3 int32 f1
+TracePacket 4 int64 f2
+TracePacket 5 bytes cfg
+)",
+ FilterToText(filter));
+
+ std::string bytecode = filter.GenerateFilterBytecode();
+ // If we generate bytecode from the schema itself, all fields are allowed and
+ // the result is identical to the unfiltered output.
+ EXPECT_EQ(FilterToText(filter), FilterToText(filter, bytecode));
+}
+
} // namespace
} // namespace protozero
diff --git a/src/protozero/filtering/message_filter_unittest.cc b/src/protozero/filtering/message_filter_unittest.cc
index 83cb911f2..3159bfcba 100644
--- a/src/protozero/filtering/message_filter_unittest.cc
+++ b/src/protozero/filtering/message_filter_unittest.cc
@@ -128,6 +128,87 @@ TEST(MessageFilterTest, EndToEnd) {
}
}
+TEST(MessageFilterTest, Passthrough) {
+ auto schema = perfetto::base::TempFile::Create();
+ static const char kSchema[] = R"(
+ syntax = "proto2";
+ message TracePacket {
+ optional int64 timestamp = 1;
+ optional TraceConfig cfg = 2;
+ optional TraceConfig cfg_filtered = 3;
+ optional string other = 4;
+ };
+ message SubConfig {
+ optional string f4 = 6;
+ }
+ message TraceConfig {
+ optional int64 f1 = 3;
+ optional string f2 = 4;
+ optional SubConfig f3 = 5;
+ }
+ )";
+
+ perfetto::base::WriteAll(*schema, kSchema, strlen(kSchema));
+ perfetto::base::FlushFile(*schema);
+
+ FilterUtil filter;
+ ASSERT_TRUE(filter.LoadMessageDefinition(
+ schema.path(), "", "", {"TracePacket:other", "TracePacket:cfg"}));
+ std::string bytecode = filter.GenerateFilterBytecode();
+ ASSERT_GT(bytecode.size(), 0u);
+
+ HeapBuffered<Message> msg;
+ msg->AppendVarInt(/*field_id=*/1, 10);
+ msg->AppendString(/*field_id=*/4, "other_string");
+
+ // Fill `cfg`.
+ auto* nest = msg->BeginNestedMessage<Message>(/*field_id=*/2);
+ nest->AppendVarInt(/*field_id=*/3, 100);
+ nest->AppendString(/*field_id=*/4, "f2.payload");
+ nest->AppendString(/*field_id=*/99, "not_in_original_schema");
+ auto* nest2 = nest->BeginNestedMessage<Message>(/*field_id=*/5);
+ nest2->AppendString(/*field_id=*/6, "subconfig.f4");
+ nest2->Finalize();
+ nest->Finalize();
+
+ // Fill `cfg_filtered`.
+ nest = msg->BeginNestedMessage<Message>(/*field_id=*/3);
+ nest->AppendVarInt(/*field_id=*/3, 200); // This should be propagated.
+ nest->AppendVarInt(/*field_id=*/6, 300); // This shoudl be filtered out.
+ nest->Finalize();
+
+ MessageFilter flt;
+ ASSERT_TRUE(flt.LoadFilterBytecode(bytecode.data(), bytecode.size()));
+
+ std::vector<uint8_t> encoded = msg.SerializeAsArray();
+
+ auto filtered = flt.FilterMessage(encoded.data(), encoded.size());
+ ASSERT_LT(filtered.size, encoded.size());
+
+ ProtoDecoder dec(filtered.data.get(), filtered.size);
+ EXPECT_EQ(dec.FindField(1).as_int64(), 10);
+ EXPECT_EQ(dec.FindField(4).as_std_string(), "other_string");
+
+ EXPECT_TRUE(dec.FindField(2).valid());
+ ProtoDecoder nest_dec(dec.FindField(2).as_bytes());
+ EXPECT_EQ(nest_dec.FindField(3).as_int32(), 100);
+ EXPECT_EQ(nest_dec.FindField(4).as_std_string(), "f2.payload");
+ EXPECT_TRUE(nest_dec.FindField(5).valid());
+ ProtoDecoder nest_dec2(nest_dec.FindField(5).as_bytes());
+ EXPECT_EQ(nest_dec2.FindField(6).as_std_string(), "subconfig.f4");
+
+ // Field 99 should be preserved anyways even if it wasn't in the original
+ // schema because the whole TracePacket submessage was passed through.
+ EXPECT_TRUE(nest_dec.FindField(99).valid());
+ EXPECT_EQ(nest_dec.FindField(99).as_std_string(), "not_in_original_schema");
+
+ // Check that the field `cfg_filtered` contains only `f1`,`f2`,`f3`.
+ EXPECT_TRUE(dec.FindField(3).valid());
+ ProtoDecoder nest_dec3(dec.FindField(3).as_bytes());
+ EXPECT_EQ(nest_dec3.FindField(3).as_int32(), 200);
+ EXPECT_FALSE(nest_dec3.FindField(6).valid());
+}
+
TEST(MessageFilterTest, ChangeRoot) {
auto schema = perfetto::base::TempFile::Create();
static const char kSchema[] = R"(
diff --git a/src/protozero/packed_repeated_fields.cc b/src/protozero/packed_repeated_fields.cc
index 16d453953..a884b73ca 100644
--- a/src/protozero/packed_repeated_fields.cc
+++ b/src/protozero/packed_repeated_fields.cc
@@ -20,11 +20,6 @@
namespace protozero {
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// static
-constexpr size_t PackedBufferBase::kOnStackStorageSize;
-#endif
-
void PackedBufferBase::GrowSlowpath() {
size_t write_off = static_cast<size_t>(write_ptr_ - storage_begin_);
size_t old_size = static_cast<size_t>(storage_end_ - storage_begin_);
diff --git a/src/protozero/proto_decoder_unittest.cc b/src/protozero/proto_decoder_unittest.cc
index 0991f887b..1e962d7a6 100644
--- a/src/protozero/proto_decoder_unittest.cc
+++ b/src/protozero/proto_decoder_unittest.cc
@@ -592,5 +592,26 @@ TEST(ProtoDecoderTest, OneBigFieldIdOnly) {
ASSERT_FALSE(field.valid());
}
+// Check what happens when trying to parse packed repeated field and finding a
+// mismatching wire type instead. A compliant protobuf decoder should accept it,
+// but protozero doesn't handle that. At least it shouldn't crash.
+TEST(ProtoDecoderTest, PacketRepeatedWireTypeMismatch) {
+ protozero::HeapBuffered<pbtest::PackedRepeatedFields> message;
+ // A proper packed encoding should have a length delimited wire type. Use a
+ // var int wire type instead.
+ constexpr int kFieldId = pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
+ message->AppendTinyVarInt(kFieldId, 5);
+ auto data = message.SerializeAsArray();
+
+ pbtest::PackedRepeatedFields::Decoder decoder(data.data(), data.size());
+ bool parse_error = false;
+ auto it = decoder.field_int32(&parse_error);
+ // The decoder doesn't return a parse error (maybe it should, but that has
+ // been the behavior since the beginning).
+ ASSERT_FALSE(parse_error);
+ // But the iterator returns 0 elements.
+ EXPECT_FALSE(it);
+}
+
} // namespace
} // namespace protozero
diff --git a/src/shared_lib/test/BUILD.gn b/src/shared_lib/test/BUILD.gn
index 220439aeb..aa87956b0 100644
--- a/src/shared_lib/test/BUILD.gn
+++ b/src/shared_lib/test/BUILD.gn
@@ -22,7 +22,11 @@ source_set("utils") {
"../../../gn:gtest_and_gmock",
"../../../include/perfetto/public",
]
- sources = [ "utils.cc" ]
+ sources = [
+ "utils.cc",
+ "utils.h",
+ ]
+ defines = [ "PERFETTO_SDK_DISABLE_SHLIB_EXPORT" ]
}
if (enable_perfetto_benchmarks) {
@@ -35,6 +39,7 @@ if (enable_perfetto_benchmarks) {
"../../../gn:default_deps",
"../../../include/perfetto/public",
]
+ defines = [ "PERFETTO_SDK_DISABLE_SHLIB_EXPORT" ]
sources = [ "benchmark.cc" ]
}
}
@@ -49,6 +54,7 @@ if (enable_perfetto_integration_tests) {
"../../../gn:gtest_and_gmock",
"../../../include/perfetto/public",
]
+ defines = [ "PERFETTO_SDK_DISABLE_SHLIB_EXPORT" ]
sources = [ "api_integrationtest.cc" ]
}
}
diff --git a/src/tools/ftrace_proto_gen/event_list b/src/tools/ftrace_proto_gen/event_list
index 33ec8e916..40dd94924 100644
--- a/src/tools/ftrace_proto_gen/event_list
+++ b/src/tools/ftrace_proto_gen/event_list
@@ -476,3 +476,5 @@ hyp/host_hcall
hyp/host_smc
hyp/host_mem_abort
synthetic/suspend_resume_minimal
+mali/mali_CSF_INTERRUPT_START
+mali/mali_CSF_INTERRUPT_END
diff --git a/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc b/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc
index f69237313..712e3d139 100644
--- a/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc
+++ b/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc
@@ -191,6 +191,11 @@ std::string SingleEventInfo(perfetto::Proto proto,
// configurations)
if (group == "ftrace" && proto.event_name == "print" && field->name == "ip")
continue;
+ // Ignore the "nid" field. On new kernels, this field has a type that we
+ // don't know how to parse. See b/281660544
+ if (group == "f2fs" && proto.event_name == "f2fs_truncate_partial_nodes" &&
+ field->name == "nid")
+ continue;
s += "{";
s += "kUnsetOffset, ";
s += "kUnsetSize, ";
diff --git a/src/tools/proto_filter/proto_filter.cc b/src/tools/proto_filter/proto_filter.cc
index 04385c2b1..7bfcb74d8 100644
--- a/src/tools/proto_filter/proto_filter.cc
+++ b/src/tools/proto_filter/proto_filter.cc
@@ -49,7 +49,7 @@ Example usage:
# Generate the filter bytecode from a .proto schema
proto_filter -r perfetto.protos.Trace -s protos/perfetto/trace/trace.proto \
- -F /tmp/bytecode [--dedupe]
+ -F /tmp/bytecode [--dedupe] [-x protos.Message:field_to_pass]
# List the used/filtered fields from a trace file
@@ -72,14 +72,15 @@ int Main(int argc, char** argv) {
{"help", no_argument, nullptr, 'h'},
{"version", no_argument, nullptr, 'v'},
{"dedupe", no_argument, nullptr, 'd'},
- {"proto_path", no_argument, nullptr, 'I'},
- {"schema_in", no_argument, nullptr, 's'},
- {"root_message", no_argument, nullptr, 'r'},
- {"msg_in", no_argument, nullptr, 'i'},
- {"msg_out", no_argument, nullptr, 'o'},
- {"filter_in", no_argument, nullptr, 'f'},
- {"filter_out", no_argument, nullptr, 'F'},
- {"filter_oct_out", no_argument, nullptr, 'T'},
+ {"proto_path", required_argument, nullptr, 'I'},
+ {"schema_in", required_argument, nullptr, 's'},
+ {"root_message", required_argument, nullptr, 'r'},
+ {"msg_in", required_argument, nullptr, 'i'},
+ {"msg_out", required_argument, nullptr, 'o'},
+ {"filter_in", required_argument, nullptr, 'f'},
+ {"filter_out", required_argument, nullptr, 'F'},
+ {"filter_oct_out", required_argument, nullptr, 'T'},
+ {"passthrough", required_argument, nullptr, 'x'},
{nullptr, 0, nullptr, 0}};
std::string msg_in;
@@ -90,11 +91,12 @@ int Main(int argc, char** argv) {
std::string filter_oct_out;
std::string proto_path;
std::string root_message_arg;
+ std::set<std::string> passthrough_fields;
bool dedupe = false;
for (;;) {
int option =
- getopt_long(argc, argv, "hvdI:s:r:i:o:f:F:T:", long_options, nullptr);
+ getopt_long(argc, argv, "hvdI:s:r:i:o:f:F:T:x:", long_options, nullptr);
if (option == -1)
break; // EOF.
@@ -149,6 +151,11 @@ int Main(int argc, char** argv) {
continue;
}
+ if (option == 'x') {
+ passthrough_fields.insert(optarg);
+ continue;
+ }
+
if (option == 'h') {
fprintf(stdout, kUsage);
exit(0);
@@ -175,8 +182,8 @@ int Main(int argc, char** argv) {
protozero::FilterUtil filter;
if (!schema_in.empty()) {
PERFETTO_LOG("Loading proto schema from %s", schema_in.c_str());
- if (!filter.LoadMessageDefinition(schema_in, root_message_arg,
- proto_path)) {
+ if (!filter.LoadMessageDefinition(schema_in, root_message_arg, proto_path,
+ passthrough_fields)) {
PERFETTO_ELOG("Failed to parse proto schema from %s", schema_in.c_str());
return 1;
}
@@ -264,7 +271,7 @@ int Main(int argc, char** argv) {
if (!msg_out.empty()) {
PERFETTO_LOG("Writing filtered proto bytes (%zu bytes) into %s",
msg_filtered_data.size(), msg_out.c_str());
- auto fd = base::OpenFile(msg_out, O_WRONLY | O_CREAT, 0644);
+ auto fd = base::OpenFile(msg_out, O_WRONLY | O_TRUNC | O_CREAT, 0644);
base::WriteAll(*fd, msg_filtered_data.data(), msg_filtered_data.size());
}
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 29bd8c5ee..6f0660c6a 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -172,6 +172,7 @@ if (enable_perfetto_trace_processor_sqlite) {
"prelude/functions",
"prelude/operators",
"prelude/table_functions",
+ "prelude/tables_views",
"sqlite",
"stdlib:gen_amalgamated_stdlib",
"storage",
diff --git a/src/trace_processor/containers/bit_vector.cc b/src/trace_processor/containers/bit_vector.cc
index b5c2dc99b..3e3adabb0 100644
--- a/src/trace_processor/containers/bit_vector.cc
+++ b/src/trace_processor/containers/bit_vector.cc
@@ -88,6 +88,76 @@ BitVector::BitVector(std::vector<uint64_t> words,
words_.resize(words_.size() + 8 - (words_.size() % 8u));
}
+void BitVector::Resize(uint32_t new_size, bool filler) {
+ uint32_t old_size = size_;
+ if (new_size == old_size)
+ return;
+
+ // Empty bitvectors should be memory efficient so we don't keep any data
+ // around in the bitvector.
+ if (new_size == 0) {
+ words_.clear();
+ counts_.clear();
+ size_ = 0;
+ return;
+ }
+
+ // Compute the address of the new last bit in the bitvector.
+ Address last_addr = IndexToAddress(new_size - 1);
+ uint32_t old_blocks_size = static_cast<uint32_t>(counts_.size());
+ uint32_t new_blocks_size = last_addr.block_idx + 1;
+
+ // Resize the block and count vectors to have the correct number of entries.
+ words_.resize(Block::kWords * new_blocks_size);
+ counts_.resize(new_blocks_size);
+
+ if (new_size > old_size) {
+ if (filler) {
+ // If the new space should be filled with ones, then set all the bits
+ // between the address of the old size and the new last address.
+ const Address& start = IndexToAddress(old_size);
+ Set(start, last_addr);
+
+ // We then need to update the counts vector to match the changes we
+ // made to the blocks.
+
+ // We start by adding the bits we set in the first block to the
+ // cummulative count before the range we changed.
+ Address end_of_block = {start.block_idx,
+ {Block::kWords - 1, BitWord::kBits - 1}};
+ uint32_t count_in_block_after_end =
+ AddressToIndex(end_of_block) - AddressToIndex(start) + 1;
+ uint32_t set_count = CountSetBits() + count_in_block_after_end;
+
+ for (uint32_t i = start.block_idx + 1; i <= last_addr.block_idx; ++i) {
+ // Set the count to the cummulative count so far.
+ counts_[i] = set_count;
+
+ // Add a full block of set bits to the count.
+ set_count += Block::kBits;
+ }
+ } else {
+ // If the newly added bits are false, we just need to update the
+ // counts vector with the current size of the bitvector for all
+ // the newly added blocks.
+ if (new_blocks_size > old_blocks_size) {
+ uint32_t count = CountSetBits();
+ for (uint32_t i = old_blocks_size; i < new_blocks_size; ++i) {
+ counts_[i] = count;
+ }
+ }
+ }
+ } else {
+ // Throw away all the bits after the new last bit. We do this to make
+ // future lookup, append and resize operations not have to worrying about
+ // trailing garbage bits in the last block.
+ BlockFromIndex(last_addr.block_idx).ClearAfter(last_addr.block_offset);
+ }
+
+ // Actually update the size.
+ size_ = new_size;
+}
+
BitVector BitVector::Copy() const {
return BitVector(words_, counts_, size_);
}
@@ -100,27 +170,50 @@ BitVector::SetBitsIterator BitVector::IterateSetBits() const {
return SetBitsIterator(this);
}
+BitVector BitVector::Not() const {
+ Builder builder(size());
+
+ // Append all words from all blocks except the last one.
+ uint32_t full_words = builder.BitsInCompleteWordsUntilFull();
+ for (uint32_t i = 0; i < full_words; ++i) {
+ builder.AppendWord(ConstBitWord(&words_[i]).Not());
+ }
+
+ // Append bits from the last word.
+ uint32_t bits_from_last_word = builder.BitsUntilFull();
+ ConstBitWord last_word(&words_[full_words]);
+ for (uint32_t i = 0; i < bits_from_last_word; ++i) {
+ builder.Append(!last_word.IsSet(i));
+ }
+
+ return std::move(builder).Build();
+}
+
void BitVector::UpdateSetBits(const BitVector& update) {
+ if (update.CountSetBits() == 0 || CountSetBits() == 0) {
+ *this = BitVector();
+ return;
+ }
PERFETTO_DCHECK(update.size() <= CountSetBits());
// Get the start and end ptrs for the current bitvector.
// Safe because of the static_assert above.
- auto* ptr = reinterpret_cast<uint64_t*>(words_.data());
- const uint64_t* ptr_end = ptr + WordCeil(size());
+ uint64_t* ptr = words_.data();
+ const uint64_t* ptr_end = ptr + WordCount(size());
- // Get the start and end ptrs for the current bitvector.
+ // Get the start and end ptrs for the update bitvector.
// Safe because of the static_assert above.
- auto* update_ptr = reinterpret_cast<const uint64_t*>(update.words_.data());
- const uint64_t* update_ptr_end = update_ptr + WordCeil(update.size());
+ const uint64_t* update_ptr = update.words_.data();
+ const uint64_t* update_ptr_end = update_ptr + WordCount(update.size());
// |update_unused_bits| contains |unused_bits_count| bits at the bottom
- // which indicates the how the next |unused_bits_count| set bits in |this|
+ // which indicates how the next |unused_bits_count| set bits in |this|
// should be changed. This is necessary because word boundaries in |this| will
// almost always *not* match the word boundaries in |update|.
uint64_t update_unused_bits = 0;
uint8_t unused_bits_count = 0;
- // The basic premise of this loop is, for each word in |this| we find the
+ // The basic premise of this loop is, for each word in |this| we find
// enough bits from |update| to cover every set bit in the word. We then use
// the PDEP x64 instruction (or equivalent instructions/software emulation) to
// update the word and store it back in |this|.
@@ -190,5 +283,47 @@ void BitVector::UpdateSetBits(const BitVector& update) {
PERFETTO_DCHECK(update.CountSetBits() == CountSetBits());
}
+BitVector BitVector::IntersectRange(uint32_t range_start,
+ uint32_t range_end) const {
+ uint32_t total_set_bits = CountSetBits();
+ if (total_set_bits == 0 || range_start >= range_end)
+ return BitVector();
+
+ // We should skip all bits until the index of first set bit bigger than
+ // |range_start|.
+ uint32_t start_idx = std::max(range_start, IndexOfNthSet(0));
+ uint32_t end_idx = std::min(range_end, size());
+
+ if (start_idx >= end_idx)
+ return BitVector();
+
+ Builder builder(end_idx);
+
+ // All bits before start should be empty.
+ builder.Skip(start_idx);
+
+ uint32_t front_bits = builder.BitsUntilWordBoundaryOrFull();
+ uint32_t cur_index = start_idx;
+ for (uint32_t i = 0; i < front_bits; ++i, ++cur_index) {
+ builder.Append(IsSet(cur_index));
+ }
+
+ PERFETTO_DCHECK(cur_index == end_idx || cur_index % BitWord::kBits == 0);
+ uint32_t cur_words = cur_index / BitWord::kBits;
+ uint32_t full_words = builder.BitsInCompleteWordsUntilFull() / BitWord::kBits;
+ uint32_t total_full_words = cur_words + full_words;
+ for (; cur_words < total_full_words; ++cur_words) {
+ builder.AppendWord(words_[cur_words]);
+ }
+
+ uint32_t last_bits = builder.BitsUntilFull();
+ cur_index += full_words * BitWord::kBits;
+ for (uint32_t i = 0; i < last_bits; ++i, ++cur_index) {
+ builder.Append(IsSet(cur_index));
+ }
+
+ return std::move(builder).Build();
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/containers/bit_vector.h b/src/trace_processor/containers/bit_vector.h
index 2855739b2..a9a5fbddc 100644
--- a/src/trace_processor/containers/bit_vector.h
+++ b/src/trace_processor/containers/bit_vector.h
@@ -23,6 +23,7 @@
#include <algorithm>
#include <array>
+#include <optional>
#include <vector>
#include "perfetto/base/logging.h"
@@ -45,13 +46,15 @@ class BitVector {
using AllBitsIterator = internal::AllBitsIterator;
using SetBitsIterator = internal::SetBitsIterator;
+ static constexpr uint32_t kBitsInWord = 64;
+
// Builder class which allows efficiently creating a BitVector by appending
// words. Using this class is generally far more efficient than trying to set
// bits directly in a BitVector or even appending one bit at a time.
class Builder {
public:
// Creates a Builder for building a BitVector of |size| bits.
- explicit Builder(uint32_t size) : words_(WordCeil(size)), size_(size) {}
+ explicit Builder(uint32_t size) : words_(WordCount(size)), size_(size) {}
// Skips forward |n| bits leaving them as zeroed.
void Skip(uint32_t n) {
@@ -86,17 +89,10 @@ class BitVector {
std::vector<uint32_t> counts(no_blocks);
// Calculate counts only for full blocks.
- for (uint32_t i = 1; i < no_blocks - 1; ++i) {
- counts[i] +=
- counts[i - 1] +
- ConstBlock(&words_[Block::kWords * (i - 1)]).CountSetBits();
- }
- if (size_ % Block::kBits == 0) {
- counts[no_blocks - 1] +=
- counts[no_blocks - 2] +
- ConstBlock(&words_[Block::kWords * (no_blocks - 2)]).CountSetBits();
+ for (uint32_t i = 1; i < no_blocks; ++i) {
+ counts[i] = counts[i - 1] +
+ ConstBlock(&words_[Block::kWords * (i - 1)]).CountSetBits();
}
-
return BitVector{std::move(words_), std::move(counts), size_};
}
@@ -104,7 +100,7 @@ class BitVector {
// appended to this builder before having to fallback to |Append| due to
// being close to the end.
uint32_t BitsInCompleteWordsUntilFull() {
- uint32_t next_word = WordCeil(global_bit_offset_);
+ uint32_t next_word = WordCount(global_bit_offset_);
uint32_t end_word = WordFloor(size_);
uint32_t complete_words = next_word < end_word ? end_word - next_word : 0;
return complete_words * BitWord::kBits;
@@ -150,24 +146,7 @@ class BitVector {
BitVector Copy() const;
// Create a bitwise Not copy of the bitvector.
- BitVector Not() const {
- Builder builder(size());
-
- // Append all words from all blocks except the last one.
- uint32_t full_words = size() / BitWord::kBits;
- for (uint32_t i = 0; i < full_words; ++i) {
- builder.AppendWord(ConstBitWord(&words_[i]).Not());
- }
-
- // Append bits from the last word.
- uint32_t bits_from_last_word = size() % BitWord::kBits;
- ConstBitWord last_word(&words_[full_words]);
- for (uint32_t i = 0; i < bits_from_last_word; ++i) {
- builder.Append(!last_word.IsSet(i));
- }
-
- return std::move(builder).Build();
- }
+ BitVector Not() const;
// Returns the size of the bitvector.
uint32_t size() const { return static_cast<uint32_t>(size_); }
@@ -298,75 +277,7 @@ class BitVector {
// Truncates the BitVector if |size| < |size()| or fills the new space with
// |filler| if |size| > |size()|. Calling this method is a noop if |size| ==
// |size()|.
- void Resize(uint32_t new_size, bool filler = false) {
- uint32_t old_size = size_;
- if (new_size == old_size)
- return;
-
- // Empty bitvectors should be memory efficient so we don't keep any data
- // around in the bitvector.
- if (new_size == 0) {
- words_.clear();
- counts_.clear();
- size_ = 0;
- return;
- }
-
- // Compute the address of the new last bit in the bitvector.
- Address last_addr = IndexToAddress(new_size - 1);
- uint32_t old_blocks_size = static_cast<uint32_t>(counts_.size());
- uint32_t new_blocks_size = last_addr.block_idx + 1;
-
- // Resize the block and count vectors to have the correct number of entries.
- words_.resize(Block::kWords * new_blocks_size);
- counts_.resize(new_blocks_size);
-
- if (new_size > old_size) {
- if (filler) {
- // If the new space should be filled with ones, then set all the bits
- // between the address of the old size and the new last address.
- const Address& start = IndexToAddress(old_size);
- Set(start, last_addr);
-
- // We then need to update the counts vector to match the changes we
- // made to the blocks.
-
- // We start by adding the bits we set in the first block to the
- // cummulative count before the range we changed.
- Address end_of_block = {start.block_idx,
- {Block::kWords - 1, BitWord::kBits - 1}};
- uint32_t count_in_block_after_end =
- AddressToIndex(end_of_block) - AddressToIndex(start) + 1;
- uint32_t set_count = CountSetBits() + count_in_block_after_end;
-
- for (uint32_t i = start.block_idx + 1; i <= last_addr.block_idx; ++i) {
- // Set the count to the cummulative count so far.
- counts_[i] = set_count;
-
- // Add a full block of set bits to the count.
- set_count += Block::kBits;
- }
- } else {
- // If the newly added bits are false, we just need to update the
- // counts vector with the current size of the bitvector for all
- // the newly added blocks.
- if (new_blocks_size > old_blocks_size) {
- uint32_t count = CountSetBits();
- for (uint32_t i = old_blocks_size; i < new_blocks_size; ++i) {
- counts_[i] = count;
- }
- }
- }
- } else {
- // Throw away all the bits after the new last bit. We do this to make
- // future lookup, append and resize operations not have to worrying about
- // trailing garbage bits in the last block.
- BlockFromIndex(last_addr.block_idx).ClearAfter(last_addr.block_offset);
- }
-
- // Actually update the size.
- size_ = new_size;
- }
+ void Resize(uint32_t new_size, bool filler = false);
// Creates a BitVector of size |end| with the bits between |start| and |end|
// filled by calling the filler function |f(index of bit)|.
@@ -378,7 +289,7 @@ class BitVector {
static BitVector Range(uint32_t start, uint32_t end, Filler f) {
// Compute the block index and bitvector index where we start and end
// working one block at a time.
- uint32_t start_fast_block = BlockCeil(start);
+ uint32_t start_fast_block = BlockCount(start);
uint32_t start_fast_idx = BlockToIndex(start_fast_block);
BitVector bv(start, false);
@@ -423,6 +334,10 @@ class BitVector {
return bv;
}
+ // Creates a BitVector of size |end| bit the bits between |start| and |end|
+ // filled with corresponding bits |this| BitVector.
+ BitVector IntersectRange(uint32_t range_start, uint32_t range_end) const;
+
// Requests the removal of unused capacity.
// Matches the semantics of std::vector::shrink_to_fit.
void ShrinkToFit() {
@@ -469,7 +384,7 @@ class BitVector {
static constexpr uint32_t ApproxBytesCost(uint32_t n) {
// The two main things making up a bitvector is the cost of the blocks of
// bits and the cost of the counts vector.
- return BlockCeil(n) * Block::kBits + BlockCeil(n) * sizeof(uint32_t);
+ return BlockCount(n) * Block::kBits + BlockCount(n) * sizeof(uint32_t);
}
private:
@@ -926,11 +841,10 @@ class BitVector {
return idx / BitWord::kBits;
}
- // Returns the number of words which would be required to store a bit at
- // |idx|.
- static uint32_t WordCeil(uint32_t idx) {
- // See |BlockCeil| for an explanation of this trick.
- return (idx + BitWord::kBits - 1) / BitWord::kBits;
+ // Returns number of words (int64_t) required to store |bit_count| bits.
+ static uint32_t WordCount(uint32_t bit_count) {
+ // See |BlockCount| for an explanation of this trick.
+ return (bit_count + BitWord::kBits - 1) / BitWord::kBits;
}
static Address IndexToAddress(uint32_t idx) {
@@ -949,17 +863,16 @@ class BitVector {
addr.block_offset.bit_idx;
}
- // Rounds |idx| up to the nearest block boundary and returns the block
- // index. If |idx| is already on a block boundary, the current block is
- // returned.
+ // Returns number of blocks (arrays of 8 int64_t) required to store
+ // |bit_count| bits.
//
// This is useful to be able to find indices where "fast" algorithms can
// start which work on entire blocks.
- static constexpr uint32_t BlockCeil(uint32_t idx) {
- // Adding |Block::kBits - 1| gives us a quick way to get the ceil. We
+ static constexpr uint32_t BlockCount(uint32_t bit_count) {
+ // Adding |Block::kBits - 1| gives us a quick way to get the count. We
// do this instead of adding 1 at the end because that gives incorrect
- // answers for index % Block::kBits == 0.
- return (idx + Block::kBits - 1) / Block::kBits;
+ // answers for bit_count % Block::kBits == 0.
+ return (bit_count + Block::kBits - 1) / Block::kBits;
}
// Returns the index of the block which would store |idx|.
diff --git a/src/trace_processor/containers/bit_vector_unittest.cc b/src/trace_processor/containers/bit_vector_unittest.cc
index c2e44805f..dd8c9512c 100644
--- a/src/trace_processor/containers/bit_vector_unittest.cc
+++ b/src/trace_processor/containers/bit_vector_unittest.cc
@@ -452,6 +452,63 @@ TEST(BitVectorUnittest, IterateSetBitsStartsCorrectly) {
ASSERT_FALSE(it);
}
+TEST(BitVectorUnittest, IntersectRange) {
+ BitVector bv = BitVector::Range(1, 20, [](uint32_t t) { return t % 2 == 0; });
+ BitVector intersected = bv.IntersectRange(3, 10);
+
+ ASSERT_EQ(intersected.IndexOfNthSet(0), 4u);
+ ASSERT_EQ(intersected.CountSetBits(), 3u);
+}
+
+TEST(BitVectorUnittest, IntersectRangeFromStart) {
+ BitVector bv = BitVector::Range(1, 20, [](uint32_t t) { return t % 2 == 0; });
+ BitVector intersected = bv.IntersectRange(0, 10);
+
+ ASSERT_EQ(intersected.IndexOfNthSet(0), 2u);
+ ASSERT_EQ(intersected.CountSetBits(), 4u);
+}
+
+TEST(BitVectorUnittest, IntersectRange2) {
+ BitVector bv{true, false, true, true, false, true};
+ BitVector intersected = bv.IntersectRange(2, 4);
+
+ ASSERT_EQ(intersected.IndexOfNthSet(0), 2u);
+}
+
+TEST(BitVectorUnittest, IntersectRangeAfterWord) {
+ BitVector bv =
+ BitVector::Range(64 + 1, 64 + 20, [](uint32_t t) { return t % 2 == 0; });
+ BitVector intersected = bv.IntersectRange(64 + 3, 64 + 10);
+
+ ASSERT_EQ(intersected.IndexOfNthSet(0), 64 + 4u);
+ ASSERT_EQ(intersected.CountSetBits(), 3u);
+}
+
+TEST(BitVectorUnittest, IntersectRangeSetBitsBeforeRange) {
+ BitVector bv = BitVector::Range(10, 30, [](uint32_t t) { return t < 15; });
+ BitVector intersected = bv.IntersectRange(16, 50);
+
+ ASSERT_FALSE(intersected.CountSetBits());
+}
+
+TEST(BitVectorUnittest, IntersectRangeSetBitOnBoundary) {
+ BitVector bv = BitVector(10, false);
+ bv.Set(5);
+ BitVector intersected = bv.IntersectRange(5, 20);
+
+ ASSERT_EQ(intersected.CountSetBits(), 1u);
+ ASSERT_EQ(intersected.IndexOfNthSet(0), 5u);
+}
+
+TEST(BitVectorUnittest, IntersectRangeStressTest) {
+ BitVector bv =
+ BitVector::Range(65, 1024 + 1, [](uint32_t t) { return t % 2 == 0; });
+ BitVector intersected = bv.IntersectRange(30, 500);
+
+ ASSERT_EQ(intersected.IndexOfNthSet(0), 66u);
+ ASSERT_EQ(intersected.CountSetBits(), 217u);
+}
+
TEST(BitVectorUnittest, Range) {
BitVector bv = BitVector::Range(1, 9, [](uint32_t t) { return t % 3 == 0; });
ASSERT_EQ(bv.size(), 9u);
@@ -515,6 +572,22 @@ TEST(BitVectorUnittest, Builder) {
ASSERT_FALSE(bv.IsSet(2));
}
+TEST(BitVectorUnittest, BuilderCountSetBits) {
+ // 16 words and 1 bit
+ BitVector::Builder builder(1025);
+
+ // 100100011010001010110011110001001 as a hex literal, with 15 set bits.
+ uint64_t word = 0x123456789;
+ for (uint32_t i = 0; i < 16; ++i) {
+ builder.AppendWord(word);
+ }
+ builder.Append(1);
+ BitVector bv = std::move(builder).Build();
+
+ ASSERT_EQ(bv.CountSetBits(500), 120u);
+ ASSERT_EQ(bv.CountSetBits(), 16 * 15 + 1u);
+}
+
TEST(BitVectorUnittest, BuilderStressTest) {
// Space for 128 words and 1 bit
uint32_t size = 8 * 1024 + 1;
@@ -533,7 +606,7 @@ TEST(BitVectorUnittest, BuilderStressTest) {
ASSERT_EQ(builder.BitsUntilFull(), size - 1024);
ASSERT_EQ(builder.BitsUntilWordBoundaryOrFull(), 0u);
- // 100100011010001010110011110001001 as a hex literal.
+ // 100100011010001010110011110001001 as a hex literal, with 15 set bits.
uint64_t word = 0x123456789;
// Add all of the remaining words.
@@ -550,6 +623,8 @@ TEST(BitVectorUnittest, BuilderStressTest) {
builder.Append(1);
BitVector bv = std::move(builder).Build();
+
+ ASSERT_EQ(bv.CountSetBits(), 2681u);
ASSERT_EQ(bv.size(), 8u * 1024u + 1u);
ASSERT_TRUE(bv.IsSet(0));
diff --git a/src/trace_processor/containers/row_map.cc b/src/trace_processor/containers/row_map.cc
index b3d1d59b9..d00d4877a 100644
--- a/src/trace_processor/containers/row_map.cc
+++ b/src/trace_processor/containers/row_map.cc
@@ -15,6 +15,7 @@
*/
#include "src/trace_processor/containers/row_map.h"
+#include <unordered_set>
#include "src/trace_processor/containers/row_map_algorithms.h"
@@ -23,22 +24,19 @@ namespace trace_processor {
namespace {
-RowMap SelectRangeWithRange(uint32_t start,
- uint32_t end,
- uint32_t selector_start,
- uint32_t selector_end) {
- PERFETTO_DCHECK(start <= end);
- PERFETTO_DCHECK(selector_start <= selector_end);
- PERFETTO_DCHECK(selector_end <= end - start);
+using Range = RowMap::Range;
+using OutputIndex = RowMap::OutputIndex;
+using Variant = std::variant<Range, BitVector, std::vector<OutputIndex>>;
- return RowMap(start + selector_start, start + selector_end);
+RowMap Select(Range range, Range selector) {
+ PERFETTO_DCHECK(selector.start <= selector.end);
+ PERFETTO_DCHECK(selector.end <= range.size());
+
+ return RowMap(range.start + selector.start, range.start + selector.end);
}
-RowMap SelectRangeWithBv(uint32_t start,
- uint32_t end,
- const BitVector& selector) {
- PERFETTO_DCHECK(start <= end);
- PERFETTO_DCHECK(selector.size() <= end - start);
+RowMap Select(Range range, const BitVector& selector) {
+ PERFETTO_DCHECK(selector.size() <= range.size());
// If |start| == 0 and |selector.size()| <= |end - start| (which is a
// precondition for this function), the BitVector we generate is going to be
@@ -48,60 +46,52 @@ RowMap SelectRangeWithBv(uint32_t start,
// SelectRows is called on all the table RowMaps with a BitVector. The self
// RowMap will always be a range so we expect this case to be hit at least
// once every filter operation.
- if (start == 0u)
+ if (range.start == 0u)
return RowMap(selector.Copy());
// We only need to resize to |start| + |selector.size()| as we know any rows
// not covered by |selector| are going to be removed below.
- BitVector bv(start, false);
- bv.Resize(start + selector.size(), true);
+ BitVector bv(range.start, false);
+ bv.Resize(range.start + selector.size(), true);
bv.UpdateSetBits(selector);
return RowMap(std::move(bv));
}
-RowMap SelectRangeWithIv(uint32_t start,
- uint32_t end,
- const std::vector<uint32_t>& selector) {
- PERFETTO_DCHECK(start <= end);
-
+RowMap Select(Range range, const std::vector<OutputIndex>& selector) {
std::vector<uint32_t> iv(selector.size());
for (uint32_t i = 0; i < selector.size(); ++i) {
- PERFETTO_DCHECK(selector[i] < end - start);
- iv[i] = selector[i] + start;
+ PERFETTO_DCHECK(selector[i] < range.size());
+ iv[i] = selector[i] + range.start;
}
return RowMap(std::move(iv));
}
-RowMap SelectBvWithRange(const BitVector& bv,
- uint32_t selector_start,
- uint32_t selector_end) {
- PERFETTO_DCHECK(selector_start <= selector_end);
- PERFETTO_DCHECK(selector_end <= bv.CountSetBits());
+RowMap Select(const BitVector& bv, Range selector) {
+ PERFETTO_DCHECK(selector.end <= bv.CountSetBits());
// If we're simply selecting every element in the bitvector, just
// return a copy of the BitVector without iterating.
BitVector ret = bv.Copy();
- if (selector_start == 0 && selector_end == bv.CountSetBits()) {
+ if (selector.start == 0 && selector.end == bv.CountSetBits()) {
return RowMap(std::move(ret));
}
for (auto it = ret.IterateSetBits(); it; it.Next()) {
auto set_idx = it.ordinal();
- if (set_idx < selector_start || set_idx >= selector_end)
+ if (set_idx < selector.start || set_idx >= selector.end)
it.Clear();
}
return RowMap(std::move(ret));
}
-RowMap SelectBvWithBv(const BitVector& bv, const BitVector& selector) {
+RowMap Select(const BitVector& bv, const BitVector& selector) {
BitVector ret = bv.Copy();
ret.UpdateSetBits(selector);
return RowMap(std::move(ret));
}
-RowMap SelectBvWithIv(const BitVector& bv,
- const std::vector<uint32_t>& selector) {
+RowMap Select(const BitVector& bv, const std::vector<uint32_t>& selector) {
// The value of this constant was found by considering the benchmarks
// |BM_SelectBvWithIvByConvertToIv| and |BM_SelectBvWithIvByIndexOfNthSet|.
//
@@ -130,21 +120,17 @@ RowMap SelectBvWithIv(const BitVector& bv,
row_map_algorithms::SelectBvWithIvByIndexOfNthSet(bv, selector));
}
-RowMap SelectIvWithRange(const std::vector<uint32_t>& iv,
- uint32_t selector_start,
- uint32_t selector_end) {
- PERFETTO_DCHECK(selector_start <= selector_end);
- PERFETTO_DCHECK(selector_end <= iv.size());
+RowMap Select(const std::vector<uint32_t>& iv, Range selector) {
+ PERFETTO_DCHECK(selector.end <= iv.size());
- std::vector<uint32_t> ret(selector_end - selector_start);
- for (uint32_t i = selector_start; i < selector_end; ++i) {
- ret[i - selector_start] = iv[i];
+ std::vector<uint32_t> ret(selector.size());
+ for (uint32_t i = selector.start; i < selector.end; ++i) {
+ ret[i - selector.start] = iv[i];
}
return RowMap(std::move(ret));
}
-RowMap SelectIvWithBv(const std::vector<uint32_t>& iv,
- const BitVector& selector) {
+RowMap Select(const std::vector<uint32_t>& iv, const BitVector& selector) {
PERFETTO_DCHECK(selector.size() <= iv.size());
std::vector<uint32_t> copy = iv;
@@ -158,83 +144,133 @@ RowMap SelectIvWithBv(const std::vector<uint32_t>& iv,
return RowMap(std::move(copy));
}
-RowMap SelectIvWithIv(const std::vector<uint32_t>& iv,
- const std::vector<uint32_t>& selector) {
+RowMap Select(const std::vector<uint32_t>& iv,
+ const std::vector<uint32_t>& selector) {
return RowMap(row_map_algorithms::SelectIvWithIv(iv, selector));
}
+Variant IntersectInternal(BitVector& first, const BitVector& second) {
+ for (auto set_bit = first.IterateSetBits(); set_bit; set_bit.Next()) {
+ if (!second.IsSet(set_bit.index()))
+ set_bit.Clear();
+ }
+ return std::move(first);
+}
+
+Variant IntersectInternal(Range first, Range second) {
+ // If both RowMaps have ranges, we can just take the smallest intersection
+ // of them as the new RowMap.
+ // We have this as an explicit fast path as this is very common for
+ // constraints on id and sorted columns to satisfy this condition.
+ OutputIndex start = std::max(first.start, second.start);
+ OutputIndex end = std::max(start, std::min(first.end, second.end));
+ return Range{start, end};
+}
+
+Variant IntersectInternal(std::vector<OutputIndex>& first,
+ const std::vector<OutputIndex>& second) {
+ std::unordered_set<OutputIndex> lookup(second.begin(), second.end());
+ first.erase(std::remove_if(first.begin(), first.end(),
+ [lookup](OutputIndex ind) {
+ return lookup.find(ind) == lookup.end();
+ }),
+ first.end());
+ return std::move(first);
+}
+
+Variant IntersectInternal(Range range, const BitVector& bv) {
+ return bv.IntersectRange(range.start, range.end);
+}
+
+Variant IntersectInternal(BitVector& bv, Range range) {
+ return IntersectInternal(range, bv);
+}
+
+Variant IntersectInternal(const std::vector<OutputIndex>& index_vec,
+ const BitVector& bv) {
+ std::vector<OutputIndex> new_vec(index_vec.begin(), index_vec.end());
+ new_vec.erase(std::remove_if(new_vec.begin(), new_vec.end(),
+ [&bv](uint32_t i) { return !bv.IsSet(i); }),
+ new_vec.end());
+ return std::move(new_vec);
+}
+
+Variant IntersectInternal(const BitVector& bv,
+ const std::vector<OutputIndex>& index_vec) {
+ return IntersectInternal(index_vec, bv);
+}
+
+Variant IntersectInternal(Range range,
+ const std::vector<OutputIndex>& index_vec) {
+ std::vector<OutputIndex> new_vec(index_vec.begin(), index_vec.end());
+ new_vec.erase(std::remove_if(new_vec.begin(), new_vec.end(),
+ [range](uint32_t i) {
+ return i < range.start || i >= range.end;
+ }),
+ new_vec.end());
+ return std::move(new_vec);
+}
+
+Variant IntersectInternal(const std::vector<OutputIndex>& index_vec,
+ Range range) {
+ return IntersectInternal(range, index_vec);
+}
+
} // namespace
-RowMap::RowMap() : RowMap(0, 0) {}
+RowMap::RowMap() : RowMap(Range()) {}
RowMap::RowMap(uint32_t start, uint32_t end, OptimizeFor optimize_for)
- : mode_(Mode::kRange),
- start_index_(start),
- end_index_(end),
- optimize_for_(optimize_for) {}
+ : data_(Range{start, end}), optimize_for_(optimize_for) {}
+
+RowMap::RowMap(Variant def) : data_(std::move(def)) {}
-RowMap::RowMap(BitVector bit_vector)
- : mode_(Mode::kBitVector), bit_vector_(std::move(bit_vector)) {}
+RowMap::RowMap(Range r) : data_(r) {}
-RowMap::RowMap(std::vector<uint32_t> vec)
- : mode_(Mode::kIndexVector), index_vector_(std::move(vec)) {}
+// Creates a RowMap backed by a BitVector.
+RowMap::RowMap(BitVector bit_vector) : data_(std::move(bit_vector)) {}
+
+// Creates a RowMap backed by an std::vector<uint32_t>.
+RowMap::RowMap(IndexVector vec) : data_(vec) {}
RowMap RowMap::Copy() const {
- switch (mode_) {
- case Mode::kRange:
- return RowMap(start_index_, end_index_);
- case Mode::kBitVector:
- return RowMap(bit_vector_.Copy());
- case Mode::kIndexVector:
- return RowMap(index_vector_);
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return RowMap(*range);
+ }
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return RowMap(bv->Copy());
}
- PERFETTO_FATAL("For GCC");
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return RowMap(*vec);
+ }
+ NoVariantMatched();
}
RowMap RowMap::SelectRowsSlow(const RowMap& selector) const {
- // Pick the strategy based on the selector as there is more common code
- // between selectors of the same mode than between the RowMaps being
- // selected of the same mode.
- switch (selector.mode_) {
- case Mode::kRange:
- switch (mode_) {
- case Mode::kRange:
- return SelectRangeWithRange(start_index_, end_index_,
- selector.start_index_,
- selector.end_index_);
- case Mode::kBitVector:
- return SelectBvWithRange(bit_vector_, selector.start_index_,
- selector.end_index_);
- case Mode::kIndexVector:
- return SelectIvWithRange(index_vector_, selector.start_index_,
- selector.end_index_);
- }
- break;
- case Mode::kBitVector:
- switch (mode_) {
- case Mode::kRange:
- return SelectRangeWithBv(start_index_, end_index_,
- selector.bit_vector_);
- case Mode::kBitVector:
- return SelectBvWithBv(bit_vector_, selector.bit_vector_);
- case Mode::kIndexVector:
- return SelectIvWithBv(index_vector_, selector.bit_vector_);
- }
- break;
- case Mode::kIndexVector:
- switch (mode_) {
- case Mode::kRange:
- return SelectRangeWithIv(start_index_, end_index_,
- selector.index_vector_);
- case Mode::kBitVector:
- return SelectBvWithIv(bit_vector_, selector.index_vector_);
- case Mode::kIndexVector:
- return SelectIvWithIv(index_vector_, selector.index_vector_);
- }
- break;
- }
- PERFETTO_FATAL("For GCC");
+ return std::visit(
+ [](const auto& def, const auto& selector_def) {
+ return Select(def, selector_def);
+ },
+ data_, selector.data_);
+}
+
+void RowMap::Intersect(const RowMap& second) {
+ data_ = std::visit(
+ [](auto& def, auto& selector_def) {
+ return IntersectInternal(def, selector_def);
+ },
+ data_, second.data_);
}
+RowMap::Iterator::Iterator(const RowMap* rm) : rm_(rm) {
+ if (auto* range = std::get_if<Range>(&rm_->data_)) {
+ ordinal_ = range->start;
+ return;
+ }
+ if (auto* bv = std::get_if<BitVector>(&rm_->data_)) {
+ set_bits_it_.reset(new BitVector::SetBitsIterator(bv->IterateSetBits()));
+ return;
+ }
+}
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/containers/row_map.h b/src/trace_processor/containers/row_map.h
index 8ab3915bf..283455c29 100644
--- a/src/trace_processor/containers/row_map.h
+++ b/src/trace_processor/containers/row_map.h
@@ -21,6 +21,7 @@
#include <memory>
#include <optional>
+#include <variant>
#include <vector>
#include "perfetto/base/logging.h"
@@ -73,56 +74,25 @@ namespace trace_processor {
// more efficient than a BitVector; in this case, we will make a best effort
// switch to it but the cases where this happens is not precisely defined.
class RowMap {
- private:
- // We need to declare these iterator classes before RowMap::Iterator as it
- // depends on them. However, we don't want to make these public so keep them
- // under a special private section.
-
- // Iterator for ranged mode of RowMap.
- // This class should act as a drop-in replacement for
- // BitVector::SetBitsIterator.
- class RangeIterator {
- public:
- RangeIterator(const RowMap* rm) : rm_(rm), index_(rm->start_index_) {}
-
- void Next() { ++index_; }
-
- operator bool() const { return index_ < rm_->end_index_; }
-
- uint32_t index() const { return index_; }
-
- uint32_t ordinal() const { return index_ - rm_->start_index_; }
-
- private:
- const RowMap* rm_ = nullptr;
- uint32_t index_ = 0;
- };
-
- // Iterator for index vector mode of RowMap.
- // This class should act as a drop-in replacement for
- // BitVector::SetBitsIterator.
- class IndexVectorIterator {
- public:
- IndexVectorIterator(const RowMap* rm) : rm_(rm) {}
-
- void Next() { ++ordinal_; }
-
- operator bool() const { return ordinal_ < rm_->index_vector_.size(); }
+ public:
+ using InputRow = uint32_t;
+ using OutputIndex = uint32_t;
+ using IndexVector = std::vector<OutputIndex>;
- uint32_t index() const { return rm_->index_vector_[ordinal_]; }
+ struct Range {
+ Range(OutputIndex start_index, OutputIndex end_index)
+ : start(start_index), end(end_index) {}
+ Range() : start(0), end(0) {}
- uint32_t ordinal() const { return ordinal_; }
+ OutputIndex start = 0; // This is an inclusive index.
+ OutputIndex end = 0; // This is an exclusive index.
- private:
- const RowMap* rm_ = nullptr;
- uint32_t ordinal_ = 0;
+ uint32_t size() const {
+ PERFETTO_DCHECK(end >= start);
+ return end - start;
+ }
};
- public:
- // Input type.
- using InputRow = uint32_t;
- using OutputIndex = uint32_t;
-
// Allows efficient iteration over the rows of a RowMap.
//
// Note: you should usually prefer to use the methods on RowMap directly (if
@@ -130,87 +100,72 @@ class RowMap {
// of the RowMap on every method call.
class Iterator {
public:
- Iterator(const RowMap* rm) : rm_(rm) {
- switch (rm->mode_) {
- case Mode::kRange:
- range_it_.reset(new RangeIterator(rm));
- break;
- case Mode::kBitVector:
- set_bits_it_.reset(
- new BitVector::SetBitsIterator(rm->bit_vector_.IterateSetBits()));
- break;
- case Mode::kIndexVector:
- iv_it_.reset(new IndexVectorIterator(rm));
- break;
- }
- }
+ explicit Iterator(const RowMap* rm);
Iterator(Iterator&&) noexcept = default;
Iterator& operator=(Iterator&&) = default;
// Forwards the iterator to the next row of the RowMap.
void Next() {
- switch (rm_->mode_) {
- case Mode::kRange:
- range_it_->Next();
- break;
- case Mode::kBitVector:
- set_bits_it_->Next();
- break;
- case Mode::kIndexVector:
- iv_it_->Next();
- break;
+ if (std::get_if<Range>(&rm_->data_)) {
+ ++ordinal_;
+ } else if (std::get_if<BitVector>(&rm_->data_)) {
+ set_bits_it_->Next();
+ } else if (std::get_if<IndexVector>(&rm_->data_)) {
+ ++ordinal_;
}
}
// Returns if the iterator is still valid.
operator bool() const {
- switch (rm_->mode_) {
- case Mode::kRange:
- return *range_it_;
- case Mode::kBitVector:
- return *set_bits_it_;
- case Mode::kIndexVector:
- return *iv_it_;
+ if (auto* range = std::get_if<Range>(&rm_->data_)) {
+ return ordinal_ < range->end;
+ }
+ if (std::get_if<BitVector>(&rm_->data_)) {
+ return bool(*set_bits_it_);
+ }
+ if (auto* vec = std::get_if<IndexVector>(&rm_->data_)) {
+ return ordinal_ < vec->size();
}
- PERFETTO_FATAL("For GCC");
+ PERFETTO_FATAL("Didn't match any variant type.");
}
// Returns the index pointed to by this iterator.
OutputIndex index() const {
- switch (rm_->mode_) {
- case Mode::kRange:
- return range_it_->index();
- case Mode::kBitVector:
- return set_bits_it_->index();
- case Mode::kIndexVector:
- return iv_it_->index();
+ if (std::get_if<Range>(&rm_->data_)) {
+ return ordinal_;
}
- PERFETTO_FATAL("For GCC");
+ if (std::get_if<BitVector>(&rm_->data_)) {
+ return set_bits_it_->index();
+ }
+ if (auto* vec = std::get_if<IndexVector>(&rm_->data_)) {
+ return (*vec)[ordinal_];
+ }
+ PERFETTO_FATAL("Didn't match any variant type.");
}
// Returns the row of the index the iterator points to.
InputRow row() const {
- switch (rm_->mode_) {
- case Mode::kRange:
- return range_it_->ordinal();
- case Mode::kBitVector:
- return set_bits_it_->ordinal();
- case Mode::kIndexVector:
- return iv_it_->ordinal();
+ if (auto* range = std::get_if<Range>(&rm_->data_)) {
+ return ordinal_ - range->start;
+ }
+ if (std::get_if<BitVector>(&rm_->data_)) {
+ return set_bits_it_->ordinal();
}
- PERFETTO_FATAL("For GCC");
+ if (std::get_if<IndexVector>(&rm_->data_)) {
+ return ordinal_;
+ }
+ PERFETTO_FATAL("Didn't match any variant type.");
}
private:
Iterator(const Iterator&) = delete;
Iterator& operator=(const Iterator&) = delete;
- // Only one of the below will be non-null depending on the mode of the
- // RowMap.
- std::unique_ptr<RangeIterator> range_it_;
+ // Ordinal will not be used for BitVector based RowMap.
+ uint32_t ordinal_ = 0;
+ // Not nullptr for BitVector based RowMap.
std::unique_ptr<BitVector::SetBitsIterator> set_bits_it_;
- std::unique_ptr<IndexVectorIterator> iv_it_;
const RowMap* rm_ = nullptr;
};
@@ -228,15 +183,15 @@ class RowMap {
// Creates a RowMap containing the range of indices between |start| and |end|
// i.e. all indices between |start| (inclusive) and |end| (exclusive).
- explicit RowMap(OutputIndex start,
- OutputIndex end,
- OptimizeFor optimize_for = OptimizeFor::kMemory);
+ RowMap(OutputIndex start,
+ OutputIndex end,
+ OptimizeFor optimize_for = OptimizeFor::kMemory);
// Creates a RowMap backed by a BitVector.
- explicit RowMap(BitVector bit_vector);
+ explicit RowMap(BitVector);
// Creates a RowMap backed by an std::vector<uint32_t>.
- explicit RowMap(std::vector<OutputIndex> vec);
+ explicit RowMap(IndexVector);
RowMap(const RowMap&) noexcept = delete;
RowMap& operator=(const RowMap&) = delete;
@@ -259,15 +214,16 @@ class RowMap {
// Returns the size of the RowMap; that is the number of indices in the
// RowMap.
uint32_t size() const {
- switch (mode_) {
- case Mode::kRange:
- return end_index_ - start_index_;
- case Mode::kBitVector:
- return bit_vector_.CountSetBits();
- case Mode::kIndexVector:
- return static_cast<uint32_t>(index_vector_.size());
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return range->size();
}
- PERFETTO_FATAL("For GCC");
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return bv->CountSetBits();
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return static_cast<uint32_t>(vec->size());
+ }
+ NoVariantMatched();
}
// Returns whether this rowmap is empty.
@@ -275,57 +231,51 @@ class RowMap {
// Returns the index at the given |row|.
OutputIndex Get(InputRow row) const {
- PERFETTO_DCHECK(row < size());
- switch (mode_) {
- case Mode::kRange:
- return GetRange(row);
- case Mode::kBitVector:
- return GetBitVector(row);
- case Mode::kIndexVector:
- return GetIndexVector(row);
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return GetRange(*range, row);
+ }
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return GetBitVector(*bv, row);
}
- PERFETTO_FATAL("For GCC");
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return GetIndexVector(*vec, row);
+ }
+ NoVariantMatched();
}
// Returns whether the RowMap contains the given index.
bool Contains(OutputIndex index) const {
- switch (mode_) {
- case Mode::kRange: {
- return index >= start_index_ && index < end_index_;
- }
- case Mode::kBitVector: {
- return index < bit_vector_.size() && bit_vector_.IsSet(index);
- }
- case Mode::kIndexVector: {
- auto it = std::find(index_vector_.begin(), index_vector_.end(), index);
- return it != index_vector_.end();
- }
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return index >= range->start && index < range->end;
+ }
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return index < bv->size() && bv->IsSet(index);
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return std::find(vec->begin(), vec->end(), index) != vec->end();
}
- PERFETTO_FATAL("For GCC");
+ NoVariantMatched();
}
// Returns the first row of the given |index| in the RowMap.
std::optional<InputRow> RowOf(OutputIndex index) const {
- switch (mode_) {
- case Mode::kRange: {
- if (index < start_index_ || index >= end_index_)
- return std::nullopt;
- return index - start_index_;
- }
- case Mode::kBitVector: {
- return index < bit_vector_.size() && bit_vector_.IsSet(index)
- ? std::make_optional(bit_vector_.CountSetBits(index))
- : std::nullopt;
- }
- case Mode::kIndexVector: {
- auto it = std::find(index_vector_.begin(), index_vector_.end(), index);
- return it != index_vector_.end()
- ? std::make_optional(static_cast<InputRow>(
- std::distance(index_vector_.begin(), it)))
- : std::nullopt;
- }
+ if (auto* range = std::get_if<Range>(&data_)) {
+ if (index < range->start || index >= range->end)
+ return std::nullopt;
+ return index - range->start;
+ }
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return index < bv->size() && bv->IsSet(index)
+ ? std::make_optional(bv->CountSetBits(index))
+ : std::nullopt;
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ auto it = std::find(vec->begin(), vec->end(), index);
+ return it != vec->end() ? std::make_optional(static_cast<InputRow>(
+ std::distance(vec->begin(), it)))
+ : std::nullopt;
}
- PERFETTO_FATAL("For GCC");
+ NoVariantMatched();
}
// Performs an ordered insert of the index into the current RowMap
@@ -343,34 +293,36 @@ class RowMap {
// the RowMap is in range or BitVector mode but is a required condition for
// IndexVector mode.
void Insert(OutputIndex index) {
- switch (mode_) {
- case Mode::kRange:
- if (index == end_index_) {
- // Fast path: if we're just appending to the end of the range, we can
- // stay in range mode and just bump the end index.
- end_index_++;
- } else {
- // Slow path: the insert is somewhere else other than the end. This
- // means we need to switch to using a BitVector instead.
- bit_vector_.Resize(start_index_, false);
- bit_vector_.Resize(end_index_, true);
- *this = RowMap(std::move(bit_vector_));
-
- InsertIntoBitVector(index);
- }
- break;
- case Mode::kBitVector:
- InsertIntoBitVector(index);
- break;
- case Mode::kIndexVector: {
- PERFETTO_DCHECK(
- std::is_sorted(index_vector_.begin(), index_vector_.end()));
- auto it =
- std::upper_bound(index_vector_.begin(), index_vector_.end(), index);
- index_vector_.insert(it, index);
- break;
+ if (auto* range = std::get_if<Range>(&data_)) {
+ if (index == range->end) {
+ // Fast path: if we're just appending to the end
+ // of the range, we can stay in range mode and
+ // just bump the end index.
+ range->end++;
+ return;
}
+
+ // Slow path: the insert is somewhere else other
+ // than the end. This means we need to switch to
+ // using a BitVector instead.
+ BitVector bv;
+ bv.Resize(range->start, false);
+ bv.Resize(range->end, true);
+ InsertIntoBitVector(bv, index);
+ data_ = std::move(bv);
+ return;
+ }
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ InsertIntoBitVector(*bv, index);
+ return;
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ PERFETTO_DCHECK(std::is_sorted(vec->begin(), vec->end()));
+ auto it = std::upper_bound(vec->begin(), vec->end(), index);
+ vec->insert(it, index);
+ return;
}
+ NoVariantMatched();
}
// Updates this RowMap by 'picking' the indices given by |picker|.
@@ -413,22 +365,7 @@ class RowMap {
// if (start_index <= idx && idx < end_index)
// continue;
// Remove(idx)
- void Intersect(uint32_t start_index, uint32_t end_index) {
- if (mode_ == Mode::kRange) {
- // If both RowMaps have ranges, we can just take the smallest intersection
- // of them as the new RowMap.
- // We have this as an explicit fast path as this is very common for
- // constraints on id and sorted columns to satisfy this condition.
- start_index_ = std::max(start_index_, start_index);
- end_index_ = std::max(start_index_, std::min(end_index_, end_index));
- return;
- }
-
- // TODO(lalitm): improve efficiency of this if we end up needing it.
- Filter([start_index, end_index](OutputIndex index) {
- return index >= start_index && index < end_index;
- });
- }
+ void Intersect(const RowMap& second);
// Intersects this RowMap with |index|. If this RowMap contained |index|, then
// it will *only* contain |index|. Otherwise, it will be empty.
@@ -444,71 +381,82 @@ class RowMap {
void Clear() { *this = RowMap(); }
template <typename Comparator = bool(uint32_t, uint32_t)>
- void StableSort(std::vector<uint32_t>* out, Comparator c) const {
- switch (mode_) {
- case Mode::kRange:
- std::stable_sort(out->begin(), out->end(),
- [this, c](uint32_t a, uint32_t b) {
- return c(GetRange(a), GetRange(b));
- });
- break;
- case Mode::kBitVector:
- std::stable_sort(out->begin(), out->end(),
- [this, c](uint32_t a, uint32_t b) {
- return c(GetBitVector(a), GetBitVector(b));
- });
- break;
- case Mode::kIndexVector:
- std::stable_sort(out->begin(), out->end(),
- [this, c](uint32_t a, uint32_t b) {
- return c(GetIndexVector(a), GetIndexVector(b));
- });
- break;
+ void StableSort(IndexVector* out, Comparator c) const {
+ if (auto* range = std::get_if<Range>(&data_)) {
+ std::stable_sort(out->begin(), out->end(),
+ [range, c](uint32_t a, uint32_t b) {
+ return c(GetRange(*range, a), GetRange(*range, b));
+ });
+ return;
+ }
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ std::stable_sort(out->begin(), out->end(),
+ [&bv, c](uint32_t a, uint32_t b) {
+ return c(GetBitVector(*bv, a), GetBitVector(*bv, b));
+ });
+ return;
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ std::stable_sort(
+ out->begin(), out->end(), [vec, c](uint32_t a, uint32_t b) {
+ return c(GetIndexVector(*vec, a), GetIndexVector(*vec, b));
+ });
+ return;
}
+ NoVariantMatched();
}
// Filters the indices in |out| by keeping those which meet |p|.
template <typename Predicate = bool(OutputIndex)>
void Filter(Predicate p) {
- switch (mode_) {
- case Mode::kRange:
- FilterRange(p);
- break;
- case Mode::kBitVector: {
- for (auto it = bit_vector_.IterateSetBits(); it; it.Next()) {
- if (!p(it.index()))
- it.Clear();
- }
- break;
- }
- case Mode::kIndexVector: {
- auto ret = std::remove_if(index_vector_.begin(), index_vector_.end(),
- [p](uint32_t i) { return !p(i); });
- index_vector_.erase(ret, index_vector_.end());
- break;
+ if (auto* range = std::get_if<Range>(&data_)) {
+ data_ = FilterRange(p, *range);
+ return;
+ }
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ for (auto it = bv->IterateSetBits(); it; it.Next()) {
+ if (!p(it.index()))
+ it.Clear();
}
+ return;
}
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ auto ret = std::remove_if(vec->begin(), vec->end(),
+ [p](uint32_t i) { return !p(i); });
+ vec->erase(ret, vec->end());
+ return;
+ }
+ NoVariantMatched();
}
// Returns the iterator over the rows in this RowMap.
Iterator IterateRows() const { return Iterator(this); }
// Returns if the RowMap is internally represented using a range.
- bool IsRange() const { return mode_ == Mode::kRange; }
+ bool IsRange() const { return std::holds_alternative<Range>(data_); }
+
+ // Returns if the RowMap is internally represented using a BitVector.
+ bool IsBitVector() const { return std::holds_alternative<BitVector>(data_); }
+
+ // Returns if the RowMap is internally represented using an index vector.
+ bool IsIndexVector() const {
+ return std::holds_alternative<IndexVector>(data_);
+ }
private:
- enum class Mode {
- kRange,
- kBitVector,
- kIndexVector,
- };
+ using Variant = std::variant<Range, BitVector, IndexVector>;
+
+ explicit RowMap(Range);
+
+ explicit RowMap(Variant);
+
// TODO(lalitm): remove this when the coupling between RowMap and
// ColumnStorage Selector is broken (after filtering is moved out of here).
friend class ColumnStorageOverlay;
template <typename Predicate>
- void FilterRange(Predicate p) {
- uint32_t count = end_index_ - start_index_;
+ Variant FilterRange(Predicate p, Range r) {
+ uint32_t count = r.size();
// Optimization: if we are only going to scan a few indices, it's not
// worth the haslle of working with a BitVector.
@@ -517,7 +465,7 @@ class RowMap {
// Optimization: weif the cost of a BitVector is more than the highest
// possible cost an index vector could have, use the index vector.
- uint32_t bit_vector_cost = BitVector::ApproxBytesCost(end_index_);
+ uint32_t bit_vector_cost = BitVector::ApproxBytesCost(r.end);
uint32_t index_vector_cost_ub = sizeof(uint32_t) * count;
// If either of the conditions hold which make it better to use an
@@ -527,7 +475,7 @@ class RowMap {
optimize_for_ == OptimizeFor::kLookupSpeed) {
// Try and strike a good balance between not making the vector too
// big and good performance.
- std::vector<uint32_t> iv(std::min(kSmallRangeLimit, count));
+ IndexVector iv(std::min(kSmallRangeLimit, count));
uint32_t out_i = 0;
for (uint32_t i = 0; i < count; ++i) {
@@ -537,8 +485,8 @@ class RowMap {
// We keep this branch free by always writing the index but only
// incrementing the out index if the return value is true.
- bool value = p(i + start_index_);
- iv[out_i] = i + start_index_;
+ bool value = p(i + r.start);
+ iv[out_i] = i + r.start;
out_i += value;
}
@@ -546,58 +494,44 @@ class RowMap {
iv.resize(out_i);
iv.shrink_to_fit();
- *this = RowMap(std::move(iv));
- return;
+ return std::move(iv);
}
// Otherwise, create a bitvector which spans the full range using
// |p| as the filler for the bits between start and end.
- *this = RowMap(BitVector::Range(start_index_, end_index_, p));
- }
-
- void InsertIntoBitVector(uint32_t row) {
- PERFETTO_DCHECK(mode_ == Mode::kBitVector);
-
- // If we're adding a row to precisely the end of the BitVector, just append
- // true instead of resizing and then setting.
- if (row == bit_vector_.size()) {
- bit_vector_.AppendTrue();
- return;
- }
-
- if (row > bit_vector_.size()) {
- bit_vector_.Resize(row + 1, false);
- }
- bit_vector_.Set(row);
+ return BitVector::Range(r.start, r.end, p);
}
- PERFETTO_ALWAYS_INLINE OutputIndex GetRange(InputRow row) const {
- PERFETTO_DCHECK(mode_ == Mode::kRange);
- return start_index_ + row;
+ PERFETTO_ALWAYS_INLINE static OutputIndex GetRange(Range r, InputRow row) {
+ return r.start + row;
}
- PERFETTO_ALWAYS_INLINE OutputIndex GetBitVector(uint32_t row) const {
- PERFETTO_DCHECK(mode_ == Mode::kBitVector);
- return bit_vector_.IndexOfNthSet(row);
+ PERFETTO_ALWAYS_INLINE static OutputIndex GetBitVector(const BitVector& bv,
+ uint32_t row) {
+ return bv.IndexOfNthSet(row);
}
- PERFETTO_ALWAYS_INLINE OutputIndex GetIndexVector(uint32_t row) const {
- PERFETTO_DCHECK(mode_ == Mode::kIndexVector);
- return index_vector_[row];
+ PERFETTO_ALWAYS_INLINE static OutputIndex GetIndexVector(
+ const IndexVector& vec,
+ uint32_t row) {
+ return vec[row];
}
RowMap SelectRowsSlow(const RowMap& selector) const;
- Mode mode_ = Mode::kRange;
-
- // Only valid when |mode_| == Mode::kRange.
- OutputIndex start_index_ = 0; // This is an inclusive index.
- OutputIndex end_index_ = 0; // This is an exclusive index.
-
- // Only valid when |mode_| == Mode::kBitVector.
- BitVector bit_vector_;
+ static void InsertIntoBitVector(BitVector& bv, OutputIndex row) {
+ if (row == bv.size()) {
+ bv.AppendTrue();
+ return;
+ }
+ if (row > bv.size())
+ bv.Resize(row + 1, false);
+ bv.Set(row);
+ }
- // Only valid when |mode_| == Mode::kIndexVector.
- std::vector<OutputIndex> index_vector_;
+ PERFETTO_NORETURN void NoVariantMatched() const {
+ PERFETTO_FATAL("Didn't match any variant type.");
+ }
+ Variant data_;
OptimizeFor optimize_for_ = OptimizeFor::kMemory;
};
diff --git a/src/trace_processor/containers/row_map_unittest.cc b/src/trace_processor/containers/row_map_unittest.cc
index 6e1ca1113..7f919bdb8 100644
--- a/src/trace_processor/containers/row_map_unittest.cc
+++ b/src/trace_processor/containers/row_map_unittest.cc
@@ -25,6 +25,191 @@ namespace perfetto {
namespace trace_processor {
namespace {
+TEST(RowMapUnittest, SingleRow) {
+ RowMap rm(10, 20);
+ RowMap rm_row = rm.SingleRow(15u);
+ ASSERT_EQ(rm_row.size(), 1u);
+ ASSERT_TRUE(rm_row.Contains(15));
+ ASSERT_FALSE(rm_row.Contains(11));
+}
+
+TEST(RowMapUnittest, CopyRange) {
+ RowMap rm(10, 20);
+ RowMap rm_copy = rm.Copy();
+ ASSERT_EQ(rm_copy.size(), 10u);
+}
+
+TEST(RowMapUnittest, CopyBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ RowMap rm_copy = rm.Copy();
+ ASSERT_EQ(rm_copy.size(), 3u);
+}
+
+TEST(RowMapUnittest, CopyIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ RowMap rm_copy = rm.Copy();
+ ASSERT_EQ(rm_copy.size(), 4u);
+}
+
+TEST(RowMapUnittest, GetFromRange) {
+ RowMap rm(10, 20);
+ ASSERT_EQ(rm.Get(5), 15u);
+}
+
+TEST(RowMapUnittest, GetFromBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ ASSERT_EQ(rm.Get(1), 4u);
+}
+
+TEST(RowMapUnittest, GetFromIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ ASSERT_EQ(rm.Get(1), 17u);
+}
+
+TEST(RowMapUnittest, ContainsFromRange) {
+ RowMap rm(10, 20);
+ ASSERT_FALSE(rm.Contains(5));
+ ASSERT_TRUE(rm.Contains(15));
+}
+
+TEST(RowMapUnittest, ContainsFromBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ ASSERT_FALSE(rm.Contains(3));
+ ASSERT_TRUE(rm.Contains(5));
+}
+
+TEST(RowMapUnittest, ContainsFromIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ ASSERT_FALSE(rm.Contains(5));
+ ASSERT_TRUE(rm.Contains(10));
+}
+
+TEST(RowMapUnittest, RowOfRange) {
+ RowMap rm(10, 20);
+ ASSERT_EQ(rm.RowOf(15).value(), 5u);
+ ASSERT_EQ(rm.RowOf(5), std::nullopt);
+}
+
+TEST(RowMapUnittest, RowOfBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ ASSERT_EQ(rm.RowOf(4), 1u);
+ ASSERT_EQ(rm.RowOf(1), std::nullopt);
+}
+
+TEST(RowMapUnittest, RowOfIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ ASSERT_EQ(rm.RowOf(17), 1u);
+ ASSERT_EQ(rm.RowOf(5), std::nullopt);
+}
+
+TEST(RowMapUnittest, InsertIntoRangeAtTheEnd) {
+ RowMap rm(10, 20);
+ rm.Insert(21);
+ ASSERT_EQ(rm.size(), 11u);
+ ASSERT_TRUE(rm.Contains(21));
+}
+
+TEST(RowMapUnittest, InsertIntoRange) {
+ RowMap rm(10, 20);
+ rm.Insert(25);
+ ASSERT_EQ(rm.size(), 11u);
+ ASSERT_TRUE(rm.Contains(25));
+}
+
+TEST(RowMapUnittest, InsertIntoBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ rm.Insert(25);
+ ASSERT_EQ(rm.size(), 4u);
+ ASSERT_TRUE(rm.Contains(25));
+}
+
+TEST(RowMapUnittest, InsertIntoIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ rm.Insert(25);
+ ASSERT_EQ(rm.size(), 5u);
+ ASSERT_TRUE(rm.Contains(25));
+}
+
+TEST(RowMapUnittest, SelectRowsFromRangeWithRange) {
+ RowMap rm(10, 20);
+
+ RowMap selector(4, 8);
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 4u);
+ ASSERT_EQ(selected.Get(0), 14u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromRangeWithBV) {
+ RowMap rm(10, 20);
+ // BitVector with values at 16, 18, 20 and so on.
+ RowMap selector(
+ BitVector::Range(4, 8, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 14u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromRangeWithIV) {
+ RowMap rm(10, 20);
+ RowMap selector(std::vector<uint32_t>{4, 6});
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 14u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromBVWithRange) {
+ RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+
+ RowMap selector(4, 8);
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 4u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromBVWithBV) {
+ RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+ // BitVector with values at 16, 18, 20 and so on.
+ RowMap selector(
+ BitVector::Range(4, 8, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromBVWithIV) {
+ RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selector(std::vector<uint32_t>{4, 6});
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromIVWithRange) {
+ RowMap rm(std::vector<uint32_t>{10, 12, 14, 16, 18, 20, 22, 24});
+
+ RowMap selector(4, 8);
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 4u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromIVWithBV) {
+ RowMap rm(std::vector<uint32_t>{10, 12, 14, 16, 18, 20, 22, 24});
+ RowMap selector(
+ BitVector::Range(4, 8, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromIVWithIV) {
+ RowMap rm(std::vector<uint32_t>{10, 12, 14, 16, 18, 20, 22, 24});
+ RowMap selector(std::vector<uint32_t>{4, 6});
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
TEST(RowMapUnittest, SmokeRange) {
RowMap rm(30, 47);
@@ -327,22 +512,86 @@ TEST(RowMapUnittest, IntersectSingleAbsent) {
ASSERT_EQ(rm.size(), 0u);
}
-TEST(RowMapUnittest, IntersectManyRange) {
+TEST(RowMapUnittest, IntersectRangeWithRange) {
RowMap rm(3, 7);
- rm.Intersect(2, 4);
+ RowMap sec(2, 4);
+ rm.Intersect(sec);
ASSERT_EQ(rm.size(), 1u);
ASSERT_EQ(rm.Get(0u), 3u);
}
-TEST(RowMapUnittest, IntersectManyIv) {
- RowMap rm(std::vector<uint32_t>{3u, 2u, 0u, 1u, 1u, 3u});
- rm.Intersect(2, 4);
+TEST(RowMapUnittest, IntersectRangeWithBV) {
+ RowMap rm(2, 4);
+ RowMap sec(BitVector{true, false, true, true, false, true});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0), 2u);
+}
+
+TEST(RowMapUnittest, IntersectRangeWithIV) {
+ RowMap rm(2, 10);
+ RowMap sec(std::vector<uint32_t>{0, 2, 5});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0u), 2u);
+}
+
+TEST(RowMapUnittest, IntersectBVWithRange) {
+ RowMap rm(BitVector{true, false, true, true, false, true});
+ RowMap sec(2, 4);
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0), 2u);
+}
+
+TEST(RowMapUnittest, IntersectBVWithBV) {
+ RowMap rm(BitVector{true, false, true, true, false, true});
+ RowMap sec(BitVector{false, true, true, false, false, true, true});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0), 2u);
+}
+
+TEST(RowMapUnittest, IntersectBVWithIV) {
+ RowMap rm(BitVector{true, false, true, true, false, true});
+ RowMap sec(std::vector<uint32_t>{0, 2, 5});
+ rm.Intersect(sec);
ASSERT_EQ(rm.size(), 3u);
- ASSERT_EQ(rm.Get(0u), 3u);
- ASSERT_EQ(rm.Get(1u), 2u);
- ASSERT_EQ(rm.Get(2u), 3u);
+ ASSERT_EQ(rm.Get(0), 0u);
+}
+
+TEST(RowMapUnittest, IntersectIVWithRange) {
+ RowMap rm(std::vector<uint32_t>{0, 2, 5});
+ RowMap sec(2, 10);
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0u), 2u);
+}
+
+TEST(RowMapUnittest, IntersectIVWithBV) {
+ RowMap rm(std::vector<uint32_t>{0, 2, 5});
+ RowMap sec(BitVector{true, false, true, true, false, true});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 3u);
+ ASSERT_EQ(rm.Get(0), 0u);
+}
+
+TEST(RowMapUnittest, IntersectIVWithIV) {
+ RowMap rm(std::vector<uint32_t>{0, 2, 5});
+ RowMap sec(std::vector<uint32_t>{1, 2, 6});
+
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 1u);
+ ASSERT_EQ(rm.Get(0u), 2u);
}
} // namespace
diff --git a/src/trace_processor/containers/string_pool.cc b/src/trace_processor/containers/string_pool.cc
index ab0b42a97..3dacca2de 100644
--- a/src/trace_processor/containers/string_pool.cc
+++ b/src/trace_processor/containers/string_pool.cc
@@ -25,23 +25,6 @@
namespace perfetto {
namespace trace_processor {
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// static
-constexpr size_t StringPool::kNumBlockIndexBits;
-// static
-constexpr size_t StringPool::kNumBlockOffsetBits;
-// static
-constexpr size_t StringPool::kLargeStringFlagBitMask;
-// static
-constexpr size_t StringPool::kBlockOffsetBitMask;
-// static
-constexpr size_t StringPool::kBlockIndexBitMask;
-// static
-constexpr size_t StringPool::kBlockSizeBytes;
-// static
-constexpr size_t StringPool::kMinLargeStringSizeBytes;
-#endif
-
StringPool::StringPool() {
static_assert(
StringPool::kMinLargeStringSizeBytes <= StringPool::kBlockSizeBytes + 1,
diff --git a/src/trace_processor/db/BUILD.gn b/src/trace_processor/db/BUILD.gn
index bfe5e8a37..043b2af0e 100644
--- a/src/trace_processor/db/BUILD.gn
+++ b/src/trace_processor/db/BUILD.gn
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import("../../../gn/perfetto_tp_tables.gni")
import("../../../gn/test.gni")
source_set("db") {
@@ -19,10 +20,22 @@ source_set("db") {
"base_id.h",
"column.cc",
"column.h",
+ "column_overlay.cc",
+ "column_overlay.h",
"column_storage.cc",
"column_storage.h",
"column_storage_overlay.h",
"compare.h",
+ "null_overlay.cc",
+ "null_overlay.h",
+ "numeric_storage.cc",
+ "numeric_storage.h",
+ "sorting_overlay.h",
+ "storage.cc",
+ "storage.h",
+ "storage_overlay.cc",
+ "storage_overlay.h",
+ "storage_variants.h",
"table.cc",
"table.h",
"typed_column.h",
@@ -40,16 +53,21 @@ source_set("db") {
]
}
+perfetto_tp_tables("view_unittest") {
+ sources = [ "view_unittest.py" ]
+}
+
perfetto_unittest_source_set("unittests") {
testonly = true
sources = [
"column_storage_overlay_unittest.cc",
"compare_unittest.cc",
- "table_unittest.cc",
+ "storage_unittest.cc",
"view_unittest.cc",
]
deps = [
":db",
+ ":view_unittest",
"../../../gn:default_deps",
"../../../gn:gtest_and_gmock",
"../../base",
diff --git a/src/trace_processor/db/column.h b/src/trace_processor/db/column.h
index 04425b9d9..f1adb96f3 100644
--- a/src/trace_processor/db/column.h
+++ b/src/trace_processor/db/column.h
@@ -367,6 +367,9 @@ class Column {
// Returns the type of this Column in terms of SqlValue::Type.
SqlValue::Type type() const { return ToSqlValueType(type_); }
+ // Returns the type of this Column in terms of ColumnType.
+ ColumnType col_type() const { return type_; }
+
// Test the type of this Column.
template <typename T>
bool IsColumnType() const {
@@ -382,6 +385,9 @@ class Column {
// Returns true if this column is a sorted column.
bool IsSorted() const { return IsSorted(flags_); }
+ // Returns true if this column is a dense column.
+ bool IsDense() const { return IsDense(flags_); }
+
// Returns true if this column is a set id column.
// Public for testing.
bool IsSetId() const { return IsSetId(flags_); }
@@ -439,31 +445,28 @@ class Column {
return IsFlagsAndTypeValid(flags, ColumnTypeHelper<T>::ToColumnType());
}
- protected:
template <typename T>
using stored_type = typename tc_internal::TypeHandler<T>::stored_type;
// Returns the backing sparse vector cast to contain data of type T.
// Should only be called when |type_| == ToColumnType<T>().
template <typename T>
- ColumnStorage<stored_type<T>>* mutable_storage() {
+ const ColumnStorage<stored_type<T>>& storage() const {
PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable());
- return static_cast<ColumnStorage<stored_type<T>>*>(storage_);
+ return *static_cast<ColumnStorage<stored_type<T>>*>(storage_);
}
+ protected:
// Returns the backing sparse vector cast to contain data of type T.
// Should only be called when |type_| == ToColumnType<T>().
template <typename T>
- const ColumnStorage<stored_type<T>>& storage() const {
+ ColumnStorage<stored_type<T>>* mutable_storage() {
PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable());
- return *static_cast<ColumnStorage<stored_type<T>>*>(storage_);
+ return static_cast<ColumnStorage<stored_type<T>>*>(storage_);
}
- // Returns true if this column is a dense column.
- bool IsDense() const { return IsDense(flags_); }
-
// Returns true if this column is a hidden column.
bool IsHidden() const { return (flags_ & Flag::kHidden) != 0; }
@@ -545,31 +548,31 @@ class Column {
b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
uint32_t end = std::distance(
b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(beg, end);
+ rm->Intersect({beg, end});
return true;
}
case FilterOp::kLe: {
uint32_t end = std::distance(
b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(0, end);
+ rm->Intersect({0, end});
return true;
}
case FilterOp::kLt: {
uint32_t end = std::distance(
b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(0, end);
+ rm->Intersect({0, end});
return true;
}
case FilterOp::kGe: {
uint32_t beg = std::distance(
b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(beg, overlay().size());
+ rm->Intersect({beg, overlay().size()});
return true;
}
case FilterOp::kGt: {
uint32_t beg = std::distance(
b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(beg, overlay().size());
+ rm->Intersect({beg, overlay().size()});
return true;
}
case FilterOp::kNe:
@@ -608,11 +611,13 @@ class Column {
// Otherwise, find the end of the set and return the intersection for this.
for (uint32_t i = set_id + 1; i < ov.size(); ++i) {
if (st.Get(ov.Get(i)) != filter_set_id) {
- rm->Intersect(set_id, i);
+ RowMap r(set_id, i);
+ rm->Intersect(r);
return;
}
}
- rm->Intersect(set_id, ov.size());
+ RowMap r(set_id, ov.size());
+ rm->Intersect(r);
}
// Slow path filter method which will perform a full table scan.
diff --git a/src/trace_processor/types/variadic.cc b/src/trace_processor/db/column_overlay.cc
index 9a26bd5ad..599a3b268 100644
--- a/src/trace_processor/types/variadic.cc
+++ b/src/trace_processor/db/column_overlay.cc
@@ -1,5 +1,5 @@
-#/*
- * Copyright (C) 2018 The Android Open Source Project
+/*
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "src/trace_processor/types/variadic.h"
+#include "src/trace_processor/db/column_overlay.h"
namespace perfetto {
namespace trace_processor {
+namespace column {
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-constexpr const char* Variadic::kTypeNames[];
-#endif
+ColumnOverlay::~ColumnOverlay() = default;
+} // namespace column
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/db/column_overlay.h b/src/trace_processor/db/column_overlay.h
new file mode 100644
index 000000000..e3bad537b
--- /dev/null
+++ b/src/trace_processor/db/column_overlay.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_COLUMN_OVERLAY_H_
+#define SRC_TRACE_PROCESSOR_DB_COLUMN_OVERLAY_H_
+
+#include <variant>
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+// Column overlay introduce separation between column storage (vector of data)
+// and state (nullability, sorting) and actions (filtering, expanding, joining)
+// done on the storage. This is a composable design - one ColumnOverlay
+// subclass might hold another subclass, and each of them implements all of the
+// functions in it's own specific way.
+class ColumnOverlay {
+ public:
+ virtual ~ColumnOverlay();
+
+ // Clears the rows of RowMap, on which data don't match the FilterOp operation
+ // with SqlValue. Efficient.
+ virtual void Filter(FilterOp, SqlValue, RowMap&) const = 0;
+
+ // Sorts (ascending) provided vector of indices based on storage.
+ virtual void StableSort(uint32_t* rows, uint32_t rows_size) const = 0;
+};
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_OVERLAY_H_
diff --git a/src/trace_processor/db/column_storage.h b/src/trace_processor/db/column_storage.h
index 6cf2f3069..7e6a60925 100644
--- a/src/trace_processor/db/column_storage.h
+++ b/src/trace_processor/db/column_storage.h
@@ -53,6 +53,7 @@ class ColumnStorage : public ColumnStorageBase {
void Set(uint32_t idx, T val) { vector_[idx] = val; }
uint32_t size() const { return static_cast<uint32_t>(vector_.size()); }
void ShrinkToFit() { vector_.shrink_to_fit(); }
+ const std::vector<T>& vector() const { return vector_; }
template <bool IsDense>
static ColumnStorage<T> Create() {
@@ -83,6 +84,14 @@ class ColumnStorage<std::optional<T>> : public ColumnStorageBase {
uint32_t size() const { return nv_.size(); }
bool IsDense() const { return nv_.IsDense(); }
void ShrinkToFit() { nv_.ShrinkToFit(); }
+ // For dense columns the size of the vector is equal to size of the bit
+ // vector. For sparse it's equal to count set bits of the bit vector.
+ const std::vector<T>& non_null_vector() const {
+ return nv_.non_null_vector();
+ }
+ const BitVector& non_null_bit_vector() const {
+ return nv_.non_null_bit_vector();
+ }
template <bool IsDense>
static ColumnStorage<std::optional<T>> Create() {
diff --git a/src/trace_processor/db/column_storage_overlay.h b/src/trace_processor/db/column_storage_overlay.h
index 108dccdd9..997d4be43 100644
--- a/src/trace_processor/db/column_storage_overlay.h
+++ b/src/trace_processor/db/column_storage_overlay.h
@@ -183,24 +183,12 @@ class ColumnStorageOverlay {
// meet |p|. However, if |this| is a BitVector, we end up needing expensive
// |IndexOfNthSet| calls (as we need to convert the row to an index before
// passing it to |p|).
- switch (row_map_.mode_) {
- case RowMap::Mode::kRange: {
- auto ip = [this, p](uint32_t row) { return p(row_map_.GetRange(row)); };
- out->Filter(ip);
- break;
- }
- case RowMap::Mode::kBitVector: {
- FilterIntoScanSelfBv(out, p);
- break;
- }
- case RowMap::Mode::kIndexVector: {
- auto ip = [this, p](uint32_t row) {
- return p(row_map_.GetIndexVector(row));
- };
- out->Filter(ip);
- break;
- }
+ if (row_map_.IsBitVector()) {
+ FilterIntoScanSelfBv(out, p);
+ return;
}
+ auto ip = [this, p](uint32_t row) { return p(row_map_.Get(row)); };
+ out->Filter(ip);
}
template <typename Comparator = bool(uint32_t, uint32_t)>
@@ -217,54 +205,57 @@ class ColumnStorageOverlay {
// Filters the current ColumnStorageOverlay into |out| by performing a full
// scan on |row_map.bit_vector_|. See |FilterInto| for a full breakdown of the
// semantics of this function.
+
template <typename Predicate>
- void FilterIntoScanSelfBv(RowMap* out, Predicate p) const {
- auto it = row_map_.bit_vector_.IterateSetBits();
- switch (out->mode_) {
- case RowMap::Mode::kRange: {
- // TODO(lalitm): investigate whether we can reuse the data inside
- // out->bit_vector_ at some point.
- BitVector bv(out->end_index_, false);
- for (auto out_it = bv.IterateAllBits(); it; it.Next(), out_it.Next()) {
- uint32_t ordinal = it.ordinal();
- if (ordinal < out->start_index_)
- continue;
- if (ordinal >= out->end_index_)
- break;
-
- if (p(it.index())) {
- out_it.Set();
- }
- }
- *out = RowMap(std::move(bv));
- break;
- }
- case RowMap::Mode::kBitVector: {
- auto out_it = out->bit_vector_.IterateAllBits();
- for (; out_it; it.Next(), out_it.Next()) {
- PERFETTO_DCHECK(it);
- if (out_it.IsSet() && !p(it.index()))
- out_it.Clear();
+ struct FilterIntoScanSelfBvVisitor {
+ void operator()(RowMap::Range out_r) {
+ BitVector bv(out_r.end, false);
+ for (auto out_it = bv.IterateAllBits(); bv_iter;
+ bv_iter.Next(), out_it.Next()) {
+ uint32_t ordinal = bv_iter.ordinal();
+ if (ordinal < out_r.start)
+ continue;
+ if (ordinal >= out_r.end)
+ break;
+
+ if (p(bv_iter.index())) {
+ out_it.Set();
}
- break;
}
- case RowMap::Mode::kIndexVector: {
- PERFETTO_DCHECK(std::is_sorted(out->index_vector_.begin(),
- out->index_vector_.end()));
- auto fn = [&p, &it](uint32_t i) {
- while (it.ordinal() < i) {
- it.Next();
- PERFETTO_DCHECK(it);
- }
- PERFETTO_DCHECK(it.ordinal() == i);
- return !p(it.index());
- };
- auto iv_it = std::remove_if(out->index_vector_.begin(),
- out->index_vector_.end(), fn);
- out->index_vector_.erase(iv_it, out->index_vector_.end());
- break;
+ *out = RowMap(std::move(bv));
+ }
+ void operator()(const BitVector& out_bv) {
+ auto out_it = out_bv.IterateAllBits();
+ for (; out_it; bv_iter.Next(), out_it.Next()) {
+ PERFETTO_DCHECK(bv_iter);
+ if (out_it.IsSet() && !p(bv_iter.index()))
+ out_it.Clear();
}
}
+ void operator()(std::vector<OutputIndex>& out_vec) {
+ PERFETTO_DCHECK(std::is_sorted(out_vec.begin(), out_vec.end()));
+ auto fn = [this](uint32_t i) {
+ while (bv_iter.ordinal() < i) {
+ bv_iter.Next();
+ PERFETTO_DCHECK(bv_iter);
+ }
+ PERFETTO_DCHECK(bv_iter.ordinal() == i);
+ return !p(bv_iter.index());
+ };
+ auto iv_it = std::remove_if(out_vec.begin(), out_vec.end(), fn);
+ out_vec.erase(iv_it, out_vec.end());
+ }
+ RowMap* out;
+ Predicate p;
+ internal::SetBitsIterator bv_iter;
+ };
+
+ template <typename Predicate>
+ void FilterIntoScanSelfBv(RowMap* out, Predicate p) const {
+ const BitVector* bv = std::get_if<BitVector>(&row_map_.data_);
+ auto it = bv->IterateSetBits();
+ std::visit(FilterIntoScanSelfBvVisitor<Predicate>{out, p, std::move(it)},
+ out->data_);
}
RowMap row_map_;
diff --git a/src/trace_processor/db/null_overlay.cc b/src/trace_processor/db/null_overlay.cc
new file mode 100644
index 000000000..ade46c5a1
--- /dev/null
+++ b/src/trace_processor/db/null_overlay.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/null_overlay.h"
+
+#include "src/trace_processor/db/storage_variants.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+void NullOverlay::Filter(FilterOp op, SqlValue sql_val, RowMap& rm) const {
+ if (op == FilterOp::kIsNull) {
+ rm.Intersect(RowMap(null_bv_->Not()));
+ return;
+ }
+ if (op == FilterOp::kIsNotNull) {
+ rm.Intersect(RowMap(null_bv_->Copy()));
+ return;
+ }
+
+ // Row map for filtered data, not the size of whole column.
+ RowMap filtered_data_rm(0, null_bv_->CountSetBits());
+ inner_->Filter(op, sql_val, filtered_data_rm);
+
+ // Select only rows that were not filtered out from null BitVector and
+ // intersect it with RowMap&.
+ rm.Intersect(RowMap(null_bv_->Copy()).SelectRows(filtered_data_rm));
+}
+
+void NullOverlay::StableSort(uint32_t* rows, uint32_t rows_size) const {
+ uint32_t count_set_bits = null_bv_->CountSetBits();
+
+ std::vector<uint32_t> non_null_rows(count_set_bits);
+ std::vector<uint32_t> storage_to_rows(count_set_bits);
+
+ // Saving the map from `out` index to `storage` index gives us free `IsSet()`
+ // function, which would be very expensive otherwise.
+ for (auto it = null_bv_->IterateSetBits(); it; it.Next()) {
+ storage_to_rows[it.ordinal()] = it.index();
+ }
+
+ uint32_t cur_non_null_id = 0;
+ uint32_t cur_null_id = 0;
+
+ // Sort elements into null and non null.
+ for (uint32_t i = 0; i < rows_size; ++i) {
+ uint32_t row_idx = rows[i];
+ auto it = std::lower_bound(storage_to_rows.begin(), storage_to_rows.end(),
+ row_idx);
+
+ // This condition holds if the row is null.
+ if (it == storage_to_rows.end() || *it != row_idx) {
+ // We can override the out because we already used this data.
+ rows[cur_null_id++] = row_idx;
+ continue;
+ }
+
+ uint32_t non_null_idx =
+ static_cast<uint32_t>(std::distance(storage_to_rows.begin(), it));
+ non_null_rows[cur_non_null_id++] = non_null_idx;
+ }
+
+ // Sort storage and translate them into `rows` indices.
+ inner_->StableSort(non_null_rows.data(), count_set_bits);
+ uint32_t set_rows_offset = null_bv_->size() - count_set_bits;
+ for (uint32_t i = 0; i < count_set_bits; ++i) {
+ rows[set_rows_offset + i] = storage_to_rows[non_null_rows[i]];
+ }
+}
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/null_overlay.h b/src/trace_processor/db/null_overlay.h
new file mode 100644
index 000000000..43d2fed37
--- /dev/null
+++ b/src/trace_processor/db/null_overlay.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_NULL_OVERLAY_H_
+#define SRC_TRACE_PROCESSOR_DB_NULL_OVERLAY_H_
+
+#include <variant>
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/column_overlay.h"
+#include "src/trace_processor/db/storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+// Overlay responsible for operations related to column nullability.
+class NullOverlay : public ColumnOverlay {
+ public:
+ explicit NullOverlay(std::unique_ptr<ColumnOverlay> inner,
+ const BitVector* null_bv)
+ : inner_(std::move(inner)), null_bv_(null_bv) {}
+
+ void Filter(FilterOp, SqlValue, RowMap&) const override;
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ private:
+ std::unique_ptr<ColumnOverlay> inner_;
+
+ // Vector of data nullability.
+ const BitVector* null_bv_;
+};
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_NULL_OVERLAY_H_
diff --git a/src/trace_processor/db/numeric_storage.cc b/src/trace_processor/db/numeric_storage.cc
new file mode 100644
index 000000000..3b66e2207
--- /dev/null
+++ b/src/trace_processor/db/numeric_storage.cc
@@ -0,0 +1,308 @@
+
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <variant>
+
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/numeric_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+namespace {
+
+// Templated part of FastPathComparison.
+template <typename T>
+inline void TypedFastPathComparison(std::optional<NumericValue> val,
+ FilterOp op,
+ const T* start,
+ uint32_t num_elements,
+ BitVector::Builder& builder) {
+ if (!val) {
+ builder.Skip(num_elements);
+ return;
+ }
+ std::visit(
+ [val, start, num_elements, &builder](auto comparator) {
+ T typed_val = std::get<T>(*val);
+ for (uint32_t i = 0; i < num_elements; i += BitVector::kBitsInWord) {
+ uint64_t word = 0;
+ // This part should be optimised by SIMD and is expected to be fast.
+ for (uint32_t k = 0; k < BitVector::kBitsInWord; ++k) {
+ bool comp_result = comparator(start[i + k], typed_val);
+ word |= static_cast<uint64_t>(comp_result) << k;
+ }
+ builder.AppendWord(word);
+ }
+ },
+ GetFilterOpVariant<T>(op));
+}
+
+// Templated part of SlowPathComparison.
+template <typename T>
+inline void TypedSlowPathComparison(std::optional<NumericValue> val,
+ FilterOp op,
+ const T* start,
+ uint32_t num_elements,
+ BitVector::Builder& builder) {
+ if (!val) {
+ builder.Skip(num_elements);
+ return;
+ }
+ std::visit(
+ [val, start, num_elements, &builder](auto comparator) {
+ T typed_val = std::get<T>(*val);
+ for (uint32_t i = 0; i < num_elements; ++i) {
+ builder.Append(comparator(start[i], typed_val));
+ }
+ },
+ GetFilterOpVariant<T>(op));
+}
+
+} // namespace
+
+void NumericStorage::StableSort(uint32_t* rows, uint32_t rows_size) const {
+ NumericValue val = *GetNumericTypeVariant(type_, SqlValue::Long(0));
+ std::visit(
+ [this, &rows, rows_size](auto val_data) {
+ using T = decltype(val_data);
+ const T* typed_start = static_cast<const T*>(data_);
+ std::stable_sort(rows, rows + rows_size,
+ [typed_start](uint32_t a_idx, uint32_t b_idx) {
+ T first_val = typed_start[a_idx];
+ T second_val = typed_start[b_idx];
+ return first_val < second_val;
+ });
+ },
+ val);
+}
+
+// Responsible for invoking templated version of FastPathComparison.
+void NumericStorage::CompareFast(FilterOp op,
+ SqlValue sql_val,
+ uint32_t offset,
+ uint32_t num_elements,
+ BitVector::Builder& builder) const {
+ PERFETTO_DCHECK(num_elements % BitVector::kBitsInWord == 0);
+ std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
+
+ // If the value is invalid we should just ignore those elements.
+ if (!val.has_value() || op == FilterOp::kIsNotNull ||
+ op == FilterOp::kIsNull || op == FilterOp::kGlob) {
+ builder.Skip(num_elements);
+ return;
+ }
+ std::visit(
+ [this, op, offset, num_elements, &builder](auto num_val) {
+ using T = decltype(num_val);
+ auto* typed_start = static_cast<const T*>(data_) + offset;
+ TypedFastPathComparison(num_val, op, typed_start, num_elements,
+ builder);
+ },
+ *val);
+}
+
+// Responsible for invoking templated version of SlowPathComparison.
+void NumericStorage::CompareSlow(FilterOp op,
+ SqlValue sql_val,
+ uint32_t offset,
+ uint32_t num_elements,
+ BitVector::Builder& builder) const {
+ std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
+
+ // If the value is invalid we should just ignore those elements.
+ if (!val.has_value() || op == FilterOp::kIsNotNull ||
+ op == FilterOp::kIsNull || op == FilterOp::kGlob) {
+ builder.Skip(num_elements);
+ return;
+ }
+
+ std::visit(
+ [this, op, offset, num_elements, &builder](auto val) {
+ using T = decltype(val);
+ auto* typed_start = static_cast<const T*>(data_) + offset;
+ TypedSlowPathComparison(val, op, typed_start, num_elements, builder);
+ },
+ *val);
+}
+
+uint32_t NumericStorage::UpperBoundIndex(NumericValue val) const {
+ return std::visit(
+ [this](auto val_data) {
+ using T = decltype(val_data);
+ const T* typed_start = static_cast<const T*>(data_);
+ auto upper =
+ std::upper_bound(typed_start, typed_start + size_, val_data);
+ return static_cast<uint32_t>(std::distance(typed_start, upper));
+ },
+ val);
+}
+
+// As we don't template those functions, we need to use std::visitor to type
+// `start`, hence this wrapping.
+uint32_t NumericStorage::LowerBoundIndex(NumericValue val) const {
+ return std::visit(
+ [this](auto val_data) {
+ using T = decltype(val_data);
+ const T* typed_start = static_cast<const T*>(data_);
+ auto lower =
+ std::lower_bound(typed_start, typed_start + size_, val_data);
+ return static_cast<uint32_t>(std::distance(typed_start, lower));
+ },
+ val);
+}
+
+void NumericStorage::CompareSorted(FilterOp op,
+ SqlValue sql_val,
+ RowMap& rm) const {
+ std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
+ if (!val.has_value() || op == FilterOp::kIsNotNull ||
+ op == FilterOp::kIsNull || op == FilterOp::kGlob) {
+ rm.Clear();
+ return;
+ }
+
+ switch (op) {
+ case FilterOp::kEq: {
+ uint32_t beg = LowerBoundIndex(*val);
+ uint32_t end = UpperBoundIndex(*val);
+ RowMap sec(beg, end);
+ rm.Intersect(sec);
+ return;
+ }
+ case FilterOp::kLe: {
+ uint32_t end = UpperBoundIndex(*val);
+ RowMap sec(0, end);
+ rm.Intersect(sec);
+ return;
+ }
+ case FilterOp::kLt: {
+ uint32_t end = LowerBoundIndex(*val);
+ RowMap sec(0, end);
+ rm.Intersect(sec);
+ return;
+ }
+ case FilterOp::kGe: {
+ uint32_t beg = LowerBoundIndex(*val);
+ RowMap sec(beg, size_);
+ rm.Intersect(sec);
+ return;
+ }
+ case FilterOp::kGt: {
+ uint32_t beg = UpperBoundIndex(*val);
+ RowMap sec(beg, size_);
+ rm.Intersect(sec);
+ return;
+ }
+ case FilterOp::kNe:
+ case FilterOp::kIsNull:
+ case FilterOp::kIsNotNull:
+ case FilterOp::kGlob:
+ rm.Clear();
+ }
+ return;
+}
+
+uint32_t NumericStorage::UpperBoundIndex(NumericValue val,
+ uint32_t* order) const {
+ return std::visit(
+ [this, order](auto val_data) {
+ using T = decltype(val_data);
+ const T* typed_start = static_cast<const T*>(data_);
+ auto upper = std::upper_bound(order, order + size_, val_data,
+ [typed_start](T val, uint32_t index) {
+ return val < *(typed_start + index);
+ });
+ return static_cast<uint32_t>(std::distance(order, upper));
+ },
+ val);
+}
+
+// As we don't template those functions, we need to use std::visitor to type
+// `start`, hence this wrapping.
+uint32_t NumericStorage::LowerBoundIndex(NumericValue val,
+ uint32_t* order) const {
+ return std::visit(
+ [this, order](auto val_data) {
+ using T = decltype(val_data);
+ const T* typed_start = static_cast<const T*>(data_);
+ auto lower = std::lower_bound(order, order + size_, val_data,
+ [typed_start](uint32_t index, T val) {
+ return *(typed_start + index) < val;
+ });
+ return static_cast<uint32_t>(std::distance(order, lower));
+ },
+ val);
+}
+
+void NumericStorage::CompareSortedIndexes(FilterOp op,
+ SqlValue sql_val,
+ uint32_t* order,
+ RowMap& rm) const {
+ std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
+ if (!val.has_value() || op == FilterOp::kIsNotNull ||
+ op == FilterOp::kIsNull || op == FilterOp::kGlob) {
+ rm.Clear();
+ return;
+ }
+
+ switch (op) {
+ case FilterOp::kEq: {
+ uint32_t beg = LowerBoundIndex(*val, order);
+ uint32_t end = UpperBoundIndex(*val, order);
+ std::vector<uint32_t> index(order + beg, order + end);
+ rm.Intersect(RowMap(std::move(index)));
+ return;
+ }
+ case FilterOp::kLe: {
+ uint32_t end = UpperBoundIndex(*val, order);
+ std::vector<uint32_t> index(order, order + end);
+ rm.Intersect(RowMap(std::move(index)));
+ return;
+ }
+ case FilterOp::kLt: {
+ uint32_t end = LowerBoundIndex(*val, order);
+ std::vector<uint32_t> index(order, order + end);
+ rm.Intersect(RowMap(std::move(index)));
+ return;
+ }
+ case FilterOp::kGe: {
+ uint32_t beg = LowerBoundIndex(*val, order);
+ std::vector<uint32_t> index(order + beg, order + size_);
+ rm.Intersect(RowMap(std::move(index)));
+ return;
+ }
+ case FilterOp::kGt: {
+ uint32_t beg = UpperBoundIndex(*val, order);
+ std::vector<uint32_t> index(order + beg, order + size_);
+ rm.Intersect(RowMap(std::move(index)));
+ return;
+ }
+ case FilterOp::kNe:
+ case FilterOp::kIsNull:
+ case FilterOp::kIsNotNull:
+ case FilterOp::kGlob:
+ rm.Clear();
+ }
+ return;
+}
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/numeric_storage.h b/src/trace_processor/db/numeric_storage.h
new file mode 100644
index 000000000..a85044bb4
--- /dev/null
+++ b/src/trace_processor/db/numeric_storage.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SRC_TRACE_PROCESSOR_DB_NUMERIC_STORAGE_H_
+#define SRC_TRACE_PROCESSOR_DB_NUMERIC_STORAGE_H_
+
+#include <variant>
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/storage.h"
+#include "src/trace_processor/db/storage_variants.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+class NumericStorage : public Storage {
+ public:
+ NumericStorage(void* data, uint32_t size, ColumnType type)
+ : type_(type), data_(data), size_(size) {}
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void CompareFast(FilterOp op,
+ SqlValue val,
+ uint32_t offset,
+ uint32_t num_elements,
+ BitVector::Builder& builder) const override;
+
+ void CompareSlow(FilterOp op,
+ SqlValue val,
+ uint32_t offset,
+ uint32_t num_elements,
+ BitVector::Builder& builder) const override;
+
+ void CompareSorted(FilterOp op, SqlValue val, RowMap&) const override;
+
+ void CompareSortedIndexes(FilterOp op,
+ SqlValue val,
+ uint32_t* order,
+ RowMap&) const override;
+
+ uint32_t size() const override { return size_; }
+
+ private:
+ // As we don't template those functions, we need to use std::visitor to type
+ // `start`, hence this wrapping.
+ uint32_t UpperBoundIndex(NumericValue val) const;
+
+ // As we don't template those functions, we need to use std::visitor to type
+ // `start`, hence this wrapping.
+ uint32_t LowerBoundIndex(NumericValue val) const;
+
+ // As we don't template those functions, we need to use std::visitor to type
+ // `start`, hence this wrapping.
+ uint32_t UpperBoundIndex(NumericValue val, uint32_t* order) const;
+
+ // As we don't template those functions, we need to use std::visitor to type
+ // `start`, hence this wrapping.
+ uint32_t LowerBoundIndex(NumericValue val, uint32_t* order) const;
+
+ const ColumnType type_;
+ const void* data_;
+ const uint32_t size_;
+};
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
+#endif // SRC_TRACE_PROCESSOR_DB_NUMERIC_STORAGE_H_
diff --git a/src/trace_processor/db/sorting_overlay.h b/src/trace_processor/db/sorting_overlay.h
new file mode 100644
index 000000000..7b536a1c2
--- /dev/null
+++ b/src/trace_processor/db/sorting_overlay.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_SORTING_OVERLAY_H_
+#define SRC_TRACE_PROCESSOR_DB_SORTING_OVERLAY_H_
+
+#include <variant>
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/column_overlay.h"
+#include "src/trace_processor/db/storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+// Overlay responsible for operations related to column sorted state.
+class SortingOverlay : public ColumnOverlay {
+ public:
+ explicit SortingOverlay(ColumnOverlay* ancestor);
+ void Filter(FilterOp, SqlValue, RowMap&) const override;
+ void StableSort(uint32_t* rows_order, uint32_t rows_size) const override;
+
+ private:
+ std::unique_ptr<ColumnOverlay> inner_;
+
+ // Index vector of data sorted in ascending order.
+ const std::vector<uint32_t>* sorted_state_;
+};
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_SORTING_OVERLAY_H_
diff --git a/protos/perfetto/trace_processor/cloud_trace_processor.proto b/src/trace_processor/db/storage.cc
index b009fe3d8..4799d0479 100644
--- a/protos/perfetto/trace_processor/cloud_trace_processor.proto
+++ b/src/trace_processor/db/storage.cc
@@ -14,8 +14,14 @@
* limitations under the License.
*/
-syntax = "proto2";
+#include "src/trace_processor/db/storage.h"
-package perfetto.protos;
+namespace perfetto {
+namespace trace_processor {
+namespace column {
-service CloudTraceProcessorWorkerService {} \ No newline at end of file
+Storage::~Storage() = default;
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage.h b/src/trace_processor/db/storage.h
new file mode 100644
index 000000000..41e616fc8
--- /dev/null
+++ b/src/trace_processor/db/storage.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_H_
+#define SRC_TRACE_PROCESSOR_DB_STORAGE_H_
+
+#include <variant>
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+// Most base column interpreting layer - responsible for implementing operations
+// that require looking at the data, such as comparison or sorting.
+class Storage {
+ public:
+ virtual ~Storage();
+
+ // Changes the vector of indices to represent the sorted state of the column.
+ virtual void StableSort(uint32_t* rows, uint32_t rows_size) const = 0;
+
+ // Efficiently compares series of |num_elements| of data from |data_start| to
+ // comparator value and appends results to BitVector::Builder. Should be used
+ // on as much data as possible.
+ virtual void CompareFast(FilterOp op,
+ SqlValue value,
+ uint32_t offset,
+ uint32_t compare_elements_count,
+ BitVector::Builder&) const = 0;
+
+ // Inefficiently compares series of |num_elements| of data from |data_start|
+ // to comparator value and appends results to BitVector::Builder. Should be
+ // avoided if possible, with `FastSeriesComparison` used instead.
+ virtual void CompareSlow(FilterOp op,
+ SqlValue value,
+ uint32_t offset,
+ uint32_t compare_elements_count,
+ BitVector::Builder&) const = 0;
+
+ // Compares sorted (asc) series data with comparator value. Should be used
+ // where possible.
+ virtual void CompareSorted(FilterOp op, SqlValue value, RowMap&) const = 0;
+
+ // Compares sorted (asc) with `order` vector series with comparator value.
+ // Should be used where possible.
+ virtual void CompareSortedIndexes(FilterOp op,
+ SqlValue value,
+ uint32_t* order,
+ RowMap&) const = 0;
+
+ // Number of elements in stored data.
+ virtual uint32_t size() const = 0;
+};
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
+#endif // SRC_TRACE_PROCESSOR_DB_STORAGE_H_
diff --git a/src/trace_processor/db/storage_overlay.cc b/src/trace_processor/db/storage_overlay.cc
new file mode 100644
index 000000000..2ab4fde29
--- /dev/null
+++ b/src/trace_processor/db/storage_overlay.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/db/storage_overlay.h"
+
+#include "src/trace_processor/db/storage_variants.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+void StorageOverlay::Filter(FilterOp op, SqlValue value, RowMap& rm) const {
+ if (op == FilterOp::kIsNotNull)
+ return;
+
+ if (op == FilterOp::kIsNull) {
+ rm.Clear();
+ return;
+ }
+
+ BitVector::Builder builder(storage_->size());
+ // Slow path: we compare <64 elements and append to get us to a word
+ // boundary.
+ uint32_t front_elements = builder.BitsUntilWordBoundaryOrFull();
+ storage_->CompareSlow(op, value, 0, front_elements, builder);
+ uint32_t cur_index = front_elements;
+
+ // Fast path: we compare as many groups of 64 elements as we can.
+ // This should be very easy for the compiler to auto-vectorize.
+ uint32_t fast_path_elements = builder.BitsInCompleteWordsUntilFull();
+ storage_->CompareFast(op, value, cur_index, fast_path_elements, builder);
+ cur_index += fast_path_elements;
+
+ // Slow path: we compare <64 elements and append to fill the Builder.
+ uint32_t back_elements = builder.BitsUntilFull();
+ storage_->CompareSlow(op, value, cur_index, back_elements, builder);
+
+ BitVector bv = std::move(builder).Build();
+ rm.Intersect(RowMap(std::move(bv)));
+}
+
+void StorageOverlay::StableSort(uint32_t* rows, uint32_t rows_size) const {
+ storage_->StableSort(rows, rows_size);
+}
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage_overlay.h b/src/trace_processor/db/storage_overlay.h
new file mode 100644
index 000000000..9b0b5ec3d
--- /dev/null
+++ b/src/trace_processor/db/storage_overlay.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_OVERLAY_H_
+#define SRC_TRACE_PROCESSOR_DB_STORAGE_OVERLAY_H_
+
+#include <variant>
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/column_overlay.h"
+#include "src/trace_processor/db/storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+// Overlay responsible for doing operations on storage.
+class StorageOverlay : public ColumnOverlay {
+ public:
+ explicit StorageOverlay(const Storage* storage) : storage_(storage) {}
+ void Filter(FilterOp, SqlValue, RowMap&) const override;
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ private:
+ const Storage* storage_;
+};
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_STORAGE_OVERLAY_H_
diff --git a/src/trace_processor/db/storage_unittest.cc b/src/trace_processor/db/storage_unittest.cc
new file mode 100644
index 000000000..8988c0030
--- /dev/null
+++ b/src/trace_processor/db/storage_unittest.cc
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <numeric>
+#include "src/trace_processor/db/numeric_storage.h"
+
+#include "src/trace_processor/db/null_overlay.h"
+#include "src/trace_processor/db/storage_overlay.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+namespace {
+
+TEST(NumericStorageUnittest, StableSortTrivial) {
+ std::vector<uint32_t> data_vec{0, 1, 2, 0, 1, 2, 0, 1, 2};
+ std::vector<uint32_t> out = {0, 1, 2, 3, 4, 5, 6, 7, 8};
+
+ NumericStorage storage(data_vec.data(), 9, ColumnType::kUint32);
+ RowMap rm(0, 9);
+ storage.StableSort(out.data(), 9);
+
+ std::vector<uint32_t> stable_out{0, 3, 6, 1, 4, 7, 2, 5, 8};
+ ASSERT_EQ(out, stable_out);
+}
+
+TEST(NumericStorageUnittest, StableSort) {
+ std::vector<uint32_t> data_vec{0, 1, 2, 0, 1, 2, 0, 1, 2};
+ std::vector<uint32_t> out = {1, 7, 4, 0, 6, 3, 2, 5, 8};
+
+ NumericStorage storage(data_vec.data(), 9, ColumnType::kUint32);
+ RowMap rm(0, 9);
+ storage.StableSort(out.data(), 9);
+
+ std::vector<uint32_t> stable_out{0, 6, 3, 1, 7, 4, 2, 5, 8};
+ ASSERT_EQ(out, stable_out);
+}
+
+TEST(NumericStorageUnittest, CompareSlow) {
+ uint32_t size = 10;
+ std::vector<uint32_t> data_vec(size);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), size, ColumnType::kUint32);
+ BitVector::Builder builder(size);
+ storage.CompareSlow(FilterOp::kGe, SqlValue::Long(5), 0, size, builder);
+ BitVector bv = std::move(builder).Build();
+
+ ASSERT_EQ(bv.CountSetBits(), 5u);
+ ASSERT_EQ(bv.IndexOfNthSet(0), 5u);
+}
+
+TEST(NumericStorageUnittest, CompareSlowLarge) {
+ uint32_t size = 1025;
+ std::vector<uint32_t> data_vec(size);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), size, ColumnType::kUint32);
+ BitVector::Builder builder(size);
+ storage.CompareSlow(FilterOp::kGe, SqlValue::Long(5), 0, size, builder);
+ BitVector bv = std::move(builder).Build();
+
+ ASSERT_EQ(bv.CountSetBits(), 1020u);
+ ASSERT_EQ(bv.IndexOfNthSet(0), 5u);
+}
+
+TEST(NumericStorageUnittest, CompareFast) {
+ std::vector<uint32_t> data_vec(128);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), 128, ColumnType::kUint32);
+ BitVector::Builder builder(128);
+ storage.CompareFast(FilterOp::kGe, SqlValue::Long(100), 0, 128, builder);
+ BitVector bv = std::move(builder).Build();
+
+ ASSERT_EQ(bv.CountSetBits(), 28u);
+ ASSERT_EQ(bv.IndexOfNthSet(0), 100u);
+}
+
+TEST(NumericStorageUnittest, CompareSorted) {
+ std::vector<uint32_t> data_vec(128);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), 128, ColumnType::kUint32);
+ RowMap rm(0, 128);
+ storage.CompareSorted(FilterOp::kGe, SqlValue::Long(100), rm);
+
+ ASSERT_EQ(rm.size(), 28u);
+ ASSERT_EQ(rm.Get(0), 100u);
+}
+
+TEST(NumericStorageUnittest, CompareSortedIndexesGreaterEqual) {
+ std::vector<uint32_t> data_vec{30, 40, 50, 60, 90, 80, 70, 0, 10, 20};
+ std::vector<uint32_t> sorted_order{7, 8, 9, 0, 1, 2, 3, 6, 5, 4};
+
+ NumericStorage storage(data_vec.data(), 10, ColumnType::kUint32);
+ RowMap rm(0, 10);
+
+ storage.CompareSortedIndexes(FilterOp::kGe, SqlValue::Long(60),
+ sorted_order.data(), rm);
+
+ ASSERT_EQ(rm.size(), 4u);
+ ASSERT_EQ(rm.Get(0), 3u);
+ ASSERT_EQ(rm.Get(1), 6u);
+ ASSERT_EQ(rm.Get(2), 5u);
+ ASSERT_EQ(rm.Get(3), 4u);
+}
+
+TEST(NumericStorageUnittest, CompareSortedIndexesLess) {
+ std::vector<uint32_t> data_vec{30, 40, 50, 60, 90, 80, 70, 0, 10, 20};
+ std::vector<uint32_t> sorted_order{7, 8, 9, 0, 1, 2, 3, 6, 5, 4};
+
+ NumericStorage storage(data_vec.data(), 10, ColumnType::kUint32);
+ RowMap rm(0, 10);
+
+ storage.CompareSortedIndexes(FilterOp::kLt, SqlValue::Long(60),
+ sorted_order.data(), rm);
+
+ ASSERT_EQ(rm.size(), 6u);
+ ASSERT_EQ(rm.Get(0), 7u);
+}
+
+TEST(NumericStorageUnittest, CompareSortedIndexesEqual) {
+ std::vector<uint32_t> data_vec{30, 40, 50, 60, 90, 80, 70, 0, 10, 20};
+ std::vector<uint32_t> sorted_order{7, 8, 9, 0, 1, 2, 3, 6, 5, 4};
+
+ NumericStorage storage(data_vec.data(), 10, ColumnType::kUint32);
+ RowMap rm(0, 10);
+
+ storage.CompareSortedIndexes(FilterOp::kEq, SqlValue::Long(60),
+ sorted_order.data(), rm);
+
+ ASSERT_EQ(rm.size(), 1u);
+ ASSERT_EQ(rm.Get(0), 3u);
+}
+
+TEST(StorageOverlayUnittests, FilterIsNull) {
+ std::vector<uint32_t> data_vec(1025);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), 1025, ColumnType::kUint32);
+ StorageOverlay overlay(&storage);
+
+ RowMap rm(0, 1025);
+ overlay.Filter(FilterOp::kIsNull, SqlValue::Long(0), rm);
+
+ ASSERT_EQ(rm.size(), 0u);
+}
+
+TEST(StorageOverlayUnittests, FilterIsNotNull) {
+ std::vector<uint32_t> data_vec(1025);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), 1025, ColumnType::kUint32);
+ StorageOverlay overlay(&storage);
+
+ RowMap rm(0, 1025);
+ overlay.Filter(FilterOp::kIsNotNull, SqlValue::Long(0), rm);
+
+ ASSERT_EQ(rm.size(), 1025u);
+}
+
+TEST(StorageOverlayUnittests, Filter) {
+ std::vector<uint32_t> data_vec(1025);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), 1025, ColumnType::kUint32);
+ StorageOverlay overlay(&storage);
+
+ RowMap rm(0, 1025);
+ overlay.Filter(FilterOp::kGe, SqlValue::Long(200), rm);
+
+ ASSERT_EQ(rm.size(), 825u);
+ ASSERT_EQ(rm.Get(0), 200u);
+}
+
+TEST(StorageOverlayUnittests, Sort) {
+ std::vector<uint32_t> data_vec{0, 1, 2, 0, 1, 2, 0, 1, 2};
+ std::vector<uint32_t> out = {1, 7, 4, 0, 6, 3, 2, 5, 8};
+
+ NumericStorage storage(data_vec.data(), 9, ColumnType::kUint32);
+ StorageOverlay overlay(&storage);
+
+ overlay.StableSort(out.data(), 9);
+
+ std::vector<uint32_t> stable_out{0, 6, 3, 1, 7, 4, 2, 5, 8};
+ ASSERT_EQ(out, stable_out);
+}
+
+TEST(NullOverlayUnittest, FilterIsNull) {
+ std::vector<uint32_t> data_vec(10);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ BitVector bv = BitVector::Range(0, 20, [](uint32_t t) { return t % 2 == 0; });
+
+ NumericStorage storage(data_vec.data(), 10, ColumnType::kUint32);
+ std::unique_ptr<ColumnOverlay> storage_overlay(new StorageOverlay(&storage));
+ NullOverlay overlay(std::move(storage_overlay), &bv);
+
+ RowMap rm(0, 10);
+ overlay.Filter(FilterOp::kIsNull, SqlValue::Long(5), rm);
+ ASSERT_EQ(rm.size(), 5u);
+ ASSERT_EQ(rm.Get(0), 1u);
+}
+
+TEST(NullOverlayUnittest, FilterIsNotNull) {
+ std::vector<uint32_t> data_vec(10);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), 10, ColumnType::kUint32);
+ BitVector bv = BitVector::Range(0, 20, [](uint32_t t) { return t % 2 == 0; });
+ std::unique_ptr<ColumnOverlay> storage_overlay(new StorageOverlay(&storage));
+ NullOverlay overlay(std::move(storage_overlay), &bv);
+
+ RowMap rm(0, 10);
+ overlay.Filter(FilterOp::kIsNotNull, SqlValue::Long(5), rm);
+
+ ASSERT_EQ(rm.size(), 5u);
+ ASSERT_EQ(rm.Get(0), 0u);
+}
+
+TEST(NullOverlayUnittest, Filter) {
+ uint32_t bv_size = 20;
+ uint32_t data_size = 10;
+
+ // Prepare storage
+ std::vector<uint32_t> data_vec(data_size);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), data_size, ColumnType::kUint32);
+
+ // Prepare NullOverlay
+ BitVector bv =
+ BitVector::Range(0, bv_size, [](uint32_t t) { return t % 2 == 0; });
+ std::unique_ptr<ColumnOverlay> storage_overlay(new StorageOverlay(&storage));
+ NullOverlay overlay(std::move(storage_overlay), &bv);
+
+ RowMap rm(0, bv_size);
+ overlay.Filter(FilterOp::kGe, SqlValue::Long(5), rm);
+
+ ASSERT_EQ(rm.size(), 5u);
+ ASSERT_EQ(rm.Get(0), 10u);
+}
+
+TEST(NullOverlayUnittest, FilterLarge) {
+ uint32_t bv_size = 1000;
+ uint32_t data_size = 100;
+
+ // Prepare storage
+ std::vector<uint32_t> data_vec(data_size);
+ std::iota(data_vec.begin(), data_vec.end(), 0);
+ NumericStorage storage(data_vec.data(), data_size, ColumnType::kUint32);
+
+ // Prepare NullOverlay
+ BitVector bv =
+ BitVector::Range(800, bv_size, [](uint32_t t) { return t % 2 == 0; });
+ std::unique_ptr<ColumnOverlay> storage_overlay(new StorageOverlay(&storage));
+ NullOverlay overlay(std::move(storage_overlay), &bv);
+
+ RowMap rm(0, bv_size);
+ overlay.Filter(FilterOp::kGe, SqlValue::Long(50), rm);
+
+ ASSERT_EQ(rm.size(), 50u);
+ ASSERT_EQ(rm.Get(0), 900u);
+}
+
+TEST(NullOverlayUnittest, Sort) {
+ // Prepare storage
+ std::vector<uint32_t> data_vec{0, 1, 2, 0, 1, 2, 0, 1, 2};
+ std::vector<uint32_t> out(18);
+ std::iota(out.begin(), out.end(), 0);
+ NumericStorage storage(data_vec.data(), 9, ColumnType::kUint32);
+
+ // Prepare NullOverlay
+ BitVector bv = BitVector::Range(0, 18, [](uint32_t t) { return t % 2 == 0; });
+ std::unique_ptr<ColumnOverlay> storage_overlay(new StorageOverlay(&storage));
+ NullOverlay overlay(std::move(storage_overlay), &bv);
+
+ overlay.StableSort(out.data(), 18);
+
+ std::vector<uint32_t> stable_out{1, 3, 5, 7, 9, 11, 13, 15, 17,
+ 0, 6, 12, 2, 8, 14, 4, 10, 16};
+ ASSERT_EQ(out, stable_out);
+}
+
+} // namespace
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/db/storage_variants.h b/src/trace_processor/db/storage_variants.h
new file mode 100644
index 000000000..bc169b9a0
--- /dev/null
+++ b/src/trace_processor/db/storage_variants.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SRC_TRACE_PROCESSOR_DB_STORAGE_VARIANTS_H_
+#define SRC_TRACE_PROCESSOR_DB_STORAGE_VARIANTS_H_
+
+#include <variant>
+#include "perfetto/ext/base/status_or.h"
+#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace column {
+
+// All viable numeric values for ColumnTypes.
+using NumericValue = std::variant<uint32_t, int32_t, int64_t, double_t>;
+
+// Using the fact that binary operators in std are operators() of classes, we
+// can wrap those classes in variants and use them for std::visit in
+// SerialComparators. This helps prevent excess templating and switches.
+template <typename T>
+using FilterOpVariant = std::variant<std::greater<T>,
+ std::greater_equal<T>,
+ std::less<T>,
+ std::less_equal<T>,
+ std::equal_to<T>,
+ std::not_equal_to<T>>;
+
+// Based on SqlValue and ColumnType, casts SqlValue to proper type, returns
+// std::nullopt if SqlValue can't be cast and should be considered invalid for
+// comparison.
+inline std::optional<NumericValue> GetNumericTypeVariant(ColumnType type,
+ SqlValue val) {
+ if (val.is_null())
+ return std::nullopt;
+
+ switch (type) {
+ case ColumnType::kDouble:
+ return val.AsDouble();
+ case ColumnType::kInt64:
+ return val.AsLong();
+ case ColumnType::kInt32:
+ if (val.AsLong() > std::numeric_limits<int32_t>::max() ||
+ val.AsLong() < std::numeric_limits<int32_t>::min())
+ return std::nullopt;
+ return static_cast<int32_t>(val.AsLong());
+ case ColumnType::kUint32:
+ if (val.AsLong() > std::numeric_limits<uint32_t>::max() ||
+ val.AsLong() < std::numeric_limits<uint32_t>::min())
+ return std::nullopt;
+ return static_cast<uint32_t>(val.AsLong());
+ case ColumnType::kString:
+ case ColumnType::kDummy:
+ case ColumnType::kId:
+ return std::nullopt;
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+// Based on SqlValue and ColumnType, casts SqlValue to proper type, returns
+// std::nullopt if SqlValue can't be cast and should be considered invalid for
+// comparison.
+inline std::optional<NumericValue> GetNumericTypeVariant(ColumnType type) {
+ return GetNumericTypeVariant(type, SqlValue::Long(0));
+}
+
+// Fetch std binary comparator class based on FilterOp. Can be used in
+// std::visit for comparison.
+template <typename T>
+inline FilterOpVariant<T> GetFilterOpVariant(FilterOp op) {
+ switch (op) {
+ case FilterOp::kEq:
+ return FilterOpVariant<T>(std::equal_to<T>());
+ case FilterOp::kNe:
+ return FilterOpVariant<T>(std::not_equal_to<T>());
+ case FilterOp::kGe:
+ return FilterOpVariant<T>(std::greater_equal<T>());
+ case FilterOp::kGt:
+ return FilterOpVariant<T>(std::greater<T>());
+ case FilterOp::kLe:
+ return FilterOpVariant<T>(std::less_equal<T>());
+ case FilterOp::kLt:
+ return FilterOpVariant<T>(std::less<T>());
+ case FilterOp::kGlob:
+ case FilterOp::kIsNotNull:
+ case FilterOp::kIsNull:
+ PERFETTO_FATAL("Not a valid operation on numeric type.");
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+} // namespace column
+} // namespace trace_processor
+} // namespace perfetto
+#endif // SRC_TRACE_PROCESSOR_DB_STORAGE_VARIANTS_H_
diff --git a/src/trace_processor/db/table_unittest.cc b/src/trace_processor/db/table_unittest.cc
deleted file mode 100644
index 6f370ca25..000000000
--- a/src/trace_processor/db/table_unittest.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/trace_processor/db/table.h"
-#include "src/trace_processor/db/typed_column.h"
-#include "src/trace_processor/tables/macros.h"
-
-#include "test/gtest_and_gmock.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace {
-
-#define PERFETTO_TP_TEST_EVENT_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestEventTable, "event") \
- PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
- C(int64_t, ts, Column::Flag::kSorted) \
- C(int64_t, dur) \
- C(uint32_t, arg_set_id, Column::Flag::kSorted | Column::Flag::kSetId)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_EVENT_TABLE_DEF);
-
-TestEventTable::~TestEventTable() = default;
-
-TEST(TableTest, SetIdColumns) {
- StringPool pool;
- TestEventTable table{&pool, nullptr};
-
- table.Insert(TestEventTable::Row(0, 0, 0));
- table.Insert(TestEventTable::Row(1, 0, 0));
- table.Insert(TestEventTable::Row(2, 0, 2));
- table.Insert(TestEventTable::Row(3, 0, 3));
- table.Insert(TestEventTable::Row(4, 0, 4));
- table.Insert(TestEventTable::Row(5, 0, 4));
- table.Insert(TestEventTable::Row(6, 0, 4));
- table.Insert(TestEventTable::Row(7, 0, 4));
- table.Insert(TestEventTable::Row(8, 0, 8));
-
- ASSERT_EQ(table.row_count(), 9u);
- ASSERT_TRUE(table.arg_set_id().IsSetId());
-
- // Verify that not-present ids are not returned.
- {
- static constexpr uint32_t kFilterArgSetId = 1;
- auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
- ASSERT_EQ(res.row_count(), 0u);
- }
- {
- static constexpr uint32_t kFilterArgSetId = 9;
- auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
- ASSERT_EQ(res.row_count(), 0u);
- }
-
- // Verify that kSetId flag is correctly removed after filtering/sorting.
- {
- static constexpr uint32_t kFilterArgSetId = 3;
- auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
- ASSERT_EQ(res.row_count(), 1u);
- ASSERT_FALSE(res.GetColumnByName("arg_set_id")->IsSetId());
- }
- {
- auto res = table.Sort({table.dur().descending()});
- ASSERT_FALSE(res.GetColumnByName("arg_set_id")->IsSetId());
- }
-
- uint32_t arg_set_id_col_idx =
- static_cast<uint32_t>(TestEventTable::ColumnIndex::arg_set_id);
-
- // Verify that filtering equality for real arg set ids works as expected.
- {
- static constexpr uint32_t kFilterArgSetId = 4;
- auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
- ASSERT_EQ(res.row_count(), 4u);
- for (auto it = res.IterateRows(); it; it.Next()) {
- uint32_t arg_set_id =
- static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
- ASSERT_EQ(arg_set_id, kFilterArgSetId);
- }
- }
- {
- static constexpr uint32_t kFilterArgSetId = 0;
- auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
- ASSERT_EQ(res.row_count(), 2u);
- for (auto it = res.IterateRows(); it; it.Next()) {
- uint32_t arg_set_id =
- static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
- ASSERT_EQ(arg_set_id, kFilterArgSetId);
- }
- }
- {
- static constexpr uint32_t kFilterArgSetId = 8;
- auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
- ASSERT_EQ(res.row_count(), 1u);
- for (auto it = res.IterateRows(); it; it.Next()) {
- uint32_t arg_set_id =
- static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
- ASSERT_EQ(arg_set_id, kFilterArgSetId);
- }
- }
-
- // Verify that filtering equality for arg set ids after filtering another
- // column works.
- {
- static constexpr uint32_t kFilterArgSetId = 4;
- auto res = table.Filter(
- {table.ts().ge(6), table.arg_set_id().eq(kFilterArgSetId)});
- ASSERT_EQ(res.row_count(), 2u);
- for (auto it = res.IterateRows(); it; it.Next()) {
- uint32_t arg_set_id =
- static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
- ASSERT_EQ(arg_set_id, kFilterArgSetId);
- }
- }
-}
-
-} // namespace
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/view_unittest.cc b/src/trace_processor/db/view_unittest.cc
index 2507b927c..221753aae 100644
--- a/src/trace_processor/db/view_unittest.cc
+++ b/src/trace_processor/db/view_unittest.cc
@@ -15,52 +15,22 @@
*/
#include "src/trace_processor/db/view.h"
-#include "src/trace_processor/tables/macros.h"
+#include "src/trace_processor/db/view_unittest_py.h"
#include "src/trace_processor/views/macros.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
namespace trace_processor {
-namespace {
+namespace tables {
+
+ViewThreadTable::~ViewThreadTable() = default;
+ViewTrackTable::~ViewTrackTable() = default;
+ViewThreadTrackTable::~ViewThreadTrackTable() = default;
+ViewEventTable::~ViewEventTable() = default;
+ViewSliceTable::~ViewSliceTable() = default;
-#define PERFETTO_TP_TEST_THREAD_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestThreadTable, "thread_table") \
- PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
- C(StringPool::Id, name) \
- C(uint32_t, tid)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_THREAD_TABLE_DEF);
-
-#define PERFETTO_TP_TEST_TRACK_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestTrackTable, "track_table") \
- PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
- C(StringPool::Id, name)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_TRACK_TABLE_DEF);
-
-#define PERFETTO_TP_TEST_THREAD_TRACK_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestThreadTrackTable, "thread_track_table") \
- PARENT(PERFETTO_TP_TEST_TRACK_TABLE_DEF, C) \
- C(TestThreadTable::Id, utid)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_THREAD_TRACK_TABLE_DEF);
-
-#define PERFETTO_TP_TEST_EVENT_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestEventTable, "event_table") \
- PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
- C(int64_t, ts, Column::Flag::kSorted) \
- C(TestTrackTable::Id, track_id)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_EVENT_TABLE_DEF);
-
-#define PERFETTO_TP_TEST_SLICE_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestSliceTable, "slice_table") \
- PARENT(PERFETTO_TP_TEST_EVENT_TABLE_DEF, C) \
- C(StringPool::Id, name)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_SLICE_TABLE_DEF);
-
-TestThreadTable::~TestThreadTable() = default;
-TestTrackTable::~TestTrackTable() = default;
-TestThreadTrackTable::~TestThreadTrackTable() = default;
-TestEventTable::~TestEventTable() = default;
-TestSliceTable::~TestSliceTable() = default;
+namespace {
template <typename ViewSubclass>
class AbstractViewTest : public ::testing::Test {
@@ -106,17 +76,17 @@ class AbstractViewTest : public ::testing::Test {
};
#define PERFETTO_TP_EVENT_VIEW_DEF(NAME, FROM, JOIN, COL, _) \
- NAME(TestEventView, "event_view") \
- FROM(TestEventTable, event) \
- JOIN(TestTrackTable, track, id, event, track_id, View::kIdAlwaysPresent) \
+ NAME(ViewEventView, "event_view") \
+ FROM(ViewEventTable, event) \
+ JOIN(ViewTrackTable, track, id, event, track_id, View::kIdAlwaysPresent) \
COL(id, event, id) \
COL(ts, event, ts) \
COL(track_id, event, track_id) \
COL(track_name, track, name)
PERFETTO_TP_DECLARE_VIEW(PERFETTO_TP_EVENT_VIEW_DEF);
-PERFETTO_TP_DEFINE_VIEW(TestEventView);
+PERFETTO_TP_DEFINE_VIEW(ViewEventView);
-class EventViewTest : public AbstractViewTest<TestEventView> {
+class EventViewTest : public AbstractViewTest<ViewEventView> {
protected:
EventViewTest() {
t1_id_ = track_.Insert({/* name */ Intern("foo")}).id;
@@ -127,26 +97,26 @@ class EventViewTest : public AbstractViewTest<TestEventView> {
event_table_.Insert({/* ts */ 102, t1_id_});
}
- virtual TestEventView& view() override { return event_view_; }
+ virtual ViewEventView& view() override { return event_view_; }
- TestTrackTable::Id t1_id_;
- TestTrackTable::Id t2_id_;
+ ViewTrackTable::Id t1_id_;
+ ViewTrackTable::Id t2_id_;
private:
- TestEventTable event_table_{&pool_, nullptr};
- TestTrackTable track_{&pool_, nullptr};
- TestEventView event_view_{&event_table_, &track_};
+ ViewEventTable event_table_{&pool_};
+ ViewTrackTable track_{&pool_};
+ ViewEventView event_view_{&event_table_, &track_};
};
TEST_F(EventViewTest, UnusedColumnsAreDummy) {
- TestEventView::QueryResult result = QueryUsingCols({ColIdx::track_name});
+ ViewEventView::QueryResult result = QueryUsingCols({ColIdx::track_name});
ASSERT_TRUE(result.columns()[ColIdx::id].IsDummy());
ASSERT_TRUE(result.columns()[ColIdx::ts].IsDummy());
ASSERT_FALSE(result.columns()[ColIdx::track_name].IsDummy());
}
TEST_F(EventViewTest, Iterate) {
- TestEventView::QueryResult result = Query();
+ ViewEventView::QueryResult result = Query();
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.row_number().row_number(), 0u);
@@ -170,13 +140,13 @@ TEST_F(EventViewTest, Iterate) {
}
TEST_F(EventViewTest, FilterEventEmpty) {
- TestEventView::QueryResult result = Query({view().ts().eq(0)});
+ ViewEventView::QueryResult result = Query({view().ts().eq(0)});
auto it = result.IterateRows();
ASSERT_FALSE(it);
}
TEST_F(EventViewTest, FilterEventNoUseTrack) {
- TestEventView::QueryResult result =
+ ViewEventView::QueryResult result =
Query({view().ts().eq(100)}, {}, {ColIdx::ts});
auto it = result.IterateRows();
ASSERT_TRUE(it);
@@ -186,7 +156,7 @@ TEST_F(EventViewTest, FilterEventNoUseTrack) {
}
TEST_F(EventViewTest, FilterEventUseTrack) {
- TestEventView::QueryResult result =
+ ViewEventView::QueryResult result =
Query({view().ts().eq(100)}, {},
{ColIdx::ts, ColIdx::track_name, ColIdx::track_id});
auto it = result.IterateRows();
@@ -199,13 +169,13 @@ TEST_F(EventViewTest, FilterEventUseTrack) {
}
TEST_F(EventViewTest, FilterTrackEmpty) {
- TestEventView::QueryResult result = Query({view().track_id().eq(102398)});
+ ViewEventView::QueryResult result = Query({view().track_id().eq(102398)});
auto it = result.IterateRows();
ASSERT_FALSE(it);
}
TEST_F(EventViewTest, FilterTrackNoUseEvent) {
- TestEventView::QueryResult result =
+ ViewEventView::QueryResult result =
Query({view().track_name().eq("foo")}, {},
{ColIdx::track_name, ColIdx::track_id});
auto it = result.IterateRows();
@@ -221,7 +191,7 @@ TEST_F(EventViewTest, FilterTrackNoUseEvent) {
}
TEST_F(EventViewTest, FilterTrackUseEvent) {
- TestEventView::QueryResult result =
+ ViewEventView::QueryResult result =
Query({view().track_id().eq(t1_id_.value)}, {},
{ColIdx::ts, ColIdx::track_name, ColIdx::track_id});
auto it = result.IterateRows();
@@ -239,10 +209,10 @@ TEST_F(EventViewTest, FilterTrackUseEvent) {
}
#define PERFETTO_TP_THREAD_EVENT_VIEW_DEF(NAME, FROM, JOIN, COL, _) \
- NAME(TestThreadEventView, "thread_event_view") \
- FROM(TestEventTable, event) \
- JOIN(TestThreadTrackTable, track, id, event, track_id, View::kNoFlag) \
- JOIN(TestThreadTable, thread, id, track, utid, View::kIdAlwaysPresent) \
+ NAME(ViewThreadEventView, "thread_event_view") \
+ FROM(ViewEventTable, event) \
+ JOIN(ViewThreadTrackTable, track, id, event, track_id, View::kNoFlag) \
+ JOIN(ViewThreadTable, thread, id, track, utid, View::kIdAlwaysPresent) \
COL(id, event, id) \
COL(ts, event, ts) \
COL(track_id, track, id) \
@@ -250,9 +220,9 @@ TEST_F(EventViewTest, FilterTrackUseEvent) {
COL(utid, track, utid) \
COL(thread_name, thread, name)
PERFETTO_TP_DECLARE_VIEW(PERFETTO_TP_THREAD_EVENT_VIEW_DEF);
-PERFETTO_TP_DEFINE_VIEW(TestThreadEventView);
+PERFETTO_TP_DEFINE_VIEW(ViewThreadEventView);
-class ThreadEventViewTest : public AbstractViewTest<TestThreadEventView> {
+class ThreadEventViewTest : public AbstractViewTest<ViewThreadEventView> {
protected:
ThreadEventViewTest() {
th1_id_ = thread_.Insert({Intern("th1"), 1}).id;
@@ -275,24 +245,24 @@ class ThreadEventViewTest : public AbstractViewTest<TestThreadEventView> {
event_table_.Insert({/* ts */ 107, t4_id_});
}
- virtual TestThreadEventView& view() override { return event_view_; }
+ virtual ViewThreadEventView& view() override { return event_view_; }
- TestThreadTable::Id th1_id_;
- TestThreadTable::Id th2_id_;
+ ViewThreadTable::Id th1_id_;
+ ViewThreadTable::Id th2_id_;
- TestTrackTable::Id t1_id_;
- TestTrackTable::Id t2_id_;
- TestTrackTable::Id t3_id_;
- TestTrackTable::Id t4_id_;
- TestTrackTable::Id t5_id_;
- TestTrackTable::Id t6_id_;
+ ViewTrackTable::Id t1_id_;
+ ViewTrackTable::Id t2_id_;
+ ViewTrackTable::Id t3_id_;
+ ViewTrackTable::Id t4_id_;
+ ViewTrackTable::Id t5_id_;
+ ViewTrackTable::Id t6_id_;
private:
- TestEventTable event_table_{&pool_, nullptr};
- TestTrackTable track_{&pool_, nullptr};
- TestThreadTrackTable thread_track_{&pool_, &track_};
- TestThreadTable thread_{&pool_, nullptr};
- TestThreadEventView event_view_{&event_table_, &thread_track_, &thread_};
+ ViewEventTable event_table_{&pool_};
+ ViewTrackTable track_{&pool_};
+ ViewThreadTrackTable thread_track_{&pool_, &track_};
+ ViewThreadTable thread_{&pool_};
+ ViewThreadEventView event_view_{&event_table_, &thread_track_, &thread_};
};
TEST_F(ThreadEventViewTest, Iterate) {
@@ -427,7 +397,7 @@ TEST_F(ThreadEventViewTest, FilterEventAndThread) {
}
#define PERFETTO_TP_THREAD_SLICE_VIEW_DEF(NAME, FROM, JOIN, COL, _) \
- NAME(TestThreadSliceView, "thread_slice_view") \
+ NAME(ViewThreadSliceView, "thread_slice_view") \
COL(id, slice, id) \
COL(ts, slice, ts) \
COL(name, slice, name) \
@@ -435,13 +405,13 @@ TEST_F(ThreadEventViewTest, FilterEventAndThread) {
COL(track_name, track, name) \
COL(utid, thread, id) \
COL(thread_name, thread, name) \
- FROM(TestSliceTable, slice) \
- JOIN(TestThreadTrackTable, track, id, slice, track_id, View::kNoFlag) \
- JOIN(TestThreadTable, thread, id, track, utid, View::kIdAlwaysPresent)
+ FROM(ViewSliceTable, slice) \
+ JOIN(ViewThreadTrackTable, track, id, slice, track_id, View::kNoFlag) \
+ JOIN(ViewThreadTable, thread, id, track, utid, View::kIdAlwaysPresent)
PERFETTO_TP_DECLARE_VIEW(PERFETTO_TP_THREAD_SLICE_VIEW_DEF);
-PERFETTO_TP_DEFINE_VIEW(TestThreadSliceView);
+PERFETTO_TP_DEFINE_VIEW(ViewThreadSliceView);
-class ThreadSliceViewTest : public AbstractViewTest<TestThreadSliceView> {
+class ThreadSliceViewTest : public AbstractViewTest<ViewThreadSliceView> {
protected:
ThreadSliceViewTest() {
th1_id_ = thread_.Insert({Intern("th1"), 1}).id;
@@ -464,25 +434,25 @@ class ThreadSliceViewTest : public AbstractViewTest<TestThreadSliceView> {
slice_table_.Insert({/* ts */ 107, t4_id_, Intern("ts107")});
}
- TestThreadSliceView& view() override { return slice_view_; }
+ ViewThreadSliceView& view() override { return slice_view_; }
- TestThreadTable::Id th1_id_;
- TestThreadTable::Id th2_id_;
+ ViewThreadTable::Id th1_id_;
+ ViewThreadTable::Id th2_id_;
- TestTrackTable::Id t1_id_;
- TestTrackTable::Id t2_id_;
- TestTrackTable::Id t3_id_;
- TestTrackTable::Id t4_id_;
- TestTrackTable::Id t5_id_;
- TestTrackTable::Id t6_id_;
+ ViewTrackTable::Id t1_id_;
+ ViewTrackTable::Id t2_id_;
+ ViewTrackTable::Id t3_id_;
+ ViewTrackTable::Id t4_id_;
+ ViewTrackTable::Id t5_id_;
+ ViewTrackTable::Id t6_id_;
private:
- TestEventTable event_{&pool_, nullptr};
- TestSliceTable slice_table_{&pool_, &event_};
- TestTrackTable track_{&pool_, nullptr};
- TestThreadTrackTable thread_track_{&pool_, &track_};
- TestThreadTable thread_{&pool_, nullptr};
- TestThreadSliceView slice_view_{&slice_table_, &thread_track_, &thread_};
+ ViewEventTable event_{&pool_};
+ ViewSliceTable slice_table_{&pool_, &event_};
+ ViewTrackTable track_{&pool_};
+ ViewThreadTrackTable thread_track_{&pool_, &track_};
+ ViewThreadTable thread_{&pool_};
+ ViewThreadSliceView slice_view_{&slice_table_, &thread_track_, &thread_};
};
TEST_F(ThreadSliceViewTest, Iterate) {
@@ -600,5 +570,6 @@ TEST_F(ThreadSliceViewTest, FilterAndSort) {
}
} // namespace
+} // namespace tables
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/db/view_unittest.py b/src/trace_processor/db/view_unittest.py
new file mode 100644
index 000000000..a7f7abda7
--- /dev/null
+++ b/src/trace_processor/db/view_unittest.py
@@ -0,0 +1,75 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Contains tables for unitviewing."""
+
+from python.generators.trace_processor_table.public import Column as C
+from python.generators.trace_processor_table.public import ColumnFlag
+from python.generators.trace_processor_table.public import Table
+from python.generators.trace_processor_table.public import CppTableId
+from python.generators.trace_processor_table.public import CppUint32
+from python.generators.trace_processor_table.public import CppInt64
+from python.generators.trace_processor_table.public import CppString
+
+VIEW_THREAD_TABLE = Table(
+ python_module=__file__,
+ class_name="ViewThreadTable",
+ sql_name="thread_table",
+ columns=[
+ C("name", CppString()),
+ C("tid", CppUint32()),
+ ])
+
+VIEW_TRACK_TABLE = Table(
+ python_module=__file__,
+ class_name="ViewTrackTable",
+ sql_name="track_table",
+ columns=[
+ C("name", CppString()),
+ ])
+
+VIEW_THREAD_TRACK_TABLE = Table(
+ python_module=__file__,
+ class_name="ViewThreadTrackTable",
+ sql_name="thread_track_table",
+ parent=VIEW_TRACK_TABLE,
+ columns=[
+ C("utid", CppTableId(VIEW_THREAD_TABLE)),
+ ])
+
+VIEW_EVENT_TABLE = Table(
+ python_module=__file__,
+ class_name="ViewEventTable",
+ sql_name="event_table",
+ columns=[
+ C("ts", CppInt64(), flags=ColumnFlag.SORTED),
+ C("track_id", CppTableId(VIEW_TRACK_TABLE)),
+ ])
+
+VIEW_SLICE_TABLE = Table(
+ python_module=__file__,
+ class_name="ViewSliceTable",
+ sql_name="slice_table",
+ parent=VIEW_EVENT_TABLE,
+ columns=[
+ C("name", CppString()),
+ ])
+
+# Keep this list sorted.
+ALL_TABLES = [
+ VIEW_EVENT_TABLE,
+ VIEW_SLICE_TABLE,
+ VIEW_THREAD_TABLE,
+ VIEW_THREAD_TRACK_TABLE,
+ VIEW_TRACK_TABLE,
+]
diff --git a/src/trace_processor/importers/common/args_translation_table.cc b/src/trace_processor/importers/common/args_translation_table.cc
index 74cdc34cd..8aa9a0d82 100644
--- a/src/trace_processor/importers/common/args_translation_table.cc
+++ b/src/trace_processor/importers/common/args_translation_table.cc
@@ -52,25 +52,6 @@ std::string ExtractMojoInterfaceTag(const std::string& method_symbol) {
} // namespace
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-constexpr char ArgsTranslationTable::kChromeHistogramHashKey[];
-constexpr char ArgsTranslationTable::kChromeHistogramNameKey[];
-
-constexpr char ArgsTranslationTable::kChromeUserEventHashKey[];
-constexpr char ArgsTranslationTable::kChromeUserEventActionKey[];
-
-constexpr char ArgsTranslationTable::kChromePerformanceMarkSiteHashKey[];
-constexpr char ArgsTranslationTable::kChromePerformanceMarkSiteKey[];
-
-constexpr char ArgsTranslationTable::kChromePerformanceMarkMarkHashKey[];
-constexpr char ArgsTranslationTable::kChromePerformanceMarkMarkKey[];
-
-constexpr char ArgsTranslationTable::kMojoMethodMappingIdKey[];
-constexpr char ArgsTranslationTable::kMojoMethodRelPcKey[];
-constexpr char ArgsTranslationTable::kMojoMethodNameKey[];
-constexpr char ArgsTranslationTable::kMojoIntefaceTagKey[];
-#endif
-
ArgsTranslationTable::ArgsTranslationTable(TraceStorage* storage)
: storage_(storage),
interned_chrome_histogram_hash_key_(
diff --git a/src/trace_processor/importers/common/track_tracker.cc b/src/trace_processor/importers/common/track_tracker.cc
index 07bd84837..f6a99f1ff 100644
--- a/src/trace_processor/importers/common/track_tracker.cc
+++ b/src/trace_processor/importers/common/track_tracker.cc
@@ -16,12 +16,43 @@
#include "src/trace_processor/importers/common/track_tracker.h"
+#include <optional>
+
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/storage/trace_storage.h"
namespace perfetto {
namespace trace_processor {
+namespace {
+
+const char* GetNameForGroup(TrackTracker::Group group) {
+ switch (group) {
+ case TrackTracker::Group::kMemory:
+ return "Memory";
+ case TrackTracker::Group::kIo:
+ return "IO";
+ case TrackTracker::Group::kVirtio:
+ return "Virtio";
+ case TrackTracker::Group::kNetwork:
+ return "Network";
+ case TrackTracker::Group::kPower:
+ return "Power";
+ case TrackTracker::Group::kDeviceState:
+ return "Device State";
+ case TrackTracker::Group::kThermals:
+ return "Thermals";
+ case TrackTracker::Group::kClockFrequency:
+ return "Clock Freqeuncy";
+ case TrackTracker::Group::kSizeSentinel:
+ PERFETTO_FATAL("Unexpected size passed as group");
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+} // namespace
+
TrackTracker::TrackTracker(TraceProcessorContext* context)
: source_key_(context->storage->InternString("source")),
source_id_key_(context->storage->InternString("source_id")),
@@ -193,7 +224,8 @@ TrackId TrackTracker::GetOrCreateTriggerTrack() {
return *trigger_track_id_;
}
-TrackId TrackTracker::InternGlobalCounterTrack(StringId name,
+TrackId TrackTracker::InternGlobalCounterTrack(TrackTracker::Group group,
+ StringId name,
SetArgsCallback callback,
StringId unit,
StringId description) {
@@ -203,6 +235,7 @@ TrackId TrackTracker::InternGlobalCounterTrack(StringId name,
}
tables::CounterTrackTable::Row row(name);
+ row.parent_id = InternTrackForGroup(group);
row.unit = unit;
row.description = description;
TrackId track =
@@ -380,5 +413,18 @@ TrackId TrackTracker::CreatePerfCounterTrack(StringId name,
return context_->storage->mutable_perf_counter_track_table()->Insert(row).id;
}
+TrackId TrackTracker::InternTrackForGroup(TrackTracker::Group group) {
+ uint32_t group_idx = static_cast<uint32_t>(group);
+ const std::optional<TrackId>& group_id = group_track_ids_[group_idx];
+ if (group_id) {
+ return *group_id;
+ }
+
+ StringId id = context_->storage->InternString(GetNameForGroup(group));
+ TrackId track_id = context_->storage->mutable_track_table()->Insert({id}).id;
+ group_track_ids_[group_idx] = track_id;
+ return track_id;
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/common/track_tracker.h b/src/trace_processor/importers/common/track_tracker.h
index c4a423262..99076f349 100644
--- a/src/trace_processor/importers/common/track_tracker.h
+++ b/src/trace_processor/importers/common/track_tracker.h
@@ -17,6 +17,7 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_TRACK_TRACKER_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_TRACK_TRACKER_H_
+#include <optional>
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
@@ -27,6 +28,23 @@ namespace trace_processor {
// Tracks and stores tracks based on track types, ids and scopes.
class TrackTracker {
public:
+ // Enum which groups global tracks to avoid an explosion of tracks at the top
+ // level.
+ // Try and keep members of this enum high level as every entry here
+ // corresponds to ~1 extra UI track.
+ enum class Group : uint32_t {
+ kMemory = 0,
+ kIo,
+ kVirtio,
+ kNetwork,
+ kPower,
+ kDeviceState,
+ kThermals,
+ kClockFrequency,
+
+ // Keep this last.
+ kSizeSentinel,
+ };
using SetArgsCallback = std::function<void(ArgsTracker::BoundInserter&)>;
explicit TrackTracker(TraceProcessorContext*);
@@ -67,7 +85,8 @@ class TrackTracker {
TrackId GetOrCreateTriggerTrack();
// Interns a global counter track into the storage.
- TrackId InternGlobalCounterTrack(StringId name,
+ TrackId InternGlobalCounterTrack(Group group,
+ StringId name,
SetArgsCallback = {},
StringId unit = kNullStringId,
StringId description = kNullStringId);
@@ -155,6 +174,12 @@ class TrackTracker {
std::tie(r.source_id, r.upid, r.source_scope);
}
};
+ static constexpr size_t kGroupCount =
+ static_cast<uint32_t>(Group::kSizeSentinel);
+
+ TrackId InternTrackForGroup(Group group);
+
+ std::array<std::optional<TrackId>, kGroupCount> group_track_ids_;
std::map<UniqueTid, TrackId> thread_tracks_;
std::map<UniquePid, TrackId> process_tracks_;
diff --git a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
index 033d24730..27df202e2 100644
--- a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
@@ -24,7 +24,7 @@ namespace perfetto {
namespace trace_processor {
namespace {
-std::array<FtraceMessageDescriptor, 482> descriptors{{
+std::array<FtraceMessageDescriptor, 484> descriptors{{
{nullptr, 0, {}},
{nullptr, 0, {}},
{nullptr, 0, {}},
@@ -5303,6 +5303,26 @@ std::array<FtraceMessageDescriptor, 482> descriptors{{
{"start", ProtoSchemaType::kUint32},
},
},
+ {
+ "mali_mali_CSF_INTERRUPT_START",
+ 3,
+ {
+ {},
+ {"kctx_tgid", ProtoSchemaType::kInt32},
+ {"kctx_id", ProtoSchemaType::kUint32},
+ {"info_val", ProtoSchemaType::kUint64},
+ },
+ },
+ {
+ "mali_mali_CSF_INTERRUPT_END",
+ 3,
+ {
+ {},
+ {"kctx_tgid", ProtoSchemaType::kInt32},
+ {"kctx_id", ProtoSchemaType::kUint32},
+ {"info_val", ProtoSchemaType::kUint64},
+ },
+ },
}};
} // namespace
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 29af4bccf..ec5f26462 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -25,6 +25,7 @@
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/binder_tracker.h"
#include "src/trace_processor/importers/ftrace/thread_state_tracker.h"
#include "src/trace_processor/importers/ftrace/v4l2_tracker.h"
@@ -70,6 +71,7 @@
#include "protos/perfetto/trace/ftrace/signal.pbzero.h"
#include "protos/perfetto/trace/ftrace/skb.pbzero.h"
#include "protos/perfetto/trace/ftrace/sock.pbzero.h"
+#include "protos/perfetto/trace/ftrace/synthetic.pbzero.h"
#include "protos/perfetto/trace/ftrace/systrace.pbzero.h"
#include "protos/perfetto/trace/ftrace/task.pbzero.h"
#include "protos/perfetto/trace/ftrace/tcp.pbzero.h"
@@ -231,6 +233,10 @@ FtraceParser::FtraceParser(TraceProcessorContext* context)
cpu_idle_name_id_(context->storage->InternString("cpuidle")),
suspend_resume_name_id_(
context->storage->InternString("Suspend/Resume Latency")),
+ suspend_resume_minimal_name_id_(
+ context->storage->InternString("Suspend/Resume Minimal")),
+ suspend_resume_minimal_slice_name_id_(
+ context->storage->InternString("Suspended")),
kfree_skb_name_id_(context->storage->InternString("Kfree Skb IP Prot")),
ion_total_id_(context->storage->InternString("mem.ion")),
ion_change_id_(context->storage->InternString("mem.ion_change")),
@@ -869,6 +875,10 @@ util::Status FtraceParser::ParseFtraceEvent(uint32_t cpu,
ParseSuspendResume(ts, fld_bytes);
break;
}
+ case FtraceEvent::kSuspendResumeMinimalFieldNumber: {
+ ParseSuspendResumeMinimal(ts, fld_bytes);
+ break;
+ }
case FtraceEvent::kDrmVblankEventFieldNumber:
case FtraceEvent::kDrmVblankEventDeliveredFieldNumber:
case FtraceEvent::kDrmSchedJobFieldNumber:
@@ -1013,6 +1023,12 @@ util::Status FtraceParser::ParseFtraceEvent(uint32_t cpu,
mali_gpu_event_tracker_.ParseMaliGpuEvent(ts, fld.id(), pid);
break;
}
+ case FtraceEvent::kMaliMaliCSFINTERRUPTSTARTFieldNumber:
+ case FtraceEvent::kMaliMaliCSFINTERRUPTENDFieldNumber: {
+ mali_gpu_event_tracker_.ParseMaliGpuIrqEvent(ts, fld.id(), cpu,
+ fld_bytes);
+ break;
+ }
default:
break;
@@ -1097,7 +1113,7 @@ void FtraceParser::ParseGenericFtrace(int64_t ts,
protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
StringId event_id = context_->storage->InternString(evt.event_name());
UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
- RawId id = context_->storage->mutable_raw_table()
+ RawId id = context_->storage->mutable_ftrace_event_table()
->Insert({ts, event_id, cpu, utid})
.id;
auto inserter = context_->args_tracker->AddArgsTo(id);
@@ -1139,7 +1155,7 @@ void FtraceParser::ParseTypedFtraceToRaw(
const auto& message_strings = ftrace_message_strings_[ftrace_id];
UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
RawId id =
- context_->storage->mutable_raw_table()
+ context_->storage->mutable_ftrace_event_table()
->Insert({timestamp, message_strings.message_name_id, cpu, utid})
.id;
auto inserter = context_->args_tracker->AddArgsTo(id);
@@ -1428,8 +1444,8 @@ void FtraceParser::ParseIonHeapGrowOrShrink(int64_t timestamp,
}
// Push the global counter.
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(global_name_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kMemory, global_name_id);
context_->event_tracker->PushCounter(timestamp,
static_cast<double>(total_bytes), track);
@@ -1466,8 +1482,8 @@ void FtraceParser::ParseIonStat(int64_t timestamp,
protozero::ConstBytes data) {
protos::pbzero::IonStatFtraceEvent::Decoder ion(data.data, data.size);
// Push the global counter.
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(ion_total_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kMemory, ion_total_id_);
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(ion.total_allocated()), track);
@@ -1502,8 +1518,8 @@ void FtraceParser::ParseDmaHeapStat(int64_t timestamp,
protos::pbzero::DmaHeapStatFtraceEvent::Decoder dma_heap(data.data,
data.size);
// Push the global counter.
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(dma_heap_total_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kMemory, dma_heap_total_id_);
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(dma_heap.total_allocated()), track);
@@ -1815,7 +1831,8 @@ void FtraceParser::ClockRate(int64_t timestamp,
clock_name.data(), int(subtitle.size()),
subtitle.data());
StringId name = context_->storage->InternString(counter_name.c_str());
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kClockFrequency, name);
context_->event_tracker->PushCounter(timestamp, static_cast<double>(rate),
track);
}
@@ -2090,8 +2107,8 @@ void FtraceParser::ParseGpuMemTotal(int64_t timestamp,
if (pid == 0) {
// Pid 0 is used to indicate the global total
track = context_->track_tracker->InternGlobalCounterTrack(
- gpu_mem_total_name_id_, {}, gpu_mem_total_unit_id_,
- gpu_mem_total_global_desc_id_);
+ TrackTracker::Group::kMemory, gpu_mem_total_name_id_, {},
+ gpu_mem_total_unit_id_, gpu_mem_total_global_desc_id_);
} else {
// It's possible for GpuMemTotal ftrace events to be emitted by kworker
// threads *after* process death. In this case, we simply want to discard
@@ -2129,7 +2146,8 @@ void FtraceParser::ParseThermalTemperature(int64_t timestamp,
base::StackString<255> counter_name(
"%.*s Temperature", int(thermal_zone.size()), thermal_zone.data());
StringId name = context_->storage->InternString(counter_name.string_view());
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kThermals, name);
context_->event_tracker->PushCounter(timestamp, event.temp(), track);
}
@@ -2140,7 +2158,8 @@ void FtraceParser::ParseCdevUpdate(int64_t timestamp,
base::StackString<255> counter_name("%.*s Cooling Device", int(type.size()),
type.data());
StringId name = context_->storage->InternString(counter_name.string_view());
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kThermals, name);
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(event.target()), track);
}
@@ -2192,7 +2211,8 @@ void FtraceParser::ParseFastRpcDmaStat(int64_t timestamp,
}
// Push the global counter.
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(total_name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kMemory, total_name);
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(event.total_allocated()), track);
@@ -2225,7 +2245,8 @@ void FtraceParser::ParseNetifReceiveSkb(uint32_t cpu,
nic_received_bytes_[name] += event.len();
uint64_t nic_received_kilobytes = nic_received_bytes_[name] / 1024;
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kNetwork, name);
std::optional<CounterId> id = context_->event_tracker->PushCounter(
timestamp, static_cast<double>(nic_received_kilobytes), track);
if (!id) {
@@ -2256,7 +2277,8 @@ void FtraceParser::ParseNetDevXmit(uint32_t cpu,
nic_transmitted_bytes_[name] += evt.len();
uint64_t nic_transmitted_kilobytes = nic_transmitted_bytes_[name] / 1024;
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kNetwork, name);
std::optional<CounterId> id = context_->event_tracker->PushCounter(
timestamp, static_cast<double>(nic_transmitted_kilobytes), track);
if (!id) {
@@ -2392,14 +2414,14 @@ void FtraceParser::ParseCpuFrequencyLimits(int64_t timestamp,
// Push max freq to global counter.
StringId max_name = context_->storage->InternString(max_counter_name.c_str());
TrackId max_track =
- context_->track_tracker->InternGlobalCounterTrack(max_name);
+ context_->track_tracker->InternCpuCounterTrack(max_name, evt.cpu_id());
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(evt.max_freq()), max_track);
// Push min freq to global counter.
StringId min_name = context_->storage->InternString(min_counter_name.c_str());
TrackId min_track =
- context_->track_tracker->InternGlobalCounterTrack(min_name);
+ context_->track_tracker->InternCpuCounterTrack(min_name, evt.cpu_id());
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(evt.min_freq()), min_track);
}
@@ -2414,8 +2436,8 @@ void FtraceParser::ParseKfreeSkb(int64_t timestamp,
}
num_of_kfree_skb_ip_prot += 1;
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(kfree_skb_name_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kNetwork, kfree_skb_name_id_);
std::optional<CounterId> id = context_->event_tracker->PushCounter(
timestamp, static_cast<double>(num_of_kfree_skb_ip_prot), track);
if (!id) {
@@ -2435,6 +2457,7 @@ void FtraceParser::ParseCrosEcSensorhubData(int64_t timestamp,
// Push the global counter.
TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kDeviceState,
context_->storage->InternString(
base::StringView("cros_ec.cros_ec_sensorhub_data." +
std::to_string(evt.ec_sensor_num()))));
@@ -2474,8 +2497,8 @@ void FtraceParser::ParseUfshcdClkGating(int64_t timestamp,
clk_state = 2;
break;
}
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(ufs_clkgating_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kNetwork, ufs_clkgating_id_);
context_->event_tracker->PushCounter(timestamp,
static_cast<double>(clk_state), track);
}
@@ -2796,8 +2819,8 @@ void FtraceParser::ParseUfshcdCommand(int64_t timestamp,
uint32_t num = evt.doorbell() > 0
? static_cast<uint32_t>(PERFETTO_POPCOUNT(evt.doorbell()))
: (evt.str_t() == 1 ? 0 : 1);
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(ufs_command_count_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kIo, ufs_command_count_id_);
context_->event_tracker->PushCounter(timestamp, static_cast<double>(num),
track);
@@ -2910,6 +2933,26 @@ void FtraceParser::ParseSuspendResume(int64_t timestamp,
ongoing_suspend_resume_actions[current_action] = true;
}
+void FtraceParser::ParseSuspendResumeMinimal(int64_t timestamp,
+ protozero::ConstBytes blob) {
+ protos::pbzero::SuspendResumeMinimalFtraceEvent::Decoder evt(blob.data,
+ blob.size);
+ auto async_track = context_->async_track_set_tracker->InternGlobalTrackSet(
+ suspend_resume_minimal_name_id_);
+
+ if (evt.start()) {
+ TrackId start_id = context_->async_track_set_tracker->Begin(
+ async_track, static_cast<int64_t>(0));
+ context_->slice_tracker->Begin(timestamp, start_id,
+ suspend_resume_minimal_name_id_,
+ suspend_resume_minimal_slice_name_id_);
+ } else {
+ TrackId end_id = context_->async_track_set_tracker->End(
+ async_track, static_cast<int64_t>(0));
+ context_->slice_tracker->End(timestamp, end_id);
+ }
+}
+
void FtraceParser::ParseSchedCpuUtilCfs(int64_t timestamp,
protozero::ConstBytes blob) {
protos::pbzero::SchedCpuUtilCfsFtraceEvent::Decoder evt(blob.data, blob.size);
@@ -2917,8 +2960,8 @@ void FtraceParser::ParseSchedCpuUtilCfs(int64_t timestamp,
StringId util_track_name_id =
context_->storage->InternString(util_track_name.string_view());
- TrackId util_track =
- context_->track_tracker->InternGlobalCounterTrack(util_track_name_id);
+ TrackId util_track = context_->track_tracker->InternCpuCounterTrack(
+ util_track_name_id, evt.cpu());
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(evt.cpu_util()), util_track);
@@ -2926,8 +2969,8 @@ void FtraceParser::ParseSchedCpuUtilCfs(int64_t timestamp,
StringId cap_track_name_id =
context_->storage->InternString(cap_track_name.string_view());
- TrackId cap_track =
- context_->track_tracker->InternGlobalCounterTrack(cap_track_name_id);
+ TrackId cap_track = context_->track_tracker->InternCpuCounterTrack(
+ cap_track_name_id, evt.cpu());
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(evt.capacity()), cap_track);
@@ -2936,8 +2979,8 @@ void FtraceParser::ParseSchedCpuUtilCfs(int64_t timestamp,
StringId nrr_track_name_id =
context_->storage->InternString(nrr_track_name.string_view());
- TrackId nrr_track =
- context_->track_tracker->InternGlobalCounterTrack(nrr_track_name_id);
+ TrackId nrr_track = context_->track_tracker->InternCpuCounterTrack(
+ nrr_track_name_id, evt.cpu());
context_->event_tracker->PushCounter(
timestamp, static_cast<double>(evt.nr_running()), nrr_track);
}
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index abfb0e3ef..ccb40f8dd 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -216,6 +216,7 @@ class FtraceParser {
void ParseWakeSourceActivate(int64_t timestamp, protozero::ConstBytes);
void ParseWakeSourceDeactivate(int64_t timestamp, protozero::ConstBytes);
void ParseSuspendResume(int64_t timestamp, protozero::ConstBytes);
+ void ParseSuspendResumeMinimal(int64_t timestamp, protozero::ConstBytes);
void ParseSchedCpuUtilCfs(int64_t timestap, protozero::ConstBytes);
void ParseFuncgraphEntry(int64_t timestamp,
@@ -288,6 +289,8 @@ class FtraceParser {
const StringId gpu_freq_name_id_;
const StringId cpu_idle_name_id_;
const StringId suspend_resume_name_id_;
+ const StringId suspend_resume_minimal_name_id_;
+ const StringId suspend_resume_minimal_slice_name_id_;
const StringId kfree_skb_name_id_;
const StringId ion_total_id_;
const StringId ion_change_id_;
diff --git a/src/trace_processor/importers/ftrace/iostat_tracker.cc b/src/trace_processor/importers/ftrace/iostat_tracker.cc
index 27e576204..d3c40d8f8 100644
--- a/src/trace_processor/importers/ftrace/iostat_tracker.cc
+++ b/src/trace_processor/importers/ftrace/iostat_tracker.cc
@@ -43,8 +43,8 @@ void IostatTracker::ParseF2fsIostat(int64_t timestamp,
uint64_t value) {
std::string track_name = tagPrefix + "." + std::string(counter_name);
StringId string_id = context_->storage->InternString(track_name.c_str());
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(string_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kIo, string_id);
context_->event_tracker->PushCounter(timestamp, static_cast<double>(value),
track);
};
@@ -83,8 +83,8 @@ void IostatTracker::ParseF2fsIostatLatency(int64_t timestamp,
uint64_t value) {
std::string track_name = tagPrefix + "." + std::string(counter_name);
StringId string_id = context_->storage->InternString(track_name.c_str());
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(string_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kIo, string_id);
context_->event_tracker->PushCounter(timestamp, static_cast<double>(value),
track);
};
diff --git a/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.cc b/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.cc
index c59bdcced..406479764 100644
--- a/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.cc
+++ b/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h"
+#include "perfetto/ext/base/string_utils.h"
#include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
#include "protos/perfetto/trace/ftrace/mali.pbzero.h"
#include "src/trace_processor/importers/common/async_track_set_tracker.h"
@@ -35,7 +36,11 @@ MaliGpuEventTracker::MaliGpuEventTracker(TraceProcessorContext* context)
mali_KCPU_FENCE_SIGNAL_id_(
context->storage->InternString("mali_KCPU_FENCE_SIGNAL")),
mali_KCPU_FENCE_WAIT_id_(
- context->storage->InternString("mali_KCPU_FENCE_WAIT")) {}
+ context->storage->InternString("mali_KCPU_FENCE_WAIT")),
+ mali_CSF_INTERRUPT_id_(
+ context->storage->InternString("mali_CSF_INTERRUPT")),
+ mali_CSF_INTERRUPT_info_val_id_(
+ context->storage->InternString("info_val")) {}
void MaliGpuEventTracker::ParseMaliGpuEvent(int64_t ts,
int32_t field_id,
@@ -76,6 +81,36 @@ void MaliGpuEventTracker::ParseMaliGpuEvent(int64_t ts,
}
}
+void MaliGpuEventTracker::ParseMaliGpuIrqEvent(int64_t ts,
+ int32_t field_id,
+ uint32_t cpu,
+ protozero::ConstBytes blob) {
+ using protos::pbzero::FtraceEvent;
+
+ // Since these events are called from an interrupt context they cannot be
+ // associated to a single process or thread. Add to a custom Mali Irq track
+ // instead.
+ base::StackString<255> track_name("Mali Irq Cpu %d", cpu);
+ StringId track_name_id =
+ context_->storage->InternString(track_name.string_view());
+ TrackId track_id =
+ context_->track_tracker->InternCpuTrack(track_name_id, cpu);
+
+ switch (field_id) {
+ case FtraceEvent::kMaliMaliCSFINTERRUPTSTARTFieldNumber: {
+ ParseMaliCSFInterruptStart(ts, track_id, blob);
+ break;
+ }
+ case FtraceEvent::kMaliMaliCSFINTERRUPTENDFieldNumber: {
+ ParseMaliCSFInterruptEnd(ts, track_id, blob);
+ break;
+ }
+ default:
+ PERFETTO_DFATAL("Unexpected field id");
+ break;
+ }
+}
+
void MaliGpuEventTracker::ParseMaliKcpuCqsSet(int64_t timestamp,
TrackId track_id) {
context_->slice_tracker->Scoped(timestamp, track_id, kNullStringId,
@@ -111,5 +146,34 @@ void MaliGpuEventTracker::ParseMaliKcpuFenceWaitEnd(int64_t timestamp,
context_->slice_tracker->End(timestamp, track_id, kNullStringId,
mali_KCPU_FENCE_WAIT_id_);
}
+
+void MaliGpuEventTracker::ParseMaliCSFInterruptStart(
+ int64_t timestamp,
+ TrackId track_id,
+ protozero::ConstBytes blob) {
+ protos::pbzero::MaliMaliCSFINTERRUPTSTARTFtraceEvent::Decoder evt(blob.data,
+ blob.size);
+ auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
+ inserter->AddArg(mali_CSF_INTERRUPT_info_val_id_,
+ Variadic::UnsignedInteger(evt.info_val()));
+ };
+
+ context_->slice_tracker->Begin(timestamp, track_id, kNullStringId,
+ mali_CSF_INTERRUPT_id_, args_inserter);
+}
+
+void MaliGpuEventTracker::ParseMaliCSFInterruptEnd(int64_t timestamp,
+ TrackId track_id,
+ protozero::ConstBytes blob) {
+ protos::pbzero::MaliMaliCSFINTERRUPTSTARTFtraceEvent::Decoder evt(blob.data,
+ blob.size);
+ auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
+ inserter->AddArg(mali_CSF_INTERRUPT_info_val_id_,
+ Variadic::UnsignedInteger(evt.info_val()));
+ };
+
+ context_->slice_tracker->End(timestamp, track_id, kNullStringId,
+ mali_CSF_INTERRUPT_id_, args_inserter);
+}
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h b/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h
index 9f74c6313..934266671 100644
--- a/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h
+++ b/src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h
@@ -18,6 +18,7 @@
#define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_MALI_GPU_EVENT_TRACKER_H_
#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/util/descriptors.h"
namespace perfetto {
namespace trace_processor {
@@ -28,6 +29,10 @@ class MaliGpuEventTracker {
public:
explicit MaliGpuEventTracker(TraceProcessorContext*);
void ParseMaliGpuEvent(int64_t timestamp, int32_t field_id, uint32_t pid);
+ void ParseMaliGpuIrqEvent(int64_t timestamp,
+ int32_t field_id,
+ uint32_t cpu,
+ protozero::ConstBytes blob);
private:
TraceProcessorContext* context_;
@@ -35,12 +40,20 @@ class MaliGpuEventTracker {
StringId mali_KCPU_CQS_WAIT_id_;
StringId mali_KCPU_FENCE_SIGNAL_id_;
StringId mali_KCPU_FENCE_WAIT_id_;
+ StringId mali_CSF_INTERRUPT_id_;
+ StringId mali_CSF_INTERRUPT_info_val_id_;
void ParseMaliKcpuFenceSignal(int64_t timestamp, TrackId track_id);
void ParseMaliKcpuFenceWaitStart(int64_t timestamp, TrackId track_id);
void ParseMaliKcpuFenceWaitEnd(int64_t timestamp, TrackId track_id);
void ParseMaliKcpuCqsSet(int64_t timestamp, TrackId track_id);
void ParseMaliKcpuCqsWaitStart(int64_t timestamp, TrackId track_id);
void ParseMaliKcpuCqsWaitEnd(int64_t timestamp, TrackId track_id);
+ void ParseMaliCSFInterruptStart(int64_t timestamp,
+ TrackId track_id,
+ protozero::ConstBytes blob);
+ void ParseMaliCSFInterruptEnd(int64_t timestamp,
+ TrackId track_id,
+ protozero::ConstBytes blob);
};
} // namespace trace_processor
diff --git a/src/trace_processor/importers/ftrace/sched_event_tracker.cc b/src/trace_processor/importers/ftrace/sched_event_tracker.cc
index f67e5717a..68fe3b7ed 100644
--- a/src/trace_processor/importers/ftrace/sched_event_tracker.cc
+++ b/src/trace_processor/importers/ftrace/sched_event_tracker.cc
@@ -240,7 +240,7 @@ void SchedEventTracker::PushSchedWakingCompact(uint32_t cpu,
if (PERFETTO_LIKELY(context_->config.ingest_ftrace_in_raw_table)) {
// Add an entry to the raw table.
- RawId id = context_->storage->mutable_raw_table()
+ RawId id = context_->storage->mutable_ftrace_event_table()
->Insert({ts, sched_waking_id_, cpu, curr_utid})
.id;
@@ -277,7 +277,7 @@ uint32_t SchedEventTracker::AddRawEventAndStartSlice(uint32_t cpu,
if (PERFETTO_LIKELY(context_->config.ingest_ftrace_in_raw_table)) {
// Push the raw event - this is done as the raw ftrace event codepath does
// not insert sched_switch.
- RawId id = context_->storage->mutable_raw_table()
+ RawId id = context_->storage->mutable_ftrace_event_table()
->Insert({ts, sched_switch_id_, cpu, prev_utid})
.id;
diff --git a/src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc b/src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc
index d4d09a2ca..9813311c1 100644
--- a/src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc
+++ b/src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc
@@ -160,8 +160,8 @@ VirtioGpuTracker::VirtioGpuQueue::VirtioGpuQueue(TraceProcessorContext* context,
void VirtioGpuTracker::VirtioGpuQueue::HandleNumFree(int64_t timestamp,
uint32_t num_free) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(num_free_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kVirtio, num_free_id_);
context_->event_tracker->PushCounter(timestamp, static_cast<double>(num_free),
track);
}
@@ -201,10 +201,10 @@ void VirtioGpuTracker::VirtioGpuQueue::HandleCmdResponse(int64_t timestamp,
int64_t duration = timestamp - *start_timestamp;
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(latency_id_);
- context_->event_tracker->PushCounter(timestamp,
- static_cast<double>(duration), track);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kVirtio, latency_id_);
+ context_->event_tracker->PushCounter(timestamp, static_cast<double>(duration),
+ track);
start_timestamps_.Erase(seqno);
}
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
index 8acc4509e..e61a13714 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
@@ -333,6 +333,44 @@ TEST_F(FuchsiaTraceParserTest, InlineInstantEvent) {
EXPECT_EQ(context_.storage->stats()[stats::fuchsia_invalid_event].value, 0);
}
+TEST_F(FuchsiaTraceParserTest, BooleanArguments) {
+ // Inline name of 8 bytes
+ uint64_t name_ref = uint64_t{0x8008} << 48;
+ // Inline category of 8 bytes
+ uint64_t category_ref = uint64_t{0x8008} << 32;
+ // Inline threadref
+ uint64_t threadref = uint64_t{0};
+ // 2 arguments
+ uint64_t argument_count = uint64_t{2} << 20;
+ // Instant Event
+ uint64_t event_type = 0 << 16;
+ uint64_t size = 8 << 4;
+ uint64_t record_type = 4;
+
+ auto header = name_ref | category_ref | threadref | event_type |
+ argument_count | size | record_type;
+ push_word(header);
+ // Timestamp
+ push_word(0xAAAAAAAAAAAAAAAA);
+ // Pid + tid
+ push_word(0xBBBBBBBBBBBBBBBB);
+ push_word(0xCCCCCCCCCCCCCCCC);
+ // Inline Category
+ push_word(0xDDDDDDDDDDDDDDDD);
+ // Inline Name
+ push_word(0xEEEEEEEEEEEEEEEE);
+ // Boolean argument true
+ push_word(0x0000'0001'8008'0029);
+ // 8 byte arg name stream
+ push_word(0x0000'0000'0000'0000);
+ // Boolean argument false
+ push_word(0x0000'0000'8008'002A);
+ // 8 byte arg name stream
+ push_word(0x0000'0000'0000'0000);
+ EXPECT_TRUE(Tokenize().ok());
+ EXPECT_EQ(context_.storage->stats()[stats::fuchsia_invalid_event].value, 0);
+}
+
TEST_F(FuchsiaTraceParserTest, FxtWithProtos) {
// Serialize some protos to bytes
protozero::HeapBuffered<protos::pbzero::Trace> protos;
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc b/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
index 014306013..0b18a7779 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
@@ -55,6 +55,7 @@ constexpr uint32_t kDouble = 5;
constexpr uint32_t kString = 6;
constexpr uint32_t kPointer = 7;
constexpr uint32_t kKoid = 8;
+constexpr uint32_t kBool = 9;
} // namespace
@@ -169,6 +170,11 @@ FuchsiaTraceParser::ParseArgs(
arg.value = fuchsia_trace_utils::ArgValue::Koid(value);
break;
}
+ case kBool: {
+ arg.value = fuchsia_trace_utils::ArgValue::Bool(
+ fuchsia_trace_utils::ReadField<bool>(arg_header, 32, 63));
+ break;
+ }
default:
arg.value = fuchsia_trace_utils::ArgValue::Unknown();
break;
@@ -325,6 +331,7 @@ void FuchsiaTraceParser::ParseFuchsiaRecord(int64_t, FuchsiaRecord fr) {
case fuchsia_trace_utils::ArgValue::kString:
case fuchsia_trace_utils::ArgValue::kPointer:
case fuchsia_trace_utils::ArgValue::kKoid:
+ case fuchsia_trace_utils::ArgValue::kBool:
case fuchsia_trace_utils::ArgValue::kUnknown:
context_->storage->IncrementStats(
stats::fuchsia_non_numeric_counters);
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.cc b/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.cc
index 47de0f8ac..48dfe2e70 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.cc
@@ -83,6 +83,8 @@ Variadic ArgValue::ToStorageVariadic(TraceStorage* storage) const {
return Variadic::Pointer(pointer_);
case ArgType::kKoid:
return Variadic::Integer(static_cast<int64_t>(koid_));
+ case ArgType::kBool:
+ return Variadic::Boolean(bool_);
case ArgType::kUnknown:
return Variadic::String(storage->InternString("unknown"));
}
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h b/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h
index f4ae23170..d4a3efa60 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h
+++ b/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h
@@ -52,6 +52,7 @@ class ArgValue {
kString,
kPointer,
kKoid,
+ kBool,
kUnknown,
};
@@ -118,6 +119,13 @@ class ArgValue {
return v;
}
+ static ArgValue Bool(bool value) {
+ ArgValue v;
+ v.type_ = ArgType::kBool;
+ v.bool_ = value;
+ return v;
+ }
+
static ArgValue Unknown() {
ArgValue v;
v.type_ = ArgType::kUnknown;
@@ -167,6 +175,11 @@ class ArgValue {
return koid_;
}
+ uint64_t Bool() const {
+ PERFETTO_DCHECK(type_ == ArgType::kBool);
+ return bool_;
+ }
+
Variadic ToStorageVariadic(TraceStorage*) const;
private:
@@ -180,6 +193,7 @@ class ArgValue {
StringId string_;
uint64_t pointer_;
uint64_t koid_;
+ bool bool_;
};
};
diff --git a/src/trace_processor/importers/proto/android_camera_event_module.h b/src/trace_processor/importers/proto/android_camera_event_module.h
index 88e747671..1d550818e 100644
--- a/src/trace_processor/importers/proto/android_camera_event_module.h
+++ b/src/trace_processor/importers/proto/android_camera_event_module.h
@@ -24,7 +24,7 @@
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
-#include "src/trace_processor/tables/slice_tables.h"
+#include "src/trace_processor/tables/slice_tables_py.h"
#include "src/trace_processor/tables/track_tables_py.h"
#include "src/trace_processor/types/trace_processor_context.h"
diff --git a/src/trace_processor/importers/proto/android_probes_module.cc b/src/trace_processor/importers/proto/android_probes_module.cc
index e1feb51e1..fece0079e 100644
--- a/src/trace_processor/importers/proto/android_probes_module.cc
+++ b/src/trace_processor/importers/proto/android_probes_module.cc
@@ -155,7 +155,8 @@ ModuleResult AndroidProbesModule::TokenizePacket(
StringId counter_name_id =
context_->storage->InternString(counter_name.string_view());
TrackId track = context_->track_tracker->InternGlobalCounterTrack(
- counter_name_id, [this, &desc](ArgsTracker::BoundInserter& inserter) {
+ TrackTracker::Group::kPower, counter_name_id,
+ [this, &desc](ArgsTracker::BoundInserter& inserter) {
StringId raw_name = context_->storage->InternString(desc.rail_name());
inserter.AddArg(power_rail_raw_name_id_, Variadic::String(raw_name));
@@ -180,7 +181,9 @@ ModuleResult AndroidProbesModule::TokenizePacket(
: packet_timestamp;
protozero::HeapBuffered<protos::pbzero::TracePacket> data_packet;
- data_packet->set_timestamp(static_cast<uint64_t>(actual_ts));
+ // Keep the original timestamp to later extract as an arg; the sorter does
+ // not read this.
+ data_packet->set_timestamp(static_cast<uint64_t>(packet_timestamp));
auto* energy = data_packet->set_power_rails()->add_energy_data();
energy->set_energy(data.energy());
@@ -206,7 +209,7 @@ void AndroidProbesModule::ParseTracePacketData(
parser_.ParseBatteryCounters(ts, decoder.battery());
return;
case TracePacket::kPowerRailsFieldNumber:
- parser_.ParsePowerRails(ts, decoder.power_rails());
+ parser_.ParsePowerRails(ts, decoder.timestamp(), decoder.power_rails());
return;
case TracePacket::kAndroidEnergyEstimationBreakdownFieldNumber:
parser_.ParseEnergyBreakdown(
diff --git a/src/trace_processor/importers/proto/android_probes_parser.cc b/src/trace_processor/importers/proto/android_probes_parser.cc
index 754f30a3d..b165a2b4c 100644
--- a/src/trace_processor/importers/proto/android_probes_parser.cc
+++ b/src/trace_processor/importers/proto/android_probes_parser.cc
@@ -62,7 +62,8 @@ AndroidProbesParser::AndroidProbesParser(TraceProcessorContext* context)
screen_state_id_(context->storage->InternString("ScreenState")),
device_state_id_(context->storage->InternString("DeviceStateChanged")),
battery_status_id_(context->storage->InternString("BatteryStatus")),
- plug_type_id_(context->storage->InternString("PlugType")) {}
+ plug_type_id_(context->storage->InternString("PlugType")),
+ rail_packet_timestamp_id_(context->storage->InternString("packet_ts")) {}
void AndroidProbesParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
protos::pbzero::BatteryCounters::Decoder evt(blob.data, blob.size);
@@ -82,14 +83,14 @@ void AndroidProbesParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
std::string("batt.").append(batt_name).append(".current.avg_ua")));
}
if (evt.has_charge_counter_uah()) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(batt_charge_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kPower, batt_charge_id);
context_->event_tracker->PushCounter(
ts, static_cast<double>(evt.charge_counter_uah()), track);
} else if (evt.has_energy_counter_uwh() && evt.has_voltage_uv()) {
// Calculate charge counter from energy counter and voltage.
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(batt_charge_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kPower, batt_charge_id);
auto energy = evt.energy_counter_uwh();
auto voltage = evt.voltage_uv();
if (voltage > 0) {
@@ -99,26 +100,28 @@ void AndroidProbesParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
}
if (evt.has_capacity_percent()) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(batt_capacity_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kPower, batt_capacity_id);
context_->event_tracker->PushCounter(
ts, static_cast<double>(evt.capacity_percent()), track);
}
if (evt.has_current_ua()) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(batt_current_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kPower, batt_current_id);
context_->event_tracker->PushCounter(
ts, static_cast<double>(evt.current_ua()), track);
}
if (evt.has_current_avg_ua()) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(batt_current_avg_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kPower, batt_current_avg_id);
context_->event_tracker->PushCounter(
ts, static_cast<double>(evt.current_avg_ua()), track);
}
}
-void AndroidProbesParser::ParsePowerRails(int64_t ts, ConstBytes blob) {
+void AndroidProbesParser::ParsePowerRails(int64_t ts,
+ uint64_t trace_packet_ts,
+ ConstBytes blob) {
protos::pbzero::PowerRails::Decoder evt(blob.data, blob.size);
// Descriptors should have been processed at tokenization time.
@@ -134,12 +137,16 @@ void AndroidProbesParser::ParsePowerRails(int64_t ts, ConstBytes blob) {
auto opt_track = tracker->GetPowerRailTrack(desc.index());
if (opt_track.has_value()) {
// The tokenization makes sure that this field is always present and
- // is equal to the packet's timestamp (as the packet was forged in
- // the tokenizer).
+ // is equal to the packet's timestamp that was passed to us via the sorter.
PERFETTO_DCHECK(desc.has_timestamp_ms());
PERFETTO_DCHECK(ts / 1000000 == static_cast<int64_t>(desc.timestamp_ms()));
- context_->event_tracker->PushCounter(ts, static_cast<double>(desc.energy()),
- *opt_track);
+ auto maybe_counter_id = context_->event_tracker->PushCounter(
+ ts, static_cast<double>(desc.energy()), *opt_track);
+ if (maybe_counter_id) {
+ context_->args_tracker->AddArgsTo(*maybe_counter_id)
+ .AddArg(rail_packet_timestamp_id_,
+ Variadic::UnsignedInteger(trace_packet_ts));
+ }
} else {
context_->storage->IncrementStats(stats::power_rail_unknown_index);
}
@@ -219,7 +226,7 @@ void AndroidProbesParser::ParseEntityStateResidency(int64_t ts,
}
TrackId track = context_->track_tracker->InternGlobalCounterTrack(
- entity_state->overall_name);
+ TrackTracker::Group::kPower, entity_state->overall_name);
context_->event_tracker->PushCounter(
ts, double(residency.total_time_in_state_ms()), track);
}
@@ -396,8 +403,8 @@ void AndroidProbesParser::ParseInitialDisplayState(int64_t ts,
ConstBytes blob) {
protos::pbzero::InitialDisplayState::Decoder state(blob.data, blob.size);
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(screen_state_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kDeviceState, screen_state_id_);
context_->event_tracker->PushCounter(ts, state.display_state(), track);
}
@@ -427,8 +434,8 @@ void AndroidProbesParser::ParseAndroidSystemProperty(int64_t ts,
std::optional<int32_t> state =
base::StringToInt32(kv.value().ToStdString());
if (state) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(name_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kNetwork, name_id);
context_->event_tracker->PushCounter(ts, *state, track);
}
} else if (name == "debug.tracing.screen_state") {
@@ -442,8 +449,8 @@ void AndroidProbesParser::ParseAndroidSystemProperty(int64_t ts,
std::optional<int32_t> state =
base::StringToInt32(kv.value().ToStdString());
if (state) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(*mapped_name_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kDeviceState, *mapped_name_id);
context_->event_tracker->PushCounter(ts, *state, track);
}
}
diff --git a/src/trace_processor/importers/proto/android_probes_parser.h b/src/trace_processor/importers/proto/android_probes_parser.h
index 7ea91a1f4..06b1019eb 100644
--- a/src/trace_processor/importers/proto/android_probes_parser.h
+++ b/src/trace_processor/importers/proto/android_probes_parser.h
@@ -34,7 +34,7 @@ class AndroidProbesParser {
explicit AndroidProbesParser(TraceProcessorContext*);
void ParseBatteryCounters(int64_t ts, ConstBytes);
- void ParsePowerRails(int64_t ts, ConstBytes);
+ void ParsePowerRails(int64_t ts, uint64_t trace_packet_ts, ConstBytes);
void ParseEnergyBreakdown(int64_t ts, ConstBytes);
void ParseEntityStateResidency(int64_t ts, ConstBytes);
void ParseAndroidLogPacket(ConstBytes);
@@ -56,6 +56,7 @@ class AndroidProbesParser {
const StringId device_state_id_;
const StringId battery_status_id_;
const StringId plug_type_id_;
+ const StringId rail_packet_timestamp_id_;
};
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/atoms.descriptor b/src/trace_processor/importers/proto/atoms.descriptor
index daeacb700..2d4c191ea 100644
--- a/src/trace_processor/importers/proto/atoms.descriptor
+++ b/src/trace_processor/importers/proto/atoms.descriptor
Binary files differ
diff --git a/src/trace_processor/importers/proto/chrome_system_probes_parser.h b/src/trace_processor/importers/proto/chrome_system_probes_parser.h
index 8c65fd4e4..b011fe5d2 100644
--- a/src/trace_processor/importers/proto/chrome_system_probes_parser.h
+++ b/src/trace_processor/importers/proto/chrome_system_probes_parser.h
@@ -43,7 +43,7 @@ class ChromeSystemProbesParser {
// Maps a proto field number for memcounters in ProcessStats::Process to
// their StringId. Keep kProcStatsProcessSize equal to 1 + max proto field
// id of ProcessStats::Process. Also update SystemProbesParser.
- static constexpr size_t kProcStatsProcessSize = 15;
+ static constexpr size_t kProcStatsProcessSize = 21;
std::array<StringId, kProcStatsProcessSize> proc_stats_process_names_{};
};
diff --git a/src/trace_processor/importers/proto/gpu_event_parser.cc b/src/trace_processor/importers/proto/gpu_event_parser.cc
index 56bc16588..9022cbb02 100644
--- a/src/trace_processor/importers/proto/gpu_event_parser.cc
+++ b/src/trace_processor/importers/proto/gpu_event_parser.cc
@@ -735,8 +735,8 @@ void GpuEventParser::ParseGpuMemTotalEvent(int64_t ts, ConstBytes blob) {
if (pid == 0) {
// Pid 0 is used to indicate the global total
track = context_->track_tracker->InternGlobalCounterTrack(
- gpu_mem_total_name_id_, {}, gpu_mem_total_unit_id_,
- gpu_mem_total_global_desc_id_);
+ TrackTracker::Group::kMemory, gpu_mem_total_name_id_, {},
+ gpu_mem_total_unit_id_, gpu_mem_total_global_desc_id_);
} else {
// Process emitting the packet can be different from the pid in the event.
UniqueTid utid = context_->process_tracker->UpdateThread(pid, pid);
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index fa1ffd643..b18bdeaf5 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -357,7 +357,7 @@ void ProtoTraceParser::ParseMetatraceEvent(int64_t ts, ConstBytes blob) {
// args in arrays.
std::stable_sort(interned.begin(), interned.end(),
[](const Arg& a, const Arg& b) {
- return a.first.raw_id() < b.second.raw_id();
+ return a.first.raw_id() < b.first.raw_id();
});
// Compute the correct key for each arg, possibly adding an index to
@@ -373,20 +373,16 @@ void ProtoTraceParser::ParseMetatraceEvent(int64_t ts, ConstBytes blob) {
inserter->AddArg(key, Variadic::String(it->second));
} else {
constexpr size_t kMaxIndexSize = 20;
- base::StringView key_str = context_->storage->GetString(key);
+ NullTermStringView key_str = context_->storage->GetString(key);
if (key_str.size() >= sizeof(buffer) - kMaxIndexSize) {
PERFETTO_DLOG("Ignoring arg with unreasonbly large size");
continue;
}
- base::StringWriter writer(buffer, sizeof(buffer));
- writer.AppendString(key_str);
- writer.AppendChar('[');
- writer.AppendUnsignedInt(current_idx);
- writer.AppendChar(']');
-
+ base::StackString<2048> array_key("%s[%u]", key_str.c_str(),
+ current_idx);
StringId new_key =
- context_->storage->InternString(writer.GetStringView());
+ context_->storage->InternString(array_key.string_view());
inserter->AddArg(key, new_key, Variadic::String(it->second));
current_idx = key == next_key ? current_idx + 1 : 0;
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index 2444215d5..97779d43d 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -647,11 +647,11 @@ TEST_F(ProtoTraceParserTest, LoadMemInfo) {
meminfo->set_value(value);
EXPECT_CALL(*event_, PushCounter(static_cast<int64_t>(ts),
- DoubleEq(value * 1024.0), TrackId{0u}));
+ DoubleEq(value * 1024.0), TrackId{1u}));
Tokenize();
context_.sorter->ExtractEventsForced();
- EXPECT_EQ(context_.storage->track_table().row_count(), 1u);
+ EXPECT_EQ(context_.storage->track_table().row_count(), 2u);
}
TEST_F(ProtoTraceParserTest, LoadVmStats) {
@@ -665,11 +665,11 @@ TEST_F(ProtoTraceParserTest, LoadVmStats) {
meminfo->set_value(value);
EXPECT_CALL(*event_, PushCounter(static_cast<int64_t>(ts), DoubleEq(value),
- TrackId{0u}));
+ TrackId{1u}));
Tokenize();
context_.sorter->ExtractEventsForced();
- EXPECT_EQ(context_.storage->track_table().row_count(), 1u);
+ EXPECT_EQ(context_.storage->track_table().row_count(), 2u);
}
TEST_F(ProtoTraceParserTest, LoadProcessPacket) {
diff --git a/src/trace_processor/importers/proto/statsd_module.h b/src/trace_processor/importers/proto/statsd_module.h
index 999a3392c..430b7a25c 100644
--- a/src/trace_processor/importers/proto/statsd_module.h
+++ b/src/trace_processor/importers/proto/statsd_module.h
@@ -26,7 +26,7 @@
#include "src/trace_processor/importers/common/trace_parser.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/slice_tables.h"
+#include "src/trace_processor/tables/slice_tables_py.h"
#include "src/trace_processor/tables/track_tables_py.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/descriptors.h"
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index da175fa57..da6a2d296 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -153,6 +153,16 @@ SystemProbesParser::SystemProbesParser(TraceProcessorContext* context)
context->storage->InternString("mem.rss.watermark");
proc_stats_process_names_[ProcessStats::Process::kOomScoreAdjFieldNumber] =
oom_score_adj_id_;
+ proc_stats_process_names_[ProcessStats::Process::kSmrRssKbFieldNumber] =
+ context->storage->InternString("mem.smaps.rss");
+ proc_stats_process_names_[ProcessStats::Process::kSmrPssKbFieldNumber] =
+ context->storage->InternString("mem.smaps.pss");
+ proc_stats_process_names_[ProcessStats::Process::kSmrPssAnonKbFieldNumber] =
+ context->storage->InternString("mem.smaps.pss.anon");
+ proc_stats_process_names_[ProcessStats::Process::kSmrPssFileKbFieldNumber] =
+ context->storage->InternString("mem.smaps.pss.file");
+ proc_stats_process_names_[ProcessStats::Process::kSmrPssShmemKbFieldNumber] =
+ context->storage->InternString("mem.smaps.pss.shmem");
}
void SystemProbesParser::ParseDiskStats(int64_t ts, ConstBytes blob) {
@@ -170,8 +180,8 @@ void SystemProbesParser::ParseDiskStats(int64_t ts, ConstBytes blob) {
base::StackString<512> track_name("%s.%s", tag_prefix.c_str(),
counter_name);
StringId string_id = context_->storage->InternString(track_name.c_str());
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(string_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kIo, string_id);
context_->event_tracker->PushCounter(ts, value, track);
};
@@ -244,7 +254,7 @@ void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
}
// /proc/meminfo counters are in kB, convert to bytes
TrackId track = context_->track_tracker->InternGlobalCounterTrack(
- meminfo_strs_id_[key]);
+ TrackTracker::Group::kMemory, meminfo_strs_id_[key]);
context_->event_tracker->PushCounter(
ts, static_cast<double>(mi.value()) * 1024., track);
}
@@ -259,7 +269,8 @@ void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
"%.*s %.*s", int(key.size()), key.data(), int(devfreq_subtitle.size()),
devfreq_subtitle.data());
StringId name = context_->storage->InternString(counter_name.string_view());
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kClockFrequency, name);
context_->event_tracker->PushCounter(ts, static_cast<double>(vm.value()),
track);
}
@@ -279,8 +290,8 @@ void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
context_->storage->IncrementStats(stats::vmstat_unknown_keys);
continue;
}
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(vmstat_strs_id_[key]);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kMemory, vmstat_strs_id_[key]);
context_->event_tracker->PushCounter(ts, static_cast<double>(vm.value()),
track);
}
@@ -348,22 +359,22 @@ void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
}
if (sys_stats.has_num_forks()) {
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(num_forks_name_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kDeviceState, num_forks_name_id_);
context_->event_tracker->PushCounter(
ts, static_cast<double>(sys_stats.num_forks()), track);
}
if (sys_stats.has_num_irq_total()) {
TrackId track = context_->track_tracker->InternGlobalCounterTrack(
- num_irq_total_name_id_);
+ TrackTracker::Group::kDeviceState, num_irq_total_name_id_);
context_->event_tracker->PushCounter(
ts, static_cast<double>(sys_stats.num_irq_total()), track);
}
if (sys_stats.has_num_softirq_total()) {
TrackId track = context_->track_tracker->InternGlobalCounterTrack(
- num_softirq_total_name_id_);
+ TrackTracker::Group::kDeviceState, num_softirq_total_name_id_);
context_->event_tracker->PushCounter(
ts, static_cast<double>(sys_stats.num_softirq_total()), track);
}
@@ -380,7 +391,8 @@ void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
node.c_str(), zone.c_str(), size_kb);
StringId name =
context_->storage->InternString(counter_name.string_view());
- TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kMemory, name);
context_->event_tracker->PushCounter(ts, static_cast<double>(*order_it),
track);
order++;
diff --git a/src/trace_processor/importers/proto/system_probes_parser.h b/src/trace_processor/importers/proto/system_probes_parser.h
index 77721d515..c1576a55a 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.h
+++ b/src/trace_processor/importers/proto/system_probes_parser.h
@@ -72,7 +72,7 @@ class SystemProbesParser {
// their StringId. Keep kProcStatsProcessSize equal to 1 + max proto field
// id of ProcessStats::Process. Also update the value in
// ChromeSystemProbesParser.
- static constexpr size_t kProcStatsProcessSize = 15;
+ static constexpr size_t kProcStatsProcessSize = 21;
std::array<StringId, kProcStatsProcessSize> proc_stats_process_names_{};
uint64_t ms_per_tick_ = 0;
diff --git a/src/trace_processor/importers/proto/track_event_tracker.cc b/src/trace_processor/importers/proto/track_event_tracker.cc
index 7591028e9..c65656499 100644
--- a/src/trace_processor/importers/proto/track_event_tracker.cc
+++ b/src/trace_processor/importers/proto/track_event_tracker.cc
@@ -24,11 +24,6 @@
namespace perfetto {
namespace trace_processor {
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// static
-constexpr uint64_t TrackEventTracker::kDefaultDescriptorTrackUuid;
-#endif
-
TrackEventTracker::TrackEventTracker(TraceProcessorContext* context)
: source_key_(context->storage->InternString("source")),
source_id_key_(context->storage->InternString("source_id")),
diff --git a/src/trace_processor/importers/systrace/systrace_line_parser.cc b/src/trace_processor/importers/systrace/systrace_line_parser.cc
index 958cb7e43..c0851d74c 100644
--- a/src/trace_processor/importers/systrace/systrace_line_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_line_parser.cc
@@ -216,8 +216,8 @@ util::Status SystraceLineParser::ParseLine(const SystraceLine& line) {
std::string clock_name_str = args["name"] + subtitle;
StringId clock_name =
context_->storage->InternString(base::StringView(clock_name_str));
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(clock_name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kClockFrequency, clock_name);
context_->event_tracker->PushCounter(line.ts, rate.value(), track);
} else if (line.event_name == "workqueue_execute_start") {
auto split = base::SplitString(line.args_str, "function ");
@@ -232,8 +232,8 @@ util::Status SystraceLineParser::ParseLine(const SystraceLine& line) {
std::string thermal_zone = args["thermal_zone"] + " Temperature";
StringId track_name =
context_->storage->InternString(base::StringView(thermal_zone));
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(track_name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kThermals, track_name);
auto temp = base::StringToInt32(args["temp"]);
if (!temp.has_value()) {
return util::Status("Could not convert temp");
@@ -243,8 +243,8 @@ util::Status SystraceLineParser::ParseLine(const SystraceLine& line) {
std::string type = args["type"] + " Cooling Device";
StringId track_name =
context_->storage->InternString(base::StringView(type));
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(track_name);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kThermals, track_name);
auto target = base::StringToDouble(args["target"]);
if (!target.has_value()) {
return util::Status("Could not convert target");
diff --git a/src/trace_processor/importers/systrace/systrace_parser.cc b/src/trace_processor/importers/systrace/systrace_parser.cc
index ac16506c3..b06bb7186 100644
--- a/src/trace_processor/importers/systrace/systrace_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_parser.cc
@@ -277,16 +277,16 @@ void SystraceParser::ParseSystracePoint(
// once the UI has support for displaying instants.
} else if (point.name == "ScreenState") {
// Promote ScreenState to its own top level counter.
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(screen_state_id_);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kDeviceState, screen_state_id_);
context_->event_tracker->PushCounter(
ts, static_cast<double>(point.int_value), track);
return;
} else if (point.name.StartsWith("battery_stats.")) {
// Promote battery_stats conters to global tracks.
StringId name_id = context_->storage->InternString(point.name);
- TrackId track =
- context_->track_tracker->InternGlobalCounterTrack(name_id);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ TrackTracker::Group::kPower, name_id);
context_->event_tracker->PushCounter(
ts, static_cast<double>(point.int_value), track);
return;
diff --git a/src/trace_processor/metrics/metrics.h b/src/trace_processor/metrics/metrics.h
index 16e004c7a..2691e91ac 100644
--- a/src/trace_processor/metrics/metrics.h
+++ b/src/trace_processor/metrics/metrics.h
@@ -27,7 +27,7 @@
#include "perfetto/protozero/message.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "perfetto/trace_processor/trace_processor.h"
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
#include "src/trace_processor/util/descriptors.h"
#include "protos/perfetto/trace_processor/metrics_impl.pbzero.h"
diff --git a/src/trace_processor/metrics/sql/android/BUILD.gn b/src/trace_processor/metrics/sql/android/BUILD.gn
index bf54d4454..a56666136 100644
--- a/src/trace_processor/metrics/sql/android/BUILD.gn
+++ b/src/trace_processor/metrics/sql/android/BUILD.gn
@@ -82,6 +82,7 @@ perfetto_sql_source_set("android") {
"java_heap_histogram.sql",
"java_heap_stats.sql",
"mem_stats_priority_breakdown.sql",
+ "network_activity_template.sql",
"p_state.sql",
"power_drain_in_watts.sql",
"power_profile_data.sql",
diff --git a/src/trace_processor/metrics/sql/android/android_batt.sql b/src/trace_processor/metrics/sql/android/android_batt.sql
index 7dde09948..b88d7ed5e 100644
--- a/src/trace_processor/metrics/sql/android/android_batt.sql
+++ b/src/trace_processor/metrics/sql/android/android_batt.sql
@@ -49,8 +49,16 @@ FROM (
)
GROUP BY group_id;
+DROP VIEW IF EXISTS suspend_slice_from_minimal;
+CREATE VIEW suspend_slice_from_minimal AS
+SELECT ts, dur
+FROM track t JOIN slice s ON s.track_id = t.id
+WHERE t.name = 'Suspend/Resume Minimal';
+
DROP TABLE IF EXISTS suspend_slice_;
CREATE TABLE suspend_slice_ AS
+SELECT ts, dur FROM suspend_slice_from_minimal
+UNION ALL
SELECT
ts,
dur
@@ -62,7 +70,10 @@ JOIN
WHERE
track.name = 'Suspend/Resume Latency'
AND (slice.name = 'syscore_resume(0)' OR slice.name = 'timekeeping_freeze(0)')
- AND dur != -1;
+ AND dur != -1
+ AND NOT EXISTS(SELECT * FROM suspend_slice_from_minimal);
+
+DROP VIEW suspend_slice_from_minimal;
SELECT RUN_METRIC('android/counter_span_view_merged.sql',
'table_name', 'screen_state',
diff --git a/src/trace_processor/metrics/sql/android/android_binder.sql b/src/trace_processor/metrics/sql/android/android_binder.sql
index 1d15050a4..f59f5d99b 100644
--- a/src/trace_processor/metrics/sql/android/android_binder.sql
+++ b/src/trace_processor/metrics/sql/android/android_binder.sql
@@ -45,11 +45,13 @@ SELECT AndroidBinderMetric(
'client_ts', client_ts,
'client_dur', client_dur,
'client_tid', client_tid,
+ 'client_pid', client_pid,
'server_process', server_process,
'server_thread', server_thread,
'server_ts', server_ts,
'server_dur', server_dur,
'server_tid', server_tid,
+ 'server_pid', server_pid,
'thread_states', (
SELECT RepeatedField(
AndroidBinderMetric_ThreadStateBreakdown(
diff --git a/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql b/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql
index 7c56db214..3538f7d86 100644
--- a/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql
+++ b/src/trace_processor/metrics/sql/android/android_blocking_calls_cuj_metric.sql
@@ -20,6 +20,7 @@
SELECT RUN_METRIC('android/android_jank_cuj.sql');
SELECT IMPORT('android.slices');
+SELECT IMPORT('android.binder');
-- Jank "J<*>" and latency "L<*>" cujs are put together in android_cujs table.
-- They are computed separately as latency ones are slightly different, don't
@@ -75,6 +76,24 @@ SELECT ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, *
FROM all_cujs;
+DROP TABLE IF EXISTS relevant_binder_calls_with_names;
+CREATE TABLE relevant_binder_calls_with_names AS
+SELECT DISTINCT
+ tx.aidl_name AS name,
+ tx.client_ts AS ts,
+ s.track_id,
+ tx.client_dur AS dur,
+ s.id,
+ tx.client_process as process_name,
+ tx.client_utid as utid,
+ tx.client_upid as upid
+FROM android_sync_binder_metrics_by_txn AS tx
+ JOIN slice AS s ON s.id = tx.binder_txn_id
+ -- Keeps only slices in cuj processes.
+ JOIN android_cujs ON tx.client_upid = android_cujs.upid
+WHERE is_main_thread AND aidl_name IS NOT NULL;
+
+
DROP TABLE IF EXISTS android_blocking_calls_cuj_calls;
CREATE TABLE android_blocking_calls_cuj_calls AS
WITH all_main_thread_relevant_slices AS (
@@ -108,6 +127,17 @@ WITH all_main_thread_relevant_slices AS (
OR s.name GLOB 'relayoutWindow*'
OR s.name GLOB 'ImageDecoder#decode*'
)
+ UNION ALL
+ SELECT
+ name,
+ ts,
+ track_id,
+ dur,
+ id,
+ process_name,
+ utid,
+ upid
+ FROM relevant_binder_calls_with_names
),
-- Now we have:
-- (1) a list of slices from the main thread of each process
diff --git a/src/trace_processor/metrics/sql/android/android_jank_cuj.sql b/src/trace_processor/metrics/sql/android/android_jank_cuj.sql
index bf7ce9ff2..299e83066 100644
--- a/src/trace_processor/metrics/sql/android/android_jank_cuj.sql
+++ b/src/trace_processor/metrics/sql/android/android_jank_cuj.sql
@@ -102,6 +102,8 @@ SELECT
'missed_app_frames', missed_app_frames,
'missed_sf_frames', missed_sf_frames,
'missed_frames_max_successive', missed_frames_max_successive,
+ 'sf_callback_missed_frames', sf_callback_missed_frames,
+ 'hwui_callback_missed_frames', hwui_callback_missed_frames,
'frame_dur_max', frame_dur_max)
FROM android_jank_cuj_counter_metrics cm
WHERE cm.cuj_id = cuj.cuj_id),
@@ -111,6 +113,8 @@ SELECT
'missed_frames', SUM(app_missed OR sf_missed),
'missed_app_frames', SUM(app_missed),
'missed_sf_frames', SUM(sf_missed),
+ 'sf_callback_missed_frames', SUM(sf_callback_missed),
+ 'hwui_callback_missed_frames', SUM(hwui_callback_missed),
'frame_dur_max', MAX(f.dur),
'frame_dur_avg', CAST(AVG(f.dur) AS INTEGER),
'frame_dur_p50', CAST(PERCENTILE(f.dur, 50) AS INTEGER),
@@ -129,6 +133,8 @@ SELECT
'missed_frames', SUM(app_missed OR sf_missed),
'missed_app_frames', SUM(app_missed),
'missed_sf_frames', SUM(sf_missed),
+ 'sf_callback_missed_frames', SUM(sf_callback_missed),
+ 'hwui_callback_missed_frames', SUM(hwui_callback_missed),
'frame_dur_max', MAX(f.dur),
'frame_dur_avg', CAST(AVG(f.dur) AS INTEGER),
'frame_dur_p50', CAST(PERCENTILE(f.dur, 50) AS INTEGER),
@@ -150,7 +156,9 @@ SELECT
'dur', f.dur,
'dur_expected', f.dur_expected,
'app_missed', f.app_missed,
- 'sf_missed', f.sf_missed))
+ 'sf_missed', f.sf_missed,
+ 'sf_callback_missed', f.sf_callback_missed,
+ 'hwui_callback_missed', f.hwui_callback_missed))
FROM android_jank_cuj_frame f
WHERE f.cuj_id = cuj.cuj_id
ORDER BY frame_number ASC),
diff --git a/src/trace_processor/metrics/sql/android/android_monitor_contention.sql b/src/trace_processor/metrics/sql/android/android_monitor_contention.sql
index 7cfaeb8b9..52e16930c 100644
--- a/src/trace_processor/metrics/sql/android/android_monitor_contention.sql
+++ b/src/trace_processor/metrics/sql/android/android_monitor_contention.sql
@@ -35,7 +35,10 @@ SELECT AndroidMonitorContentionMetric(
'waiter_count', waiter_count,
'blocking_thread_name', blocking_thread_name,
'blocked_thread_name', blocked_thread_name,
+ 'blocked_thread_tid', blocked_thread_tid,
+ 'blocking_thread_tid', blocking_thread_tid,
'process_name', process_name,
+ 'pid', pid,
'is_blocked_thread_main', is_blocked_thread_main,
'is_blocking_thread_main', is_blocking_thread_main,
'binder_reply_ts', binder_reply_ts,
diff --git a/src/trace_processor/metrics/sql/android/android_startup.sql b/src/trace_processor/metrics/sql/android/android_startup.sql
index da39e3450..892f6beef 100644
--- a/src/trace_processor/metrics/sql/android/android_startup.sql
+++ b/src/trace_processor/metrics/sql/android/android_startup.sql
@@ -209,14 +209,22 @@ SELECT
'time_gc_total', (
SELECT NULL_IF_EMPTY(STARTUP_SLICE_PROTO(TOTAL_GC_TIME_BY_LAUNCH(launches.startup_id)))
),
+ 'time_dex_open_thread_main',
+ DUR_SUM_MAIN_THREAD_SLICE_PROTO_FOR_LAUNCH(
+ launches.startup_id,
+ 'OpenDexFilesFromOat*'),
+ 'time_dlopen_thread_main',
+ DUR_SUM_MAIN_THREAD_SLICE_PROTO_FOR_LAUNCH(
+ launches.startup_id,
+ 'dlopen:*.so'),
'time_lock_contention_thread_main',
DUR_SUM_MAIN_THREAD_SLICE_PROTO_FOR_LAUNCH(
- launches.startup_id,
+ launches.startup_id,
'Lock contention on*'
),
'time_monitor_contention_thread_main',
DUR_SUM_MAIN_THREAD_SLICE_PROTO_FOR_LAUNCH(
- launches.startup_id,
+ launches.startup_id,
'Lock contention on a monitor*'
),
'time_before_start_process', (
@@ -286,6 +294,7 @@ SELECT
FROM android_thread_slices_for_all_startups
WHERE startup_id = launches.startup_id AND slice_name GLOB "VerifyClass *"
ORDER BY slice_dur DESC
+ LIMIT 5
),
'startup_concurrent_to_launch', (
SELECT RepeatedField(package)
@@ -293,6 +302,11 @@ SELECT
WHERE l.startup_id != launches.startup_id
AND IS_SPANS_OVERLAPPING(l.ts, l.ts_end, launches.ts, launches.ts_end)
),
+ 'dlopen_file', (
+ SELECT RepeatedField(STR_SPLIT(slice_name, "dlopen: ", 1))
+ FROM android_thread_slices_for_all_startups s
+ WHERE startup_id = launches.startup_id AND slice_name GLOB "dlopen: *.so"
+ ),
'system_state', AndroidStartupMetric_SystemState(
'dex2oat_running',
DUR_OF_PROCESS_RUNNING_CONCURRENT_TO_LAUNCH(launches.startup_id, '*dex2oat64') > 0,
@@ -362,11 +376,10 @@ SELECT
WHERE MAIN_THREAD_TIME_FOR_LAUNCH_STATE_AND_IO_WAIT(launches.startup_id, 'D*', TRUE) > 155e6
UNION ALL
- SELECT 'Time spent in OpenDexFilesFromOat*'
+ SELECT 'Main Thread - Time spent in OpenDexFilesFromOat*'
AS slow_cause
- WHERE
- ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(launches.startup_id, 'OpenDexFilesFromOat*')
- > launches.dur * 0.2
+ WHERE ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE(
+ launches.startup_id, 'OpenDexFilesFromOat*') > launches.dur * 0.2
UNION ALL
SELECT 'Time spent in bindApplication'
@@ -392,9 +405,7 @@ SELECT
> launches.dur * 0.15
UNION ALL
- SELECT 'Potential CPU contention with '
- || MOST_ACTIVE_PROCESS_FOR_LAUNCH(launches.startup_id)
- AS slow_cause
+ SELECT 'Potential CPU contention with another process' AS slow_cause
WHERE MAIN_THREAD_TIME_FOR_LAUNCH_IN_RUNNABLE_STATE(launches.startup_id) > 100e6
AND MOST_ACTIVE_PROCESS_FOR_LAUNCH(launches.startup_id) IS NOT NULL
diff --git a/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql b/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql
index b14ce8490..498baf8a0 100644
--- a/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql
+++ b/src/trace_processor/metrics/sql/android/android_surfaceflinger.sql
@@ -86,6 +86,37 @@ FROM (
)
WHERE event_type = 0 AND fence_id = next_fence_id;
+
+DROP VIEW IF EXISTS display_ids;
+CREATE VIEW display_ids AS
+SELECT DISTINCT display_id
+FROM (
+ SELECT display_id FROM frame_missed
+ UNION
+ SELECT display_id FROM hwc_frame_missed
+ UNION
+ SELECT display_id FROM gpu_frame_missed
+);
+
+DROP VIEW IF EXISTS metrics_per_display;
+CREATE VIEW metrics_per_display AS
+SELECT AndroidSurfaceflingerMetric_MetricsPerDisplay(
+ 'display_id', d.display_id,
+ 'missed_frames',
+ (SELECT COUNT(1) FROM frame_missed WHERE value = 1 AND display_id = d.display_id),
+ 'missed_hwc_frames',
+ (SELECT COUNT(1) FROM hwc_frame_missed WHERE value = 1 AND display_id = d.display_id),
+ 'missed_gpu_frames',
+ (SELECT COUNT(1) FROM gpu_frame_missed WHERE value = 1 AND display_id = d.display_id),
+ 'missed_frame_rate',
+ (SELECT AVG(value) FROM frame_missed WHERE display_id = d.display_id),
+ 'missed_hwc_frame_rate',
+ (SELECT AVG(value) FROM hwc_frame_missed WHERE display_id = d.display_id),
+ 'missed_gpu_frame_rate',
+ (SELECT AVG(value) FROM gpu_frame_missed WHERE display_id = d.display_id)
+) AS proto
+FROM display_ids d;
+
DROP VIEW IF EXISTS android_surfaceflinger_output;
CREATE VIEW android_surfaceflinger_output AS
SELECT
@@ -99,5 +130,6 @@ SELECT
'gpu_invocations', (SELECT COUNT(1) FROM gpu_waiting_end),
'avg_gpu_waiting_dur_ms', (SELECT AVG(dur) / 1e6 FROM gpu_waiting_span),
'total_non_empty_gpu_waiting_dur_ms',
- (SELECT SUM(dur) / 1e6 FROM gpu_waiting_end)
+ (SELECT SUM(dur) / 1e6 FROM gpu_waiting_end),
+ 'metrics_per_display', (SELECT RepeatedField(proto) FROM metrics_per_display)
);
diff --git a/src/trace_processor/metrics/sql/android/frame_missed.sql b/src/trace_processor/metrics/sql/android/frame_missed.sql
index e6546bae0..5372177e4 100644
--- a/src/trace_processor/metrics/sql/android/frame_missed.sql
+++ b/src/trace_processor/metrics/sql/android/frame_missed.sql
@@ -22,12 +22,18 @@ WITH frame_missed_counters AS (
-- track should ever exist with this name (the track from
-- surfaceflinger).
ts - LAG(ts) OVER (ORDER BY ts) AS dur,
+ name,
+ INSTR(name, ' ') AS separator_pos,
value
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
- WHERE t.name = '{{track_name}}'
+ WHERE t.name GLOB '{{track_name}}*'
)
SELECT
+ CASE
+ WHEN separator_pos = 0 THEN 'unspecified'
+ ELSE SUBSTR(name, separator_pos + 1)
+ END AS display_id,
ts,
dur,
value
diff --git a/src/trace_processor/metrics/sql/android/jank/cujs.sql b/src/trace_processor/metrics/sql/android/jank/cujs.sql
index 2638a8e4d..03d0d96a4 100644
--- a/src/trace_processor/metrics/sql/android/jank/cujs.sql
+++ b/src/trace_processor/metrics/sql/android/jank/cujs.sql
@@ -90,11 +90,23 @@ SELECT
FROM cuj_state_markers csm
WHERE csm.cuj_id = cujs.cuj_id AND csm.marker_name GLOB '*layerId#*'
LIMIT 1
- ) AS layer_id
+ ) AS layer_id,
+ (
+ SELECT CAST(STR_SPLIT(csm.marker_name, 'beginVsync#', 1) AS INTEGER)
+ FROM cuj_state_markers csm
+ WHERE csm.cuj_id = cujs.cuj_id AND csm.marker_name GLOB '*beginVsync#*'
+ LIMIT 1
+ ) AS begin_vsync,
+ (
+ SELECT CAST(STR_SPLIT(csm.marker_name, 'endVsync#', 1) AS INTEGER)
+ FROM cuj_state_markers csm
+ WHERE csm.cuj_id = cujs.cuj_id AND csm.marker_name GLOB '*endVsync#*'
+ LIMIT 1
+ ) AS end_vsync
FROM cujs
WHERE
state != 'canceled'
-- Older builds don't have the state markers so we allow NULL but filter out
-- CUJs that are <4ms long - assuming CUJ was canceled in that case.
OR (state IS NULL AND cujs.dur > 4e6)
-ORDER BY ts ASC;
+ORDER BY ts ASC; \ No newline at end of file
diff --git a/src/trace_processor/metrics/sql/android/jank/cujs_boundaries.sql b/src/trace_processor/metrics/sql/android/jank/cujs_boundaries.sql
index 0d91cb8a7..687b808a2 100644
--- a/src/trace_processor/metrics/sql/android/jank/cujs_boundaries.sql
+++ b/src/trace_processor/metrics/sql/android/jank/cujs_boundaries.sql
@@ -13,8 +13,9 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--- Stores the min and max vsync IDs for each of the CUJs.
--- We calculate that by extracting the vsync ID from the
+-- Stores the min and max vsync IDs for each of the CUJs which are extracted
+-- from the CUJ markers. For backward compatibility (In case the markers don't
+-- exist), We calculate that by extracting the vsync ID from the
-- `Choreographer#doFrame` slices that are within the CUJ markers.
DROP TABLE IF EXISTS android_jank_cuj_vsync_boundary;
CREATE TABLE android_jank_cuj_vsync_boundary AS
@@ -22,8 +23,8 @@ SELECT
cuj.cuj_id,
cuj.upid, -- also store upid to simplify further queries
cuj.layer_id, -- also store layer_id to simplify further queries
- MIN(vsync) AS vsync_min,
- MAX(vsync) AS vsync_max
+ IFNULL(cuj.begin_vsync, MIN(vsync)) AS vsync_min,
+ IFNULL(cuj.end_vsync, MAX(vsync)) AS vsync_max
FROM android_jank_cuj cuj
JOIN android_jank_cuj_do_frame_slice USING (cuj_id)
GROUP BY cuj.cuj_id, cuj.upid, cuj.layer_id;
diff --git a/src/trace_processor/metrics/sql/android/jank/frames.sql b/src/trace_processor/metrics/sql/android/jank/frames.sql
index 66f6639f0..ffef19d7f 100644
--- a/src/trace_processor/metrics/sql/android/jank/frames.sql
+++ b/src/trace_processor/metrics/sql/android/jank/frames.sql
@@ -13,6 +13,14 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
+DROP TABLE IF EXISTS vsync_missed_callback;
+CREATE TABLE vsync_missed_callback AS
+SELECT CAST(STR_SPLIT(name, 'Callback#', 1) AS INTEGER) AS vsync,
+ MAX(name GLOB '*SF*') as sf_callback_missed,
+ MAX(name GLOB '*HWUI*') as hwui_callback_missed
+FROM slice
+WHERE name GLOB '*FT#Missed*Callback*'
+GROUP BY vsync;
DROP TABLE IF EXISTS android_jank_cuj_frame_timeline;
CREATE TABLE android_jank_cuj_frame_timeline AS
@@ -35,6 +43,8 @@ SELECT
OR jank_type GLOB '*SurfaceFlinger Scheduling*'
OR jank_type GLOB '*Prediction Error*'
OR jank_type GLOB '*Display HAL*') AS sf_missed,
+ IFNULL(MAX(sf_callback_missed), 0) AS sf_callback_missed,
+ IFNULL(MAX(hwui_callback_missed), 0) AS hwui_callback_missed,
-- We use MIN to check if ALL layers finished on time
MIN(on_time_finish) AS on_time_finish,
MAX(timeline.ts + timeline.dur) AS ts_end_actual,
@@ -54,6 +64,7 @@ JOIN actual_timeline_with_vsync timeline
AND vsync <= vsync_max
LEFT JOIN expected_frame_timeline_slice expected
ON expected.upid = timeline.upid AND expected.name = timeline.name
+LEFT JOIN vsync_missed_callback missed_callback USING(vsync)
WHERE
boundary.layer_id IS NULL
OR (
@@ -99,6 +110,8 @@ SELECT
frame_base.*,
app_missed,
sf_missed,
+ sf_callback_missed,
+ hwui_callback_missed,
on_time_finish,
ts_end_actual - ts AS dur,
ts_end_actual - ts_do_frame_start AS dur_unadjusted,
diff --git a/src/trace_processor/metrics/sql/android/jank/internal/counters.sql b/src/trace_processor/metrics/sql/android/jank/internal/counters.sql
index fdcc04cee..d04229d94 100644
--- a/src/trace_processor/metrics/sql/android/jank/internal/counters.sql
+++ b/src/trace_processor/metrics/sql/android/jank/internal/counters.sql
@@ -51,6 +51,30 @@ SELECT CREATE_FUNCTION(
'
);
+DROP TABLE IF EXISTS cuj_marker_missed_callback;
+CREATE TABLE cuj_marker_missed_callback AS
+SELECT
+ marker_track.name AS cuj_slice_name,
+ marker.ts,
+ marker.name AS marker_name
+FROM slice marker
+JOIN track marker_track on marker_track.id = marker.track_id
+WHERE marker.name GLOB '*FT#Missed*';
+
+SELECT CREATE_FUNCTION(
+ 'ANDROID_MISSED_VSYNCS_FOR_CALLBACK(cuj_slice_name STRING, ts_min INT, ts_max INT, callback_missed STRING)',
+ 'INT',
+ '
+ SELECT IFNULL(SUM(marker_name GLOB $callback_missed), 0)
+ FROM cuj_marker_missed_callback
+ WHERE
+ cuj_slice_name = $cuj_slice_name
+ AND ts >= $ts_min
+ AND ($ts_max IS NULL OR ts <= $ts_max)
+ ORDER BY ts ASC LIMIT 1
+ '
+);
+
DROP TABLE IF EXISTS android_jank_cuj_counter_metrics;
CREATE TABLE android_jank_cuj_counter_metrics AS
-- Order CUJs to get the ts of the next CUJ with the same name.
@@ -60,6 +84,7 @@ WITH cujs_ordered AS (
SELECT
cuj_id,
cuj_name,
+ cuj_slice_name,
upid,
state,
ts_end,
@@ -83,5 +108,7 @@ SELECT
ANDROID_JANK_CUJ_COUNTER_VALUE(cuj_name, 'missedSfFrames', ts_earliest_allowed_counter, ts_end_next_cuj) AS missed_sf_frames,
ANDROID_JANK_CUJ_COUNTER_VALUE(cuj_name, 'maxSuccessiveMissedFrames', ts_earliest_allowed_counter, ts_end_next_cuj) AS missed_frames_max_successive,
-- convert ms to nanos to align with the unit for `dur` in the other tables
- ANDROID_JANK_CUJ_COUNTER_VALUE(cuj_name, 'maxFrameTimeMillis', ts_earliest_allowed_counter, ts_end_next_cuj) * 1000000 AS frame_dur_max
+ ANDROID_JANK_CUJ_COUNTER_VALUE(cuj_name, 'maxFrameTimeMillis', ts_earliest_allowed_counter, ts_end_next_cuj) * 1000000 AS frame_dur_max,
+ ANDROID_MISSED_VSYNCS_FOR_CALLBACK(cuj_slice_name, ts_earliest_allowed_counter, ts_end_next_cuj, '*SF*') AS sf_callback_missed_frames,
+ ANDROID_MISSED_VSYNCS_FOR_CALLBACK(cuj_slice_name, ts_earliest_allowed_counter, ts_end_next_cuj, '*HWUI*') AS hwui_callback_missed_frames
FROM cujs_ordered cuj;
diff --git a/src/trace_processor/metrics/sql/android/java_heap_stats.sql b/src/trace_processor/metrics/sql/android/java_heap_stats.sql
index 15627b42e..32c43f4b8 100644
--- a/src/trace_processor/metrics/sql/android/java_heap_stats.sql
+++ b/src/trace_processor/metrics/sql/android/java_heap_stats.sql
@@ -65,7 +65,7 @@ base_stats AS (
SELECT * FROM base_stat_counts JOIN heap_roots_proto USING (upid, graph_sample_ts)
),
-- Find closest value
-closest_anon_swap AS (
+closest_anon_swap_oom AS (
SELECT
upid,
graph_sample_ts,
@@ -84,7 +84,23 @@ closest_anon_swap AS (
-- accept it if close (500ms)
OR (graph_sample_ts < ts AND diff <= 500 * 1e6)
ORDER BY diff LIMIT 1
- ) AS val
+ ) AS anon_swap_val,
+ (
+ SELECT oom_score_val
+ FROM (
+ SELECT
+ ts, dur,
+ oom_score_val,
+ ABS(ts - base_stats.graph_sample_ts) AS diff
+ FROM oom_score_span
+ WHERE upid = base_stats.upid)
+ WHERE
+ (graph_sample_ts >= ts AND graph_sample_ts < ts + dur)
+ -- If the first memory sample for the UPID comes *after* the heap profile
+ -- accept it if close (500ms)
+ OR (graph_sample_ts < ts AND diff <= 500 * 1e6)
+ ORDER BY diff LIMIT 1
+ ) AS oom_score_val
FROM base_stats
),
-- Group by upid
@@ -100,10 +116,11 @@ heap_graph_sample_protos AS (
'reachable_heap_native_size', reachable_native_size,
'reachable_obj_count', reachable_obj_count,
'roots', roots,
- 'anon_rss_and_swap_size', closest_anon_swap.val
+ 'anon_rss_and_swap_size', closest_anon_swap_oom.anon_swap_val,
+ 'oom_score_adj', closest_anon_swap_oom.oom_score_val
)) AS sample_protos
FROM base_stats
- LEFT JOIN closest_anon_swap USING (upid, graph_sample_ts)
+ LEFT JOIN closest_anon_swap_oom USING (upid, graph_sample_ts)
GROUP BY 1
)
SELECT JavaHeapStats(
diff --git a/src/trace_processor/metrics/sql/android/network_activity_template.sql b/src/trace_processor/metrics/sql/android/network_activity_template.sql
new file mode 100644
index 000000000..2dcfa31a2
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/network_activity_template.sql
@@ -0,0 +1,74 @@
+--
+-- Copyright 2023 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+SELECT IMPORT('android.network_packets');
+
+-- Creates a view of aggregated network activity. It is common among networking
+-- to have the interface active for some time after network use. For example, in
+-- mobile networking, it is common to have the cellular interface active for 10
+-- or more seconds after the last packet was sent or received. This view takes
+-- raw packet timing and aggregates it into something that approximates the
+-- activity of the underlying interface.
+--
+-- @arg view_name The name of the output view.
+-- @arg group_by Expression to group by (set to 'null' for no grouping).
+-- @arg filter Expression on `android_network_packets` to filter by.
+-- @arg idle_ns The amount of time before considering the network idle.
+-- @arg quant_ns Quantization value, to group rows before the heavy
+-- part of the query. This should be smaller than idle_ns.
+--
+-- @column group_by The group_by columns are all present in the output.
+-- @column ts The timestamp indicating the start of the segment.
+-- @column dur The duration of the current segment.
+-- @column packet_count The total number of packets in this segment.
+-- @column packet_length The total number of bytes for packets in this segment.
+CREATE VIEW {{view_name}} AS
+WITH quantized AS (
+ SELECT
+ {{group_by}},
+ MIN(ts) AS ts,
+ MAX(ts+dur)-MIN(ts) AS dur,
+ SUM(packet_count) AS packet_count,
+ SUM(packet_length) AS packet_length
+ FROM android_network_packets
+ WHERE {{filter}}
+ GROUP BY CAST(ts / {{quant_ns}} AS INT64), {{group_by}}
+),
+with_last AS (
+ SELECT
+ *,
+ LAG(ts) OVER (
+ PARTITION BY {{group_by}}
+ ORDER BY ts
+ ) AS last_ts
+ FROM quantized
+),
+with_group AS (
+ SELECT
+ *,
+ COUNT(IIF(ts-last_ts>{{idle_ns}}, 1, null)) OVER (
+ PARTITION BY {{group_by}}
+ ORDER BY ts
+ ) AS group_id
+ FROM with_last
+)
+SELECT
+ {{group_by}},
+ MIN(ts) AS ts,
+ MAX(ts+dur)-MIN(ts)+{{idle_ns}} AS dur,
+ SUM(packet_count) AS packet_count,
+ SUM(packet_length) AS packet_length
+FROM with_group
+GROUP BY group_id, {{group_by}}
diff --git a/src/trace_processor/metrics/sql/android/process_metadata.sql b/src/trace_processor/metrics/sql/android/process_metadata.sql
index acaceb777..5ccf2b1d3 100644
--- a/src/trace_processor/metrics/sql/android/process_metadata.sql
+++ b/src/trace_processor/metrics/sql/android/process_metadata.sql
@@ -18,7 +18,8 @@ SELECT IMPORT('android.process_metadata');
DROP VIEW IF EXISTS process_metadata_table;
CREATE VIEW process_metadata_table AS
-SELECT * FROM android_process_metadata;
+SELECT android_process_metadata.*, pid FROM android_process_metadata
+JOIN process USING(upid);
DROP VIEW IF EXISTS uid_package_count;
CREATE VIEW uid_package_count AS
@@ -43,6 +44,7 @@ SELECT
NULL_IF_EMPTY(AndroidProcessMetadata(
'name', process_name,
'uid', uid,
+ 'pid', pid,
'package', NULL_IF_EMPTY(AndroidProcessMetadata_Package(
'package_name', package_name,
'apk_version_code', version_code,
diff --git a/src/trace_processor/metrics/sql/chrome/chrome_tasks_template.sql b/src/trace_processor/metrics/sql/chrome/chrome_tasks_template.sql
index d2886f1f5..b5464cf23 100644
--- a/src/trace_processor/metrics/sql/chrome/chrome_tasks_template.sql
+++ b/src/trace_processor/metrics/sql/chrome/chrome_tasks_template.sql
@@ -427,6 +427,7 @@ scheduler_tasks_with_mojo AS (
WHERE
s1.posted_from IN (
"mojo/public/cpp/system/simple_watcher.cc:Notify",
+ "mojo/public/cpp/system/simple_watcher.cc:ArmOrNotify",
"mojo/public/cpp/bindings/lib/connector.cc:PostDispatchNextMessageFromPipe",
"ipc/ipc_mojo_bootstrap.cc:Accept")
),
diff --git a/src/trace_processor/prelude/functions/BUILD.gn b/src/trace_processor/prelude/functions/BUILD.gn
index ec4da442d..f2f22ba7b 100644
--- a/src/trace_processor/prelude/functions/BUILD.gn
+++ b/src/trace_processor/prelude/functions/BUILD.gn
@@ -31,12 +31,12 @@ source_set("functions") {
"layout_functions.h",
"pprof_functions.cc",
"pprof_functions.h",
- "register_function.cc",
- "register_function.h",
"sqlite3_str_split.cc",
"sqlite3_str_split.h",
"stack_functions.cc",
"stack_functions.h",
+ "to_ftrace.cc",
+ "to_ftrace.h",
"utils.h",
"window_functions.h",
]
@@ -57,7 +57,7 @@ source_set("functions") {
"../../importers/common",
"../../importers/ftrace:ftrace_descriptors",
"../../prelude/table_functions",
- "../../sqlite:sqlite_minimal",
+ "../../sqlite",
"../../storage",
"../../types",
"../../util",
@@ -65,6 +65,20 @@ source_set("functions") {
"../../util:sql_argument",
"../../util:stdlib",
]
+ public_deps = [ ":interface" ]
+}
+
+source_set("interface") {
+ sources = [
+ "sql_function.cc",
+ "sql_function.h",
+ ]
+ deps = [
+ "../../../../gn:default_deps",
+ "../../../../gn:sqlite",
+ "../../../../include/perfetto/trace_processor:basic_types",
+ "../../../base",
+ ]
}
perfetto_unittest_source_set("unittests") {
@@ -76,6 +90,6 @@ perfetto_unittest_source_set("unittests") {
"../../../../gn:gtest_and_gmock",
"../../../../gn:sqlite",
"../../../base",
- "../../sqlite:sqlite_minimal",
+ "../../sqlite",
]
}
diff --git a/src/trace_processor/prelude/functions/clock_functions.h b/src/trace_processor/prelude/functions/clock_functions.h
index 34f23f246..aac62803f 100644
--- a/src/trace_processor/prelude/functions/clock_functions.h
+++ b/src/trace_processor/prelude/functions/clock_functions.h
@@ -25,7 +25,7 @@
#include "src/trace_processor/prelude/functions/create_function_internal.h"
#include "src/trace_processor/util/status_macros.h"
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/prelude/functions/create_function.cc b/src/trace_processor/prelude/functions/create_function.cc
index ee2e73397..c90ad9ad8 100644
--- a/src/trace_processor/prelude/functions/create_function.cc
+++ b/src/trace_processor/prelude/functions/create_function.cc
@@ -20,6 +20,7 @@
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/prelude/functions/create_function_internal.h"
#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/tp_metatrace.h"
#include "src/trace_processor/util/status_macros.h"
@@ -31,11 +32,11 @@ namespace {
struct CreatedFunction : public SqlFunction {
struct Context {
- sqlite3* db;
+ SqliteEngine* engine;
Prototype prototype;
sql_argument::Type return_type;
std::string sql;
- sqlite3_stmt* stmt;
+ ScopedStmt stmt;
};
static base::Status Run(Context* ctx,
@@ -88,20 +89,21 @@ base::Status CreatedFunction::Run(CreatedFunction::Context* ctx,
// Bind all the arguments to the appropriate places in the function.
for (size_t i = 0; i < argc; ++i) {
- RETURN_IF_ERROR(MaybeBindArgument(ctx->stmt, ctx->prototype.function_name,
+ RETURN_IF_ERROR(MaybeBindArgument(ctx->stmt.get(),
+ ctx->prototype.function_name,
ctx->prototype.arguments[i], argv[i]));
}
- int ret = sqlite3_step(ctx->stmt);
+ int ret = sqlite3_step(ctx->stmt.get());
RETURN_IF_ERROR(
- SqliteRetToStatus(ctx->db, ctx->prototype.function_name, ret));
+ SqliteRetToStatus(ctx->engine->db(), ctx->prototype.function_name, ret));
if (ret == SQLITE_DONE) {
// No return value means we just return don't set |out|.
return base::OkStatus();
}
PERFETTO_DCHECK(ret == SQLITE_ROW);
- size_t col_count = static_cast<size_t>(sqlite3_column_count(ctx->stmt));
+ size_t col_count = static_cast<size_t>(sqlite3_column_count(ctx->stmt.get()));
if (col_count != 1) {
return base::ErrStatus(
"%s: SQL definition should only return one column: returned %zu "
@@ -109,7 +111,8 @@ base::Status CreatedFunction::Run(CreatedFunction::Context* ctx,
ctx->prototype.function_name.c_str(), col_count);
}
- out = sqlite_utils::SqliteValueToSqlValue(sqlite3_column_value(ctx->stmt, 0));
+ out = sqlite_utils::SqliteValueToSqlValue(
+ sqlite3_column_value(ctx->stmt.get(), 0));
// If we return a bytes type but have a null pointer, SQLite will convert this
// to an SQL null. However, for proto build functions, we actively want to
@@ -123,11 +126,11 @@ base::Status CreatedFunction::Run(CreatedFunction::Context* ctx,
}
base::Status CreatedFunction::VerifyPostConditions(Context* ctx) {
- int ret = sqlite3_step(ctx->stmt);
+ int ret = sqlite3_step(ctx->stmt.get());
RETURN_IF_ERROR(
- SqliteRetToStatus(ctx->db, ctx->prototype.function_name, ret));
+ SqliteRetToStatus(ctx->engine->db(), ctx->prototype.function_name, ret));
if (ret == SQLITE_ROW) {
- auto expanded_sql = sqlite_utils::ExpandedSqlForStmt(ctx->stmt);
+ auto expanded_sql = sqlite_utils::ExpandedSqlForStmt(ctx->stmt.get());
return base::ErrStatus(
"%s: multiple values were returned when executing function body. "
"Executed SQL was %s",
@@ -138,21 +141,13 @@ base::Status CreatedFunction::VerifyPostConditions(Context* ctx) {
}
void CreatedFunction::Cleanup(CreatedFunction::Context* ctx) {
- sqlite3_reset(ctx->stmt);
- sqlite3_clear_bindings(ctx->stmt);
+ sqlite3_reset(ctx->stmt.get());
+ sqlite3_clear_bindings(ctx->stmt.get());
}
} // namespace
-size_t CreateFunction::NameAndArgc::Hasher::operator()(
- const NameAndArgc& s) const noexcept {
- base::Hasher hash;
- hash.Update(s.name.data(), s.name.size());
- hash.Update(s.argc);
- return static_cast<size_t>(hash.digest());
-}
-
-base::Status CreateFunction::Run(CreateFunction::Context* ctx,
+base::Status CreateFunction::Run(SqliteEngine* engine,
size_t argc,
sqlite3_value** argv,
SqlValue&,
@@ -216,16 +211,14 @@ base::Status CreateFunction::Run(CreateFunction::Context* ctx,
}
int created_argc = static_cast<int>(prototype.arguments.size());
- NameAndArgc key{prototype.function_name, created_argc};
- auto it = ctx->state->find(key);
- if (it != ctx->state->end()) {
+ auto* fn_ctx =
+ engine->GetFunctionContext(prototype.function_name, created_argc);
+ if (fn_ctx) {
// If the function already exists, just verify that the prototype, return
// type and SQL matches exactly with what we already had registered. By
// doing this, we can avoid the problem plaguing C++ macros where macro
// ordering determines which one gets run.
- auto* created_ctx = static_cast<CreatedFunction::Context*>(
- it->second.created_functon_context);
-
+ auto* created_ctx = static_cast<CreatedFunction::Context*>(fn_ctx);
if (created_ctx->prototype != prototype) {
return base::ErrStatus(
"CREATE_FUNCTION[prototype=%s]: function prototype changed",
@@ -252,7 +245,7 @@ base::Status CreateFunction::Run(CreateFunction::Context* ctx,
// Prepare the SQL definition as a statement using SQLite.
ScopedStmt stmt;
sqlite3_stmt* stmt_raw = nullptr;
- int ret = sqlite3_prepare_v2(ctx->db, sql_defn_str.data(),
+ int ret = sqlite3_prepare_v2(engine->db(), sql_defn_str.data(),
static_cast<int>(sql_defn_str.size()), &stmt_raw,
nullptr);
if (ret != SQLITE_OK) {
@@ -261,19 +254,18 @@ base::Status CreateFunction::Run(CreateFunction::Context* ctx,
"statement %s",
prototype_str.ToStdString().c_str(),
sqlite_utils::FormatErrorMessage(
- stmt_raw, base::StringView(sql_defn_str), ctx->db, ret)
+ stmt_raw, base::StringView(sql_defn_str), engine->db(), ret)
.c_message());
}
stmt.reset(stmt_raw);
- std::unique_ptr<CreatedFunction::Context> created(
- new CreatedFunction::Context{ctx->db, std::move(prototype),
+ std::string function_name = prototype.function_name;
+ std::unique_ptr<CreatedFunction::Context> created_fn_ctx(
+ new CreatedFunction::Context{engine, std::move(prototype),
*opt_return_type, std::move(sql_defn_str),
- stmt.get()});
- CreatedFunction::Context* created_ptr = created.get();
- RETURN_IF_ERROR(RegisterSqlFunction<CreatedFunction>(
- ctx->db, key.name.c_str(), created_argc, std::move(created)));
- ctx->state->emplace(key, PerFunctionState{std::move(stmt), created_ptr});
+ std::move(stmt)});
+ RETURN_IF_ERROR(engine->RegisterSqlFunction<CreatedFunction>(
+ function_name.c_str(), created_argc, std::move(created_fn_ctx)));
// CREATE_FUNCTION doesn't have a return value so just don't sent |out|.
return base::OkStatus();
diff --git a/src/trace_processor/prelude/functions/create_function.h b/src/trace_processor/prelude/functions/create_function.h
index 258c4bbbe..0dd6f4c63 100644
--- a/src/trace_processor/prelude/functions/create_function.h
+++ b/src/trace_processor/prelude/functions/create_function.h
@@ -20,7 +20,9 @@
#include <sqlite3.h>
#include <unordered_map>
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
+#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/sqlite_table.h"
namespace perfetto {
namespace trace_processor {
@@ -34,25 +36,7 @@ struct CreateFunction : public SqlFunction {
// void* to avoid leaking state.
void* created_functon_context;
};
- struct NameAndArgc {
- std::string name;
- int argc;
-
- struct Hasher {
- std::size_t operator()(const NameAndArgc& s) const noexcept;
- };
- bool operator==(const NameAndArgc& other) const {
- return name == other.name && argc == other.argc;
- }
- };
- using State = std::unordered_map<NameAndArgc,
- CreateFunction::PerFunctionState,
- NameAndArgc::Hasher>;
-
- struct Context {
- sqlite3* db;
- State* state;
- };
+ using Context = SqliteEngine;
static constexpr bool kVoidReturn = true;
diff --git a/src/trace_processor/prelude/functions/create_view_function.cc b/src/trace_processor/prelude/functions/create_view_function.cc
index 3989de42e..952924f3f 100644
--- a/src/trace_processor/prelude/functions/create_view_function.cc
+++ b/src/trace_processor/prelude/functions/create_view_function.cc
@@ -24,6 +24,7 @@
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/prelude/functions/create_function_internal.h"
#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "src/trace_processor/sqlite/sqlite_table.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/tp_metatrace.h"
@@ -34,19 +35,20 @@ namespace trace_processor {
namespace {
-class CreatedViewFunction : public SqliteTable {
+class CreatedViewFunction final
+ : public TypedSqliteTable<CreatedViewFunction, void*> {
public:
- class Cursor : public SqliteTable::Cursor {
+ class Cursor final : public SqliteTable::BaseCursor {
public:
explicit Cursor(CreatedViewFunction* table);
- ~Cursor() override;
+ ~Cursor() final;
- int Filter(const QueryConstraints& qc,
- sqlite3_value**,
- FilterHistory) override;
- int Next() override;
- int Eof() override;
- int Column(sqlite3_context* context, int N) override;
+ base::Status Filter(const QueryConstraints& qc,
+ sqlite3_value**,
+ FilterHistory);
+ base::Status Next();
+ bool Eof();
+ base::Status Column(sqlite3_context* context, int N);
private:
ScopedStmt scoped_stmt_;
@@ -57,16 +59,11 @@ class CreatedViewFunction : public SqliteTable {
};
CreatedViewFunction(sqlite3*, void*);
- ~CreatedViewFunction() override;
+ ~CreatedViewFunction() final;
- base::Status Init(int argc, const char* const* argv, Schema*) override;
- std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
- int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) override;
-
- static void Register(sqlite3* db) {
- SqliteTable::Register<CreatedViewFunction>(
- db, nullptr, "internal_view_function_impl", false, true);
- }
+ base::Status Init(int argc, const char* const* argv, Schema*) final;
+ std::unique_ptr<SqliteTable::BaseCursor> CreateCursor() final;
+ int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) final;
private:
Schema CreateSchema();
@@ -246,7 +243,7 @@ SqliteTable::Schema CreatedViewFunction::CreateSchema() {
return SqliteTable::Schema(std::move(columns), std::move(primary_keys));
}
-std::unique_ptr<SqliteTable::Cursor> CreatedViewFunction::CreateCursor() {
+std::unique_ptr<SqliteTable::BaseCursor> CreatedViewFunction::CreateCursor() {
return std::unique_ptr<Cursor>(new Cursor(this));
}
@@ -272,13 +269,13 @@ int CreatedViewFunction::BestIndex(const QueryConstraints& qc,
}
CreatedViewFunction::Cursor::Cursor(CreatedViewFunction* table)
- : SqliteTable::Cursor(table), table_(table) {}
+ : SqliteTable::BaseCursor(table), table_(table) {}
CreatedViewFunction::Cursor::~Cursor() = default;
-int CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
- sqlite3_value** argv,
- FilterHistory) {
+base::Status CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
+ sqlite3_value** argv,
+ FilterHistory) {
PERFETTO_TP_TRACE(metatrace::Category::FUNCTION, "CREATE_VIEW_FUNCTION",
[this](metatrace::Record* r) {
r->AddArg("Function",
@@ -302,10 +299,8 @@ int CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
// We only support equality constraints as we're expecting "input arguments"
// to our "function".
if (!sqlite_utils::IsOpEq(cs.op)) {
- table_->SetErrorMessage(
- sqlite3_mprintf("%s: non-equality constraint passed",
- table_->prototype_.function_name.c_str()));
- return SQLITE_ERROR;
+ return base::ErrStatus("%s: non-equality constraint passed",
+ table_->prototype_.function_name.c_str());
}
const auto& arg = table_->prototype_.arguments[col_to_arg_idx(cs.column)];
@@ -313,11 +308,9 @@ int CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
argv[i], sql_argument::TypeToSqlValueType(arg.type()),
sql_argument::TypeToHumanFriendlyString(arg.type()));
if (!status.ok()) {
- table_->SetErrorMessage(
- sqlite3_mprintf("%s: argument %s (index %u) %s",
- table_->prototype_.function_name.c_str(),
- arg.name().c_str(), i, status.c_message()));
- return SQLITE_ERROR;
+ return base::ErrStatus("%s: argument %s (index %zu) %s",
+ table_->prototype_.function_name.c_str(),
+ arg.name().c_str(), i, status.c_message());
}
seen_argument_constraints++;
@@ -325,12 +318,11 @@ int CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
// Verify that we saw one valid constriant for every input argument.
if (seen_argument_constraints < table_->prototype_.arguments.size()) {
- table_->SetErrorMessage(sqlite3_mprintf(
- "%s: missing value for input argument. Saw %u arguments but expected "
- "%u",
+ return base::ErrStatus(
+ "%s: missing value for input argument. Saw %zu arguments but expected "
+ "%zu",
table_->prototype_.function_name.c_str(), seen_argument_constraints,
- table_->prototype_.arguments.size()));
- return SQLITE_ERROR;
+ table_->prototype_.arguments.size());
}
// Prepare the SQL definition as a statement using SQLite.
@@ -361,10 +353,7 @@ int CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
const auto& arg = table_->prototype_.arguments[index];
auto status = MaybeBindArgument(stmt_, table_->prototype_.function_name,
arg, argv[i]);
- if (!status.ok()) {
- table_->SetErrorMessage(sqlite3_mprintf("%s", status.c_message()));
- return SQLITE_ERROR;
- }
+ RETURN_IF_ERROR(status);
}
// Reset the next call count - this is necessary because the same cursor
@@ -373,26 +362,25 @@ int CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
return Next();
}
-int CreatedViewFunction::Cursor::Next() {
+base::Status CreatedViewFunction::Cursor::Next() {
int ret = sqlite3_step(stmt_);
is_eof_ = ret == SQLITE_DONE;
next_call_count_++;
if (ret != SQLITE_ROW && ret != SQLITE_DONE) {
- table_->SetErrorMessage(sqlite3_mprintf(
+ return base::ErrStatus(
"%s: SQLite error while stepping statement: %s",
table_->prototype_.function_name.c_str(),
sqlite_utils::FormatErrorMessage(stmt_, std::nullopt, table_->db_, ret)
- .c_message()));
- return ret;
+ .c_message());
}
- return SQLITE_OK;
+ return base::OkStatus();
}
-int CreatedViewFunction::Cursor::Eof() {
+bool CreatedViewFunction::Cursor::Eof() {
return is_eof_;
}
-int CreatedViewFunction::Cursor::Column(sqlite3_context* ctx, int i) {
+base::Status CreatedViewFunction::Cursor::Column(sqlite3_context* ctx, int i) {
size_t idx = static_cast<size_t>(i);
if (table_->IsReturnValueColumn(idx)) {
sqlite3_result_value(ctx, sqlite3_column_value(stmt_, i));
@@ -406,7 +394,7 @@ int CreatedViewFunction::Cursor::Column(sqlite3_context* ctx, int i) {
PERFETTO_DCHECK(table_->IsPrimaryKeyColumn(idx));
sqlite3_result_int(ctx, next_call_count_);
}
- return SQLITE_OK;
+ return base::OkStatus();
}
} // namespace
@@ -494,8 +482,10 @@ base::Status CreateViewFunction::Run(CreateViewFunction::Context* ctx,
return base::OkStatus();
}
-void CreateViewFunction::RegisterTable(sqlite3* db) {
- CreatedViewFunction::Register(db);
+void RegisterCreateViewFunctionModule(SqliteEngine* engine) {
+ engine->RegisterVirtualTableModule<CreatedViewFunction>(
+ "internal_view_function_impl", nullptr,
+ SqliteTable::TableType::kExplicitCreate, false);
}
} // namespace trace_processor
diff --git a/src/trace_processor/prelude/functions/create_view_function.h b/src/trace_processor/prelude/functions/create_view_function.h
index c91817a9e..509ea5e64 100644
--- a/src/trace_processor/prelude/functions/create_view_function.h
+++ b/src/trace_processor/prelude/functions/create_view_function.h
@@ -20,11 +20,13 @@
#include <sqlite3.h>
#include <unordered_map>
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
namespace perfetto {
namespace trace_processor {
+class SqliteEngine;
+
// Implementation of CREATE_VIEW_FUNCTION SQL function.
// See https://perfetto.dev/docs/analysis/metrics#metric-helper-functions for
// usage of this function.
@@ -40,10 +42,10 @@ struct CreateViewFunction : public SqlFunction {
sqlite3_value** argv,
SqlValue& out,
Destructors&);
-
- static void RegisterTable(sqlite3* db);
};
+void RegisterCreateViewFunctionModule(SqliteEngine*);
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/prelude/functions/import.h b/src/trace_processor/prelude/functions/import.h
index 9773b5f0e..da40f5fbb 100644
--- a/src/trace_processor/prelude/functions/import.h
+++ b/src/trace_processor/prelude/functions/import.h
@@ -23,7 +23,7 @@
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/trace_processor/trace_processor.h"
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
#include "src/trace_processor/util/sql_modules.h"
namespace perfetto {
diff --git a/src/trace_processor/prelude/functions/register_function.h b/src/trace_processor/prelude/functions/register_function.h
deleted file mode 100644
index acca3e62a..000000000
--- a/src/trace_processor/prelude/functions/register_function.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_REGISTER_FUNCTION_H_
-#define SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_REGISTER_FUNCTION_H_
-
-#include <sqlite3.h>
-#include <memory>
-
-#include "src/trace_processor/sqlite/sqlite_utils.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// Prototype for a C++ function which can be registered with SQLite.
-//
-// Usage
-//
-// Define a subclass of this struct as follows:
-// struct YourFunction : public SqlFunction {
-// // Optional if you want a custom context object (i.e. an object
-// // passed in at registration time which will be passed to Run on
-// // every invocation)
-// struct YourContext { /* define context fields here */ };
-//
-// static base::Status Run(/* see parameters below */) {
-// /* function body here */
-// }
-//
-// static base::Status Cleanup(/* see parameters below */) {
-// /* function body here */
-// }
-// }
-//
-// Then, register this function with SQLite using RegisterFunction (see below);
-// you'll likely want to do this in TraceProcessorImpl:
-// RegisterFunction<YourFunction>(/* see arguments below */)
-struct SqlFunction {
- // The type of the context object which will be passed to the function.
- // Can be redefined in any sub-classes to override the context.
- using Context = void;
-
- // Indicates whether this function is "void" (i.e. doesn't actually want
- // to return a value). While the function will still return null in SQL
- // (because SQLite does not actually allow null functions), for accounting
- // purposes, this null will be ignored when verifying whether this statement
- // has any output.
- // Can be redefined in any sub-classes to override it.
- // If this is set to true, subclasses must not modify |out| or |destructors|.
- static constexpr bool kVoidReturn = false;
-
- // Struct which holds destructors for strings/bytes returned from the
- // function. Passed as an argument to |Run| to allow implementations to
- // override the destructors.
- struct Destructors {
- sqlite3_destructor_type string_destructor = sqlite_utils::kSqliteTransient;
- sqlite3_destructor_type bytes_destructor = sqlite_utils::kSqliteTransient;
- };
-
- // The function which will be exectued with the arguments from SQL.
- //
- // Implementations MUST define this function themselves; this function is
- // declared but *not* defined so linker errors will be thrown if not defined.
- //
- // |ctx|: the context object passed at registration time.
- // |argc|: number of arguments.
- // |argv|: arguments to the function.
- // |out|: the return value of the function.
- // |destructors|: destructors for string/bytes return values.
- static base::Status Run(Context* ctx,
- size_t argc,
- sqlite3_value** argv,
- SqlValue& out,
- Destructors& destructors);
-
- // Executed after the result from |Run| is reported to SQLite.
- // Allows implementations to verify post-conditions without needing to worry
- // about overwriting return types.
- //
- // Implementations do not need to define this function; a default no-op
- // implementation will be used in this case.
- static base::Status VerifyPostConditions(Context*);
-
- // Executed after the result from |Run| is reported to SQLite.
- // Allows any pending state to be cleaned up post-copy of results by SQLite:
- // this function will be called even if |Run| or |PostRun| returned errors.
- //
- // Implementations do not need to define this function; a default no-op
- // implementation will be used in this case.
- static void Cleanup(Context*);
-};
-
-// Registers a C++ function to be runnable from SQL.
-// The format of the function is given by the |SqlFunction|; see the
-// documentaion above.
-//
-// |db|: sqlite3 database object
-// |name|: name of the function in SQL
-// |argc|: number of arguments for this function, -1 if variable
-// |ctx|: context object for the function (see SqlFunction::Run above);
-// this object *must* outlive the function so should likely be
-// either static or scoped to the lifetime of TraceProcessor.
-// |determistic|: whether this function has deterministic output given the
-// same set of arguments.
-template <typename Function>
-base::Status RegisterSqlFunction(sqlite3* db,
- const char* name,
- int argc,
- typename Function::Context* ctx,
- bool deterministic = true);
-
-// Same as above except allows a unique_ptr to be passed for the context; this
-// allows for SQLite to manage the lifetime of this pointer instead of the
-// essentially static requirement of the context pointer above.
-template <typename Function>
-base::Status RegisterSqlFunction(
- sqlite3* db,
- const char* name,
- int argc,
- std::unique_ptr<typename Function::Context> ctx,
- bool deterministic = true);
-
-} // namespace trace_processor
-} // namespace perfetto
-
-// The rest of this file is just implementation details which we need
-// in the header file because it is templated code. We separate it out
-// like this to keep the API people actually care about easy to read.
-
-namespace perfetto {
-namespace trace_processor {
-
-namespace sqlite_internal {
-
-// RAII type to call Function::Cleanup when destroyed.
-template <typename Function>
-struct ScopedCleanup {
- typename Function::Context* ctx;
- ~ScopedCleanup() { Function::Cleanup(ctx); }
-};
-
-template <typename Function>
-void WrapSqlFunction(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
- using Context = typename Function::Context;
- Context* ud = static_cast<Context*>(sqlite3_user_data(ctx));
-
- ScopedCleanup<Function> scoped_cleanup{ud};
- SqlValue value{};
- SqlFunction::Destructors destructors{};
- base::Status status =
- Function::Run(ud, static_cast<size_t>(argc), argv, value, destructors);
- if (!status.ok()) {
- sqlite3_result_error(ctx, status.c_message(), -1);
- return;
- }
-
- if (Function::kVoidReturn) {
- if (!value.is_null()) {
- sqlite3_result_error(ctx, "void SQL function returned value", -1);
- return;
- }
-
- // If the function doesn't want to return anything, set the "VOID"
- // pointer type to a non-null value. Note that because of the weird
- // way |sqlite3_value_pointer| works, we need to set some value even
- // if we don't actually read it - just set it to a pointer to an empty
- // string for this reason.
- static char kVoidValue[] = "";
- sqlite3_result_pointer(ctx, kVoidValue, "VOID", nullptr);
- } else {
- sqlite_utils::ReportSqlValue(ctx, value, destructors.string_destructor,
- destructors.bytes_destructor);
- }
-
- status = Function::VerifyPostConditions(ud);
- if (!status.ok()) {
- sqlite3_result_error(ctx, status.c_message(), -1);
- return;
- }
-}
-} // namespace sqlite_internal
-
-template <typename Function>
-base::Status RegisterSqlFunction(sqlite3* db,
- const char* name,
- int argc,
- typename Function::Context* ctx,
- bool deterministic) {
- int flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0);
- int ret = sqlite3_create_function_v2(
- db, name, static_cast<int>(argc), flags, ctx,
- sqlite_internal::WrapSqlFunction<Function>, nullptr, nullptr, nullptr);
- if (ret != SQLITE_OK) {
- return base::ErrStatus("Unable to register function with name %s", name);
- }
- return base::OkStatus();
-}
-
-template <typename Function>
-base::Status RegisterSqlFunction(
- sqlite3* db,
- const char* name,
- int argc,
- std::unique_ptr<typename Function::Context> user_data,
- bool deterministic) {
- int flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0);
- int ret = sqlite3_create_function_v2(
- db, name, static_cast<int>(argc), flags, user_data.release(),
- sqlite_internal::WrapSqlFunction<Function>, nullptr, nullptr,
- [](void* ptr) { delete static_cast<typename Function::Context*>(ptr); });
- if (ret != SQLITE_OK) {
- return base::ErrStatus("Unable to register function with name %s", name);
- }
- return base::OkStatus();
-}
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_REGISTER_FUNCTION_H_
diff --git a/src/trace_processor/prelude/functions/register_function.cc b/src/trace_processor/prelude/functions/sql_function.cc
index ef41f1d62..26bac5e5b 100644
--- a/src/trace_processor/prelude/functions/register_function.cc
+++ b/src/trace_processor/prelude/functions/sql_function.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-#include "src/trace_processor/prelude/functions/register_function.h"
-#include "sqlite3.h"
-#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/prelude/functions/sql_function.h b/src/trace_processor/prelude/functions/sql_function.h
new file mode 100644
index 000000000..ba7fab7d8
--- /dev/null
+++ b/src/trace_processor/prelude/functions/sql_function.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_SQL_FUNCTION_H_
+#define SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_SQL_FUNCTION_H_
+
+#include <sqlite3.h>
+#include <memory>
+
+#include "perfetto/base/status.h"
+#include "perfetto/trace_processor/basic_types.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Prototype for a C++ function which can be registered with SQLite.
+//
+// Usage
+//
+// Define a subclass of this struct as follows:
+// struct YourFunction : public SqlFunction {
+// // Optional if you want a custom context object (i.e. an object
+// // passed in at registration time which will be passed to Run on
+// // every invocation)
+// struct YourContext { /* define context fields here */ };
+//
+// static base::Status Run(/* see parameters below */) {
+// /* function body here */
+// }
+//
+// static base::Status Cleanup(/* see parameters below */) {
+// /* function body here */
+// }
+// }
+//
+// Then, register this function with SQLite using RegisterFunction (see below);
+// you'll likely want to do this in TraceProcessorImpl:
+// RegisterFunction<YourFunction>(/* see arguments below */)
+struct SqlFunction {
+ // The type of the context object which will be passed to the function.
+ // Can be redefined in any sub-classes to override the context.
+ using Context = void;
+
+ // Indicates whether this function is "void" (i.e. doesn't actually want
+ // to return a value). While the function will still return null in SQL
+ // (because SQLite does not actually allow null functions), for accounting
+ // purposes, this null will be ignored when verifying whether this statement
+ // has any output.
+ // Can be redefined in any sub-classes to override it.
+ // If this is set to true, subclasses must not modify |out| or |destructors|.
+ static constexpr bool kVoidReturn = false;
+
+ // Struct which holds destructors for strings/bytes returned from the
+ // function. Passed as an argument to |Run| to allow implementations to
+ // override the destructors.
+ struct Destructors {
+ // This matches SQLITE_TRANSIENT constant which we cannot use because it
+ // expands to a C-style cast, causing compiler warnings.
+ sqlite3_destructor_type string_destructor =
+ reinterpret_cast<sqlite3_destructor_type>(-1);
+ sqlite3_destructor_type bytes_destructor =
+ reinterpret_cast<sqlite3_destructor_type>(-1);
+ };
+
+ // The function which will be executed with the arguments from SQL.
+ //
+ // Implementations MUST define this function themselves; this function is
+ // declared but *not* defined so linker errors will be thrown if not defined.
+ //
+ // |ctx|: the context object passed at registration time.
+ // |argc|: number of arguments.
+ // |argv|: arguments to the function.
+ // |out|: the return value of the function.
+ // |destructors|: destructors for string/bytes return values.
+ static base::Status Run(Context* ctx,
+ size_t argc,
+ sqlite3_value** argv,
+ SqlValue& out,
+ Destructors& destructors);
+
+ // Executed after the result from |Run| is reported to SQLite.
+ // Allows implementations to verify post-conditions without needing to worry
+ // about overwriting return types.
+ //
+ // Implementations do not need to define this function; a default no-op
+ // implementation will be used in this case.
+ static base::Status VerifyPostConditions(Context*);
+
+ // Executed after the result from |Run| is reported to SQLite.
+ // Allows any pending state to be cleaned up post-copy of results by SQLite:
+ // this function will be called even if |Run| or |PostRun| returned errors.
+ //
+ // Implementations do not need to define this function; a default no-op
+ // implementation will be used in this case.
+ static void Cleanup(Context*);
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_SQL_FUNCTION_H_
diff --git a/src/trace_processor/prelude/functions/stack_functions.cc b/src/trace_processor/prelude/functions/stack_functions.cc
index 2f8730b51..e2c446827 100644
--- a/src/trace_processor/prelude/functions/stack_functions.cc
+++ b/src/trace_processor/prelude/functions/stack_functions.cc
@@ -31,7 +31,8 @@
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/status.h"
#include "protos/perfetto/trace_processor/stack.pbzero.h"
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
+#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
@@ -243,15 +244,16 @@ struct StackFromStackProfileFrameFunction : public SqlFunction {
} // namespace
-base::Status RegisterStackFunctions(sqlite3* db,
+base::Status RegisterStackFunctions(SqliteEngine* engine,
TraceProcessorContext* context) {
- RETURN_IF_ERROR(RegisterSqlFunction<CatStacksFunction>(
- db, CatStacksFunction::kFunctionName, -1, context->storage.get()));
- RETURN_IF_ERROR(RegisterSqlFunction<StackFromStackProfileFrameFunction>(
- db, StackFromStackProfileFrameFunction::kFunctionName, 1,
- context->storage.get()));
- return RegisterSqlFunction<StackFromStackProfileCallsiteFunction>(
- db, StackFromStackProfileCallsiteFunction::kFunctionName, -1,
+ RETURN_IF_ERROR(engine->RegisterSqlFunction<CatStacksFunction>(
+ CatStacksFunction::kFunctionName, -1, context->storage.get()));
+ RETURN_IF_ERROR(
+ engine->RegisterSqlFunction<StackFromStackProfileFrameFunction>(
+ StackFromStackProfileFrameFunction::kFunctionName, 1,
+ context->storage.get()));
+ return engine->RegisterSqlFunction<StackFromStackProfileCallsiteFunction>(
+ StackFromStackProfileCallsiteFunction::kFunctionName, -1,
context->storage.get());
}
diff --git a/src/trace_processor/prelude/functions/stack_functions.h b/src/trace_processor/prelude/functions/stack_functions.h
index 5acb046b8..7fd676cfd 100644
--- a/src/trace_processor/prelude/functions/stack_functions.h
+++ b/src/trace_processor/prelude/functions/stack_functions.h
@@ -26,6 +26,7 @@
namespace perfetto {
namespace trace_processor {
+class SqliteEngine;
class TraceProcessorContext;
// Registers the stack manipulation related functions:
@@ -49,7 +50,7 @@ class TraceProcessorContext;
// it generates a fake Frame
//
// See protos/perfetto/trace_processor/stack.proto
-base::Status RegisterStackFunctions(sqlite3* db,
+base::Status RegisterStackFunctions(SqliteEngine* engine,
TraceProcessorContext* context);
} // namespace trace_processor
diff --git a/src/trace_processor/sqlite/sqlite_raw_table.cc b/src/trace_processor/prelude/functions/to_ftrace.cc
index feaca0010..5bb138f6e 100644
--- a/src/trace_processor/sqlite/sqlite_raw_table.cc
+++ b/src/trace_processor/prelude/functions/to_ftrace.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#include "src/trace_processor/sqlite/sqlite_raw_table.h"
-
-#include <cinttypes>
+#include "src/trace_processor/prelude/functions/to_ftrace.h"
#include "perfetto/base/compiler.h"
+#include "perfetto/base/status.h"
#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/importers/common/system_info_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_descriptors.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
@@ -538,46 +538,24 @@ void ArgsSerializer::WriteValue(const Variadic& value) {
} // namespace
-SqliteRawTable::SqliteRawTable(sqlite3* db, Context context)
- : DbSqliteTable(db,
- {context.cache, TableComputation::kStatic,
- &context.context->storage->raw_table(), nullptr}),
- serializer_(context.context) {
- auto fn = [](sqlite3_context* ctx, int argc, sqlite3_value** argv) {
- auto* thiz = static_cast<SqliteRawTable*>(sqlite3_user_data(ctx));
- thiz->ToSystrace(ctx, argc, argv);
- };
- sqlite3_create_function(db, "to_ftrace", 1,
- SQLITE_UTF8 | SQLITE_DETERMINISTIC, this, fn, nullptr,
- nullptr);
-}
-
-SqliteRawTable::~SqliteRawTable() = default;
-
-void SqliteRawTable::RegisterTable(sqlite3* db,
- QueryCache* cache,
- TraceProcessorContext* context) {
- SqliteTable::Register<SqliteRawTable, Context>(db, Context{cache, context},
- "raw");
-}
-
-void SqliteRawTable::ToSystrace(sqlite3_context* ctx,
- int argc,
- sqlite3_value** argv) {
+base::Status ToFtrace::Run(Context* context,
+ size_t argc,
+ sqlite3_value** argv,
+ SqlValue& out,
+ Destructors& destructors) {
if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
- sqlite3_result_error(ctx, "Usage: to_ftrace(id)", -1);
- return;
+ return base::ErrStatus("Usage: to_ftrace(id)");
}
uint32_t row = static_cast<uint32_t>(sqlite3_value_int64(argv[0]));
- auto str = serializer_.SerializeToString(row);
+ auto str = context->serializer.SerializeToString(row);
if (str.get() == nullptr) {
- base::StackString<128> err("to_ftrace: Cannot serialize row id %u", row);
- sqlite3_result_error(ctx, err.c_str(), -1);
- return;
+ return base::ErrStatus("to_ftrace: Cannot serialize row id %u", row);
}
- sqlite3_result_text(ctx, str.release(), -1, str.get_deleter());
+ out = SqlValue::String(str.release());
+ destructors.string_destructor = str.get_deleter();
+ return base::OkStatus();
}
SystraceSerializer::SystraceSerializer(TraceProcessorContext* context)
diff --git a/src/trace_processor/sqlite/sqlite_raw_table.h b/src/trace_processor/prelude/functions/to_ftrace.h
index dcb5c46f9..9c5506776 100644
--- a/src/trace_processor/sqlite/sqlite_raw_table.h
+++ b/src/trace_processor/prelude/functions/to_ftrace.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,14 @@
* limitations under the License.
*/
-#ifndef SRC_TRACE_PROCESSOR_SQLITE_SQLITE_RAW_TABLE_H_
-#define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_RAW_TABLE_H_
+#ifndef SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_TO_FTRACE_H_
+#define SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_TO_FTRACE_H_
-#include "perfetto/base/logging.h"
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/ext/base/string_writer.h"
-#include "src/trace_processor/sqlite/db_sqlite_table.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/types/variadic.h"
namespace perfetto {
namespace trace_processor {
@@ -47,25 +45,20 @@ class SystraceSerializer {
TraceProcessorContext* context_ = nullptr;
};
-class SqliteRawTable : public DbSqliteTable {
- public:
+struct ToFtrace : public SqlFunction {
struct Context {
- QueryCache* cache;
- TraceProcessorContext* context;
+ const TraceStorage* storage;
+ SystraceSerializer serializer;
};
- SqliteRawTable(sqlite3*, Context);
- ~SqliteRawTable() override;
-
- static void RegisterTable(sqlite3* db, QueryCache*, TraceProcessorContext*);
-
- private:
- void ToSystrace(sqlite3_context* ctx, int argc, sqlite3_value** argv);
-
- SystraceSerializer serializer_;
+ static base::Status Run(Context*,
+ size_t argc,
+ sqlite3_value** argv,
+ SqlValue& out,
+ Destructors& destructors);
};
} // namespace trace_processor
} // namespace perfetto
-#endif // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_RAW_TABLE_H_
+#endif // SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_TO_FTRACE_H_
diff --git a/src/trace_processor/prelude/functions/utils.h b/src/trace_processor/prelude/functions/utils.h
index 82b293fbb..ac848d094 100644
--- a/src/trace_processor/prelude/functions/utils.h
+++ b/src/trace_processor/prelude/functions/utils.h
@@ -19,6 +19,7 @@
#include <sqlite3.h>
#include <unordered_map>
+
#include "perfetto/ext/base/base64.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/trace_processor/demangle.h"
@@ -26,10 +27,10 @@
#include "src/trace_processor/export_json.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
#include "src/trace_processor/prelude/functions/create_function_internal.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/util/status_macros.h"
-#include "src/trace_processor/prelude/functions/register_function.h"
-
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/prelude/functions/window_functions.h b/src/trace_processor/prelude/functions/window_functions.h
index 3a76fcedb..a3fbeafa5 100644
--- a/src/trace_processor/prelude/functions/window_functions.h
+++ b/src/trace_processor/prelude/functions/window_functions.h
@@ -28,7 +28,7 @@
#include "src/trace_processor/prelude/functions/create_function_internal.h"
#include "src/trace_processor/util/status_macros.h"
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/prelude/operators/BUILD.gn b/src/trace_processor/prelude/operators/BUILD.gn
index 2a3daa619..3d994a7bd 100644
--- a/src/trace_processor/prelude/operators/BUILD.gn
+++ b/src/trace_processor/prelude/operators/BUILD.gn
@@ -42,5 +42,6 @@ perfetto_unittest_source_set("unittests") {
"../../../../gn:default_deps",
"../../../../gn:gtest_and_gmock",
"../../../../gn:sqlite",
+ "../../sqlite",
]
}
diff --git a/src/trace_processor/prelude/operators/span_join_operator.cc b/src/trace_processor/prelude/operators/span_join_operator.cc
index 7d4ccb807..2ee2839eb 100644
--- a/src/trace_processor/prelude/operators/span_join_operator.cc
+++ b/src/trace_processor/prelude/operators/span_join_operator.cc
@@ -24,6 +24,7 @@
#include <utility>
#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
@@ -105,23 +106,9 @@ std::string EscapedSqliteValueAsString(sqlite3_value* value) {
} // namespace
-SpanJoinOperatorTable::SpanJoinOperatorTable(sqlite3* db, const TraceStorage*)
+SpanJoinOperatorTable::SpanJoinOperatorTable(sqlite3* db, const void*)
: db_(db) {}
-
-void SpanJoinOperatorTable::RegisterTable(sqlite3* db,
- const TraceStorage* storage) {
- SqliteTable::Register<SpanJoinOperatorTable>(db, storage, "span_join",
- /* read_write */ false,
- /* requires_args */ true);
-
- SqliteTable::Register<SpanJoinOperatorTable>(db, storage, "span_left_join",
- /* read_write */ false,
- /* requires_args */ true);
-
- SqliteTable::Register<SpanJoinOperatorTable>(db, storage, "span_outer_join",
- /* read_write */ false,
- /* requires_args */ true);
-}
+SpanJoinOperatorTable::~SpanJoinOperatorTable() = default;
util::Status SpanJoinOperatorTable::Init(int argc,
const char* const* argv,
@@ -241,7 +228,7 @@ void SpanJoinOperatorTable::CreateSchemaColsForDefn(
}
}
-std::unique_ptr<SqliteTable::Cursor> SpanJoinOperatorTable::CreateCursor() {
+std::unique_ptr<SqliteTable::BaseCursor> SpanJoinOperatorTable::CreateCursor() {
return std::unique_ptr<SpanJoinOperatorTable::Cursor>(new Cursor(this, db_));
}
@@ -406,14 +393,15 @@ std::string SpanJoinOperatorTable::GetNameForGlobalColumnIndex(
}
SpanJoinOperatorTable::Cursor::Cursor(SpanJoinOperatorTable* table, sqlite3* db)
- : SqliteTable::Cursor(table),
+ : SqliteTable::BaseCursor(table),
t1_(table, &table->t1_defn_, db),
t2_(table, &table->t2_defn_, db),
table_(table) {}
+SpanJoinOperatorTable::Cursor::~Cursor() = default;
-base::Status SpanJoinOperatorTable::Cursor::FilterInner(
- const QueryConstraints& qc,
- sqlite3_value** argv) {
+base::Status SpanJoinOperatorTable::Cursor::Filter(const QueryConstraints& qc,
+ sqlite3_value** argv,
+ FilterHistory) {
PERFETTO_TP_TRACE(metatrace::Category::QUERY, "SPAN_JOIN_XFILTER");
bool t1_partitioned_mixed =
@@ -435,7 +423,7 @@ base::Status SpanJoinOperatorTable::Cursor::FilterInner(
return FindOverlappingSpan();
}
-base::Status SpanJoinOperatorTable::Cursor::NextInner() {
+base::Status SpanJoinOperatorTable::Cursor::Next() {
RETURN_IF_ERROR(next_query_->Next());
return FindOverlappingSpan();
}
@@ -556,11 +544,12 @@ SpanJoinOperatorTable::Cursor::FindEarliestFinishQuery() {
return t1_less ? &t1_ : &t2_;
}
-int SpanJoinOperatorTable::Cursor::Eof() {
+bool SpanJoinOperatorTable::Cursor::Eof() {
return t1_.IsEof() || t2_.IsEof();
}
-int SpanJoinOperatorTable::Cursor::Column(sqlite3_context* context, int N) {
+base::Status SpanJoinOperatorTable::Cursor::Column(sqlite3_context* context,
+ int N) {
PERFETTO_DCHECK(t1_.IsReal() || t2_.IsReal());
switch (N) {
@@ -598,7 +587,7 @@ int SpanJoinOperatorTable::Cursor::Column(sqlite3_context* context, int N) {
t2_.ReportSqliteResult(context, locator.col_index);
}
}
- return SQLITE_OK;
+ return base::OkStatus();
}
SpanJoinOperatorTable::Query::Query(SpanJoinOperatorTable* table,
diff --git a/src/trace_processor/prelude/operators/span_join_operator.h b/src/trace_processor/prelude/operators/span_join_operator.h
index f150a7532..3f7a006fb 100644
--- a/src/trace_processor/prelude/operators/span_join_operator.h
+++ b/src/trace_processor/prelude/operators/span_join_operator.h
@@ -69,7 +69,8 @@ namespace trace_processor {
//
// All other columns apart from timestamp (ts), duration (dur) and the join key
// are passed through unchanged.
-class SpanJoinOperatorTable : public SqliteTable {
+class SpanJoinOperatorTable final
+ : public TypedSqliteTable<SpanJoinOperatorTable, const void*> {
public:
// Enum indicating whether the queries on the two inner tables should
// emit shadows.
@@ -316,32 +317,17 @@ class SpanJoinOperatorTable : public SqliteTable {
};
// Base class for a cursor on the span table.
- class Cursor : public SqliteTable::Cursor {
+ class Cursor final : public SqliteTable::BaseCursor {
public:
Cursor(SpanJoinOperatorTable*, sqlite3* db);
- ~Cursor() override = default;
-
- int Filter(const QueryConstraints& qc,
- sqlite3_value** argv,
- FilterHistory) override {
- base::Status status = FilterInner(qc, argv);
- if (!status.ok()) {
- table_->SetErrorMessage(sqlite3_mprintf("%s", status.c_message()));
- return SQLITE_ERROR;
- }
- return SQLITE_OK;
- }
- int Next() override {
- base::Status status = NextInner();
- if (!status.ok()) {
- table_->SetErrorMessage(sqlite3_mprintf("%s", status.c_message()));
- return SQLITE_ERROR;
- }
- return SQLITE_OK;
- }
+ ~Cursor() final;
- int Column(sqlite3_context* context, int N) override;
- int Eof() override;
+ base::Status Filter(const QueryConstraints& qc,
+ sqlite3_value** argv,
+ FilterHistory);
+ base::Status Next();
+ base::Status Column(sqlite3_context* context, int N);
+ bool Eof();
private:
Cursor(Cursor&) = delete;
@@ -351,11 +337,7 @@ class SpanJoinOperatorTable : public SqliteTable {
Cursor& operator=(Cursor&&) = default;
bool IsOverlappingSpan();
-
- base::Status NextInner();
- base::Status FilterInner(const QueryConstraints& qc, sqlite3_value** argv);
util::Status FindOverlappingSpan();
-
Query* FindEarliestFinishQuery();
Query t1_;
@@ -369,15 +351,14 @@ class SpanJoinOperatorTable : public SqliteTable {
SpanJoinOperatorTable* table_;
};
- SpanJoinOperatorTable(sqlite3*, const TraceStorage*);
-
- static void RegisterTable(sqlite3* db, const TraceStorage* storage);
+ SpanJoinOperatorTable(sqlite3*, const void*);
+ ~SpanJoinOperatorTable() final;
// Table implementation.
- util::Status Init(int, const char* const*, SqliteTable::Schema*) override;
- std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
- int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) override;
- int FindFunction(const char* name, FindFunctionFn* fn, void** args) override;
+ util::Status Init(int, const char* const*, SqliteTable::Schema*) final;
+ std::unique_ptr<SqliteTable::BaseCursor> CreateCursor() final;
+ int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) final;
+ int FindFunction(const char* name, FindFunctionFn* fn, void** args) final;
private:
// Columns of the span operator table.
diff --git a/src/trace_processor/prelude/operators/span_join_operator_unittest.cc b/src/trace_processor/prelude/operators/span_join_operator_unittest.cc
index 737e82860..661a7f101 100644
--- a/src/trace_processor/prelude/operators/span_join_operator_unittest.cc
+++ b/src/trace_processor/prelude/operators/span_join_operator_unittest.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/prelude/operators/span_join_operator.h"
+#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
@@ -25,19 +26,19 @@ namespace {
class SpanJoinOperatorTableTest : public ::testing::Test {
public:
SpanJoinOperatorTableTest() {
- sqlite3* db = nullptr;
- PERFETTO_CHECK(sqlite3_initialize() == SQLITE_OK);
- PERFETTO_CHECK(sqlite3_open(":memory:", &db) == SQLITE_OK);
- db_.reset(db);
-
- SpanJoinOperatorTable::RegisterTable(db_.get(), nullptr);
+ engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
+ "span_join", nullptr, SqliteTable::TableType::kExplicitCreate, false);
+ engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
+ "span_left_join", nullptr, SqliteTable::TableType::kExplicitCreate,
+ false);
}
void PrepareValidStatement(const std::string& sql) {
int size = static_cast<int>(sql.size());
sqlite3_stmt* stmt;
- ASSERT_EQ(sqlite3_prepare_v2(*db_, sql.c_str(), size, &stmt, nullptr),
- SQLITE_OK);
+ ASSERT_EQ(
+ sqlite3_prepare_v2(engine_.db(), sql.c_str(), size, &stmt, nullptr),
+ SQLITE_OK);
stmt_.reset(stmt);
}
@@ -55,7 +56,7 @@ class SpanJoinOperatorTableTest : public ::testing::Test {
}
protected:
- ScopedDb db_;
+ SqliteEngine engine_;
ScopedStmt stmt_;
};
diff --git a/src/trace_processor/prelude/operators/window_operator.cc b/src/trace_processor/prelude/operators/window_operator.cc
index b308c5302..68f2ff474 100644
--- a/src/trace_processor/prelude/operators/window_operator.cc
+++ b/src/trace_processor/prelude/operators/window_operator.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/prelude/operators/window_operator.h"
+#include "perfetto/base/status.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
namespace perfetto {
@@ -26,11 +27,7 @@ using namespace sqlite_utils;
} // namespace
WindowOperatorTable::WindowOperatorTable(sqlite3*, const TraceStorage*) {}
-
-void WindowOperatorTable::RegisterTable(sqlite3* db,
- const TraceStorage* storage) {
- SqliteTable::Register<WindowOperatorTable>(db, storage, "window", true);
-}
+WindowOperatorTable::~WindowOperatorTable() = default;
base::Status WindowOperatorTable::Init(int,
const char* const*,
@@ -57,54 +54,55 @@ base::Status WindowOperatorTable::Init(int,
return base::OkStatus();
}
-std::unique_ptr<SqliteTable::Cursor> WindowOperatorTable::CreateCursor() {
- return std::unique_ptr<SqliteTable::Cursor>(new Cursor(this));
+std::unique_ptr<SqliteTable::BaseCursor> WindowOperatorTable::CreateCursor() {
+ return std::unique_ptr<SqliteTable::BaseCursor>(new Cursor(this));
}
int WindowOperatorTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
return SQLITE_OK;
}
-int WindowOperatorTable::ModifyConstraints(QueryConstraints* qc) {
+base::Status WindowOperatorTable::ModifyConstraints(QueryConstraints* qc) {
// Remove ordering on timestamp if it is the only ordering as we are already
// sorted on TS. This makes span joining significantly faster.
const auto& ob = qc->order_by();
if (ob.size() == 1 && ob[0].iColumn == Column::kTs && !ob[0].desc) {
qc->mutable_order_by()->clear();
}
- return SQLITE_OK;
+ return base::OkStatus();
}
-int WindowOperatorTable::Update(int argc,
- sqlite3_value** argv,
- sqlite3_int64*) {
+base::Status WindowOperatorTable::Update(int argc,
+ sqlite3_value** argv,
+ sqlite3_int64*) {
// We only support updates to ts and dur. Disallow deletes (argc == 1) and
// inserts (argv[0] == null).
- if (argc < 2 || sqlite3_value_type(argv[0]) == SQLITE_NULL)
- return SQLITE_READONLY;
+ if (argc < 2 || sqlite3_value_type(argv[0]) == SQLITE_NULL) {
+ return base::ErrStatus(
+ "Invalid number/value of arguments when updating window table");
+ }
int64_t new_quantum = sqlite3_value_int64(argv[3]);
int64_t new_start = sqlite3_value_int64(argv[4]);
int64_t new_dur = sqlite3_value_int64(argv[5]);
if (new_dur == 0) {
- auto* err = sqlite3_mprintf("Cannot set duration of window table to zero.");
- SetErrorMessage(err);
- return SQLITE_ERROR;
+ return base::ErrStatus("Cannot set duration of window table to zero.");
}
quantum_ = new_quantum;
window_start_ = new_start;
window_dur_ = new_dur;
- return SQLITE_OK;
+ return base::OkStatus();
}
WindowOperatorTable::Cursor::Cursor(WindowOperatorTable* table)
- : SqliteTable::Cursor(table), table_(table) {}
+ : SqliteTable::BaseCursor(table), table_(table) {}
+WindowOperatorTable::Cursor::~Cursor() = default;
-int WindowOperatorTable::Cursor::Filter(const QueryConstraints& qc,
- sqlite3_value** argv,
- FilterHistory) {
+base::Status WindowOperatorTable::Cursor::Filter(const QueryConstraints& qc,
+ sqlite3_value** argv,
+ FilterHistory) {
*this = Cursor(table_);
window_start_ = table_->window_start_;
window_end_ = table_->window_start_ + table_->window_dur_;
@@ -123,10 +121,11 @@ int WindowOperatorTable::Cursor::Filter(const QueryConstraints& qc,
} else {
filter_type_ = FilterType::kReturnAll;
}
- return SQLITE_OK;
+ return base::OkStatus();
}
-int WindowOperatorTable::Cursor::Column(sqlite3_context* context, int N) {
+base::Status WindowOperatorTable::Cursor::Column(sqlite3_context* context,
+ int N) {
switch (N) {
case Column::kQuantum: {
sqlite3_result_int64(context,
@@ -163,10 +162,10 @@ int WindowOperatorTable::Cursor::Column(sqlite3_context* context, int N) {
break;
}
}
- return SQLITE_OK;
+ return base::OkStatus();
}
-int WindowOperatorTable::Cursor::Next() {
+base::Status WindowOperatorTable::Cursor::Next() {
switch (filter_type_) {
case FilterType::kReturnFirst:
current_ts_ = window_end_;
@@ -177,10 +176,10 @@ int WindowOperatorTable::Cursor::Next() {
break;
}
row_id_++;
- return SQLITE_OK;
+ return base::OkStatus();
}
-int WindowOperatorTable::Cursor::Eof() {
+bool WindowOperatorTable::Cursor::Eof() {
return current_ts_ >= window_end_;
}
diff --git a/src/trace_processor/prelude/operators/window_operator.h b/src/trace_processor/prelude/operators/window_operator.h
index d10b81b70..5f4af16fd 100644
--- a/src/trace_processor/prelude/operators/window_operator.h
+++ b/src/trace_processor/prelude/operators/window_operator.h
@@ -20,6 +20,7 @@
#include <limits>
#include <memory>
+#include "perfetto/base/status.h"
#include "src/trace_processor/sqlite/sqlite_table.h"
namespace perfetto {
@@ -27,7 +28,8 @@ namespace trace_processor {
class TraceStorage;
-class WindowOperatorTable : public SqliteTable {
+class WindowOperatorTable final
+ : public TypedSqliteTable<WindowOperatorTable, const TraceStorage*> {
public:
enum Column {
kRowId = 0,
@@ -38,17 +40,21 @@ class WindowOperatorTable : public SqliteTable {
kDuration = 5,
kQuantumTs = 6
};
- class Cursor : public SqliteTable::Cursor {
+ class Cursor final : public SqliteTable::BaseCursor {
public:
explicit Cursor(WindowOperatorTable*);
+ ~Cursor() final;
+
+ Cursor(Cursor&&) = default;
+ Cursor& operator=(Cursor&&) = default;
// Implementation of SqliteTable::Cursor.
- int Filter(const QueryConstraints& qc,
- sqlite3_value**,
- FilterHistory) override;
- int Next() override;
- int Eof() override;
- int Column(sqlite3_context*, int N) override;
+ base::Status Filter(const QueryConstraints& qc,
+ sqlite3_value**,
+ FilterHistory);
+ base::Status Next();
+ bool Eof();
+ base::Status Column(sqlite3_context*, int N);
private:
// Defines the data to be generated by the table.
@@ -72,16 +78,15 @@ class WindowOperatorTable : public SqliteTable {
WindowOperatorTable* table_ = nullptr;
};
- static void RegisterTable(sqlite3* db, const TraceStorage* storage);
-
WindowOperatorTable(sqlite3*, const TraceStorage*);
+ ~WindowOperatorTable() final;
// Table implementation.
- base::Status Init(int, const char* const*, Schema* schema) override;
- std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
- int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
- int ModifyConstraints(QueryConstraints* qc) override;
- int Update(int, sqlite3_value**, sqlite3_int64*) override;
+ base::Status Init(int, const char* const*, Schema* schema) final;
+ std::unique_ptr<SqliteTable::BaseCursor> CreateCursor() final;
+ int BestIndex(const QueryConstraints&, BestIndexInfo*) final;
+ base::Status ModifyConstraints(QueryConstraints* qc) final;
+ base::Status Update(int, sqlite3_value**, sqlite3_int64*) final;
private:
int64_t quantum_ = 0;
@@ -91,6 +96,7 @@ class WindowOperatorTable : public SqliteTable {
// uint64s.
int64_t window_dur_ = std::numeric_limits<int64_t>::max();
};
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/prelude/table_functions/BUILD.gn b/src/trace_processor/prelude/table_functions/BUILD.gn
index 4f5ced3d3..2a97bca2d 100644
--- a/src/trace_processor/prelude/table_functions/BUILD.gn
+++ b/src/trace_processor/prelude/table_functions/BUILD.gn
@@ -13,6 +13,7 @@
# limitations under the License.
import("../../../../gn/perfetto.gni")
+import("../../../../gn/perfetto_tp_tables.gni")
assert(enable_perfetto_trace_processor_sqlite)
@@ -38,12 +39,11 @@ source_set("table_functions") {
"experimental_slice_layout.h",
"flamegraph_construction_algorithms.cc",
"flamegraph_construction_algorithms.h",
- "table_function.cc",
- "table_function.h",
"view.cc",
"view.h",
]
deps = [
+ ":tables",
"../../../../gn:default_deps",
"../../../../gn:sqlite",
"../../../base",
@@ -51,12 +51,31 @@ source_set("table_functions") {
"../../db",
"../../importers/proto:full",
"../../importers/proto:minimal",
- "../../sqlite:sqlite_minimal",
+ "../../sqlite",
"../../storage",
"../../tables",
"../../types",
"../../util",
]
+ public_deps = [ ":interface" ]
+}
+
+source_set("interface") {
+ sources = [
+ "table_function.cc",
+ "table_function.h",
+ ]
+ deps = [
+ "../../../../gn:default_deps",
+ "../../../base",
+ "../../db",
+ "../../sqlite:query_constraints",
+ ]
+}
+
+perfetto_tp_tables("tables") {
+ sources = [ "tables.py" ]
+ deps = [ "../../tables:tables_python" ]
}
source_set("unittests") {
@@ -71,6 +90,7 @@ source_set("unittests") {
]
deps = [
":table_functions",
+ ":tables",
"../../../../gn:default_deps",
"../../../../gn:gtest_and_gmock",
"../../containers",
diff --git a/src/trace_processor/prelude/table_functions/ancestor.cc b/src/trace_processor/prelude/table_functions/ancestor.cc
index c1656d9e9..9089b826f 100644
--- a/src/trace_processor/prelude/table_functions/ancestor.cc
+++ b/src/trace_processor/prelude/table_functions/ancestor.cc
@@ -19,6 +19,7 @@
#include <memory>
#include <set>
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/status_macros.h"
diff --git a/src/trace_processor/prelude/table_functions/ancestor.h b/src/trace_processor/prelude/table_functions/ancestor.h
index c625f165c..755a48280 100644
--- a/src/trace_processor/prelude/table_functions/ancestor.h
+++ b/src/trace_processor/prelude/table_functions/ancestor.h
@@ -16,40 +16,14 @@
#ifndef SRC_TRACE_PROCESSOR_PRELUDE_TABLE_FUNCTIONS_ANCESTOR_H_
#define SRC_TRACE_PROCESSOR_PRELUDE_TABLE_FUNCTIONS_ANCESTOR_H_
+
#include <optional>
#include "src/trace_processor/prelude/table_functions/table_function.h"
#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/profiler_tables.h"
-#include "src/trace_processor/tables/slice_tables.h"
namespace perfetto {
namespace trace_processor {
-namespace tables {
-
-#define PERFETTO_TP_ANCESTOR_SLICE_TABLE_DEF(NAME, PARENT, C) \
- NAME(AncestorSliceTable, "ancestor_slice") \
- PARENT(PERFETTO_TP_SLICE_TABLE_DEF, C) \
- C(tables::SliceTable::Id, start_id, Column::Flag::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_ANCESTOR_SLICE_TABLE_DEF);
-
-#define PERFETTO_TP_ANCESTOR_STACK_PROFILE_CALLSITE_TABLE_DEF(NAME, PARENT, C) \
- NAME(AncestorStackProfileCallsiteTable, \
- "experimental_ancestor_stack_profile_callsite") \
- PARENT(PERFETTO_TP_STACK_PROFILE_CALLSITE_DEF, C) \
- C(tables::StackProfileCallsiteTable::Id, start_id, Column::Flag::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_ANCESTOR_STACK_PROFILE_CALLSITE_TABLE_DEF);
-
-#define PERFETTO_TP_ANCESTOR_SLICE_BY_STACK_TABLE_DEF(NAME, PARENT, C) \
- NAME(AncestorSliceByStackTable, "ancestor_slice_by_stack") \
- PARENT(PERFETTO_TP_SLICE_TABLE_DEF, C) \
- C(int64_t, start_stack_id, Column::Flag::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_ANCESTOR_SLICE_BY_STACK_TABLE_DEF);
-
-} // namespace tables
class TraceProcessorContext;
diff --git a/src/trace_processor/prelude/table_functions/ancestor_unittest.cc b/src/trace_processor/prelude/table_functions/ancestor_unittest.cc
index 08fdad4c5..afc2d3337 100644
--- a/src/trace_processor/prelude/table_functions/ancestor_unittest.cc
+++ b/src/trace_processor/prelude/table_functions/ancestor_unittest.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/prelude/table_functions/ancestor.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
diff --git a/src/trace_processor/prelude/table_functions/connected_flow.h b/src/trace_processor/prelude/table_functions/connected_flow.h
index c05e25e06..3ef3fc3e2 100644
--- a/src/trace_processor/prelude/table_functions/connected_flow.h
+++ b/src/trace_processor/prelude/table_functions/connected_flow.h
@@ -18,24 +18,14 @@
#define SRC_TRACE_PROCESSOR_PRELUDE_TABLE_FUNCTIONS_CONNECTED_FLOW_H_
#include "src/trace_processor/prelude/table_functions/table_function.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/flow_tables.h"
#include <queue>
#include <set>
namespace perfetto {
namespace trace_processor {
-namespace tables {
-
-#define PERFETTO_TP_CONNECTED_FLOW_TABLE_DEF(NAME, PARENT, C) \
- NAME(ConnectedFlowTable, "not_exposed_to_sql") \
- PARENT(PERFETTO_TP_FLOW_TABLE_DEF, C) \
- C(uint32_t, start_id, Column::Flag::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_CONNECTED_FLOW_TABLE_DEF);
-
-} // namespace tables
class TraceProcessorContext;
diff --git a/src/trace_processor/prelude/table_functions/descendant.cc b/src/trace_processor/prelude/table_functions/descendant.cc
index 75cb8c91c..382edf27a 100644
--- a/src/trace_processor/prelude/table_functions/descendant.cc
+++ b/src/trace_processor/prelude/table_functions/descendant.cc
@@ -19,6 +19,7 @@
#include <memory>
#include <set>
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/status_macros.h"
diff --git a/src/trace_processor/prelude/table_functions/descendant.h b/src/trace_processor/prelude/table_functions/descendant.h
index 8e9381187..bffd9b528 100644
--- a/src/trace_processor/prelude/table_functions/descendant.h
+++ b/src/trace_processor/prelude/table_functions/descendant.h
@@ -24,23 +24,6 @@
namespace perfetto {
namespace trace_processor {
-namespace tables {
-
-#define PERFETTO_TP_DESCENDANT_SLICE_TABLE_DEF(NAME, PARENT, C) \
- NAME(DescendantSliceTable, "descendant_slice") \
- PARENT(PERFETTO_TP_SLICE_TABLE_DEF, C) \
- C(uint32_t, start_id, Column::Flag::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_DESCENDANT_SLICE_TABLE_DEF);
-
-#define PERFETTO_TP_DESCENDANT_SLICE_BY_STACK_TABLE_DEF(NAME, PARENT, C) \
- NAME(DescendantSliceByStackTable, "descendant_slice_by_stack") \
- PARENT(PERFETTO_TP_SLICE_TABLE_DEF, C) \
- C(int64_t, start_stack_id, Column::Flag::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_DESCENDANT_SLICE_BY_STACK_TABLE_DEF);
-
-} // namespace tables
class TraceProcessorContext;
diff --git a/src/trace_processor/prelude/table_functions/descendant_unittest.cc b/src/trace_processor/prelude/table_functions/descendant_unittest.cc
index f1ef1ca31..67399d1f5 100644
--- a/src/trace_processor/prelude/table_functions/descendant_unittest.cc
+++ b/src/trace_processor/prelude/table_functions/descendant_unittest.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/prelude/table_functions/descendant.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
diff --git a/src/trace_processor/prelude/table_functions/experimental_annotated_stack.cc b/src/trace_processor/prelude/table_functions/experimental_annotated_stack.cc
index 819837658..09363f291 100644
--- a/src/trace_processor/prelude/table_functions/experimental_annotated_stack.cc
+++ b/src/trace_processor/prelude/table_functions/experimental_annotated_stack.cc
@@ -19,24 +19,15 @@
#include <optional>
#include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/profiler_tables.h"
#include "src/trace_processor/types/trace_processor_context.h"
namespace perfetto {
namespace trace_processor {
namespace tables {
-#define PERFETTO_TP_ANNOTATED_CALLSTACK_TABLE_DEF(NAME, PARENT, C) \
- NAME(ExperimentalAnnotatedCallstackTable, \
- "experimental_annotated_callstack") \
- PARENT(PERFETTO_TP_STACK_PROFILE_CALLSITE_DEF, C) \
- C(StringId, annotation) \
- C(tables::StackProfileCallsiteTable::Id, start_id, Column::Flag::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_ANNOTATED_CALLSTACK_TABLE_DEF);
-
ExperimentalAnnotatedCallstackTable::~ExperimentalAnnotatedCallstackTable() =
default;
diff --git a/src/trace_processor/prelude/table_functions/experimental_counter_dur.cc b/src/trace_processor/prelude/table_functions/experimental_counter_dur.cc
index 3513c8922..a7d98149c 100644
--- a/src/trace_processor/prelude/table_functions/experimental_counter_dur.cc
+++ b/src/trace_processor/prelude/table_functions/experimental_counter_dur.cc
@@ -16,20 +16,12 @@
#include "src/trace_processor/prelude/table_functions/experimental_counter_dur.h"
-#include "src/trace_processor/tables/counter_tables.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
namespace perfetto {
namespace trace_processor {
namespace tables {
-#define PERFETTO_TP_COUNTER_DUR_TABLE_DEF(NAME, PARENT, C) \
- NAME(ExperimentalCounterDurTable, "experimental_counter_dur") \
- PARENT(PERFETTO_TP_COUNTER_TABLE_DEF, C) \
- C(int64_t, dur) \
- C(double, delta)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_COUNTER_DUR_TABLE_DEF);
-
ExperimentalCounterDurTable::~ExperimentalCounterDurTable() = default;
} // namespace tables
diff --git a/src/trace_processor/prelude/table_functions/experimental_sched_upid.cc b/src/trace_processor/prelude/table_functions/experimental_sched_upid.cc
index 45a76ea14..ba3a0c6cf 100644
--- a/src/trace_processor/prelude/table_functions/experimental_sched_upid.cc
+++ b/src/trace_processor/prelude/table_functions/experimental_sched_upid.cc
@@ -16,17 +16,14 @@
#include "src/trace_processor/prelude/table_functions/experimental_sched_upid.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
+
namespace perfetto {
namespace trace_processor {
namespace tables {
-#define PERFETTO_TP_SCHED_UPID_TABLE_DEF(NAME, PARENT, C) \
- NAME(ExperimentalSchedUpidTable, "experimental_sched_upid") \
- PARENT(PERFETTO_TP_SCHED_SLICE_TABLE_DEF, C) \
- C(std::optional<UniquePid>, upid)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_SCHED_UPID_TABLE_DEF);
ExperimentalSchedUpidTable::~ExperimentalSchedUpidTable() = default;
+
} // namespace tables
ExperimentalSchedUpid::ExperimentalSchedUpid(
diff --git a/src/trace_processor/prelude/table_functions/experimental_slice_layout.cc b/src/trace_processor/prelude/table_functions/experimental_slice_layout.cc
index e544dbbe3..d6276dce8 100644
--- a/src/trace_processor/prelude/table_functions/experimental_slice_layout.cc
+++ b/src/trace_processor/prelude/table_functions/experimental_slice_layout.cc
@@ -20,11 +20,13 @@
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
namespace perfetto {
namespace trace_processor {
namespace tables {
+
ExperimentalSliceLayoutTable::~ExperimentalSliceLayoutTable() = default;
}
diff --git a/src/trace_processor/prelude/table_functions/experimental_slice_layout.h b/src/trace_processor/prelude/table_functions/experimental_slice_layout.h
index 19af803d6..3aa61bbd0 100644
--- a/src/trace_processor/prelude/table_functions/experimental_slice_layout.h
+++ b/src/trace_processor/prelude/table_functions/experimental_slice_layout.h
@@ -25,18 +25,6 @@
namespace perfetto {
namespace trace_processor {
-namespace tables {
-
-#define PERFETTO_TP_SLICE_LAYOUT_TABLE_DEF(NAME, PARENT, C) \
- NAME(ExperimentalSliceLayoutTable, "experimental_slice_layout") \
- PARENT(PERFETTO_TP_SLICE_TABLE_DEF, C) \
- C(uint32_t, layout_depth) \
- C(StringPool::Id, filter_track_ids, Column::kHidden)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_SLICE_LAYOUT_TABLE_DEF);
-
-} // namespace tables
-
class ExperimentalSliceLayout : public TableFunction {
public:
ExperimentalSliceLayout(StringPool* string_pool,
diff --git a/src/trace_processor/prelude/table_functions/experimental_slice_layout_unittest.cc b/src/trace_processor/prelude/table_functions/experimental_slice_layout_unittest.cc
index 43c986d5a..164dfbbe2 100644
--- a/src/trace_processor/prelude/table_functions/experimental_slice_layout_unittest.cc
+++ b/src/trace_processor/prelude/table_functions/experimental_slice_layout_unittest.cc
@@ -19,6 +19,7 @@
#include <algorithm>
#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/prelude/table_functions/tables_py.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
diff --git a/src/trace_processor/prelude/table_functions/tables.py b/src/trace_processor/prelude/table_functions/tables.py
new file mode 100644
index 000000000..4ffc5266e
--- /dev/null
+++ b/src/trace_processor/prelude/table_functions/tables.py
@@ -0,0 +1,166 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Contains tables for finding ancestor events."""
+
+from python.generators.trace_processor_table.public import Column as C
+from python.generators.trace_processor_table.public import ColumnFlag
+from python.generators.trace_processor_table.public import CppDouble
+from python.generators.trace_processor_table.public import CppInt64
+from python.generators.trace_processor_table.public import CppOptional
+from python.generators.trace_processor_table.public import CppString
+from python.generators.trace_processor_table.public import CppTableId
+from python.generators.trace_processor_table.public import CppUint32
+from python.generators.trace_processor_table.public import Table
+
+from src.trace_processor.tables.counter_tables import COUNTER_TABLE
+from src.trace_processor.tables.flow_tables import FLOW_TABLE
+from src.trace_processor.tables.metadata_tables import PROCESS_TABLE
+from src.trace_processor.tables.profiler_tables import STACK_PROFILE_CALLSITE_TABLE
+from src.trace_processor.tables.slice_tables import SLICE_TABLE
+from src.trace_processor.tables.slice_tables import SCHED_SLICE_TABLE
+
+ANCESTOR_SLICE_TABLE = Table(
+ python_module=__file__,
+ class_name="AncestorSliceTable",
+ sql_name="ancestor_slice",
+ columns=[
+ C("start_id", CppTableId(SLICE_TABLE), flags=ColumnFlag.HIDDEN),
+ ],
+ parent=SLICE_TABLE)
+
+ANCESTOR_SLICE_BY_STACK_TABLE = Table(
+ python_module=__file__,
+ class_name="AncestorSliceByStackTable",
+ sql_name="ancestor_slice_by_stack",
+ columns=[
+ C("start_stack_id", CppInt64(), flags=ColumnFlag.HIDDEN),
+ ],
+ parent=SLICE_TABLE)
+
+ANCESTOR_STACK_PROFILE_CALLSITE_TABLE = Table(
+ python_module=__file__,
+ class_name="AncestorStackProfileCallsiteTable",
+ sql_name="experimental_ancestor_stack_profile_callsite",
+ columns=[
+ C("start_id",
+ CppTableId(STACK_PROFILE_CALLSITE_TABLE),
+ flags=ColumnFlag.HIDDEN),
+ ],
+ parent=STACK_PROFILE_CALLSITE_TABLE)
+
+CONNECTED_FLOW_TABLE = Table(
+ python_module=__file__,
+ class_name="ConnectedFlowTable",
+ sql_name="not_exposed_to_sql",
+ columns=[
+ C("start_id", CppTableId(SLICE_TABLE), flags=ColumnFlag.HIDDEN),
+ ],
+ parent=FLOW_TABLE)
+
+DESCENDANT_SLICE_TABLE = Table(
+ python_module=__file__,
+ class_name="DescendantSliceTable",
+ sql_name="descendant_slice",
+ columns=[
+ C("start_id", CppTableId(SLICE_TABLE), flags=ColumnFlag.HIDDEN),
+ ],
+ parent=SLICE_TABLE)
+
+DESCENDANT_SLICE_BY_STACK_TABLE = Table(
+ python_module=__file__,
+ class_name="DescendantSliceByStackTable",
+ sql_name="descendant_slice_by_stack",
+ columns=[
+ C("start_stack_id", CppInt64(), flags=ColumnFlag.HIDDEN),
+ ],
+ parent=SLICE_TABLE)
+
+EXPERIMENTAL_ANNOTATED_CALLSTACK_TABLE = Table(
+ python_module=__file__,
+ class_name="ExperimentalAnnotatedCallstackTable",
+ sql_name="experimental_annotated_callstack",
+ columns=[
+ C("annotation", CppString()),
+ C("start_id",
+ CppTableId(STACK_PROFILE_CALLSITE_TABLE),
+ flags=ColumnFlag.HIDDEN),
+ ],
+ parent=STACK_PROFILE_CALLSITE_TABLE)
+
+EXPERIMENTAL_ANNOTATED_CALLSTACK_TABLE = Table(
+ python_module=__file__,
+ class_name="ExperimentalAnnotatedCallstackTable",
+ sql_name="experimental_annotated_callstack",
+ columns=[
+ C("annotation", CppString()),
+ C("start_id",
+ CppTableId(STACK_PROFILE_CALLSITE_TABLE),
+ flags=ColumnFlag.HIDDEN),
+ ],
+ parent=STACK_PROFILE_CALLSITE_TABLE)
+
+EXPERIMENTAL_ANNOTATED_CALLSTACK_TABLE = Table(
+ python_module=__file__,
+ class_name="ExperimentalAnnotatedCallstackTable",
+ sql_name="experimental_annotated_callstack",
+ columns=[
+ C("annotation", CppString()),
+ C("start_id",
+ CppTableId(STACK_PROFILE_CALLSITE_TABLE),
+ flags=ColumnFlag.HIDDEN),
+ ],
+ parent=STACK_PROFILE_CALLSITE_TABLE)
+
+EXPERIMENTAL_COUNTER_DUR_TABLE = Table(
+ python_module=__file__,
+ class_name="ExperimentalCounterDurTable",
+ sql_name="experimental_counter_dur",
+ columns=[
+ C("dur", CppInt64()),
+ C("delta", CppDouble()),
+ ],
+ parent=COUNTER_TABLE)
+
+EXPERIMENTAL_SCHED_UPID_TABLE = Table(
+ python_module=__file__,
+ class_name="ExperimentalSchedUpidTable",
+ sql_name="experimental_sched_upid",
+ columns=[
+ C("upid", CppOptional(CppTableId(PROCESS_TABLE))),
+ ],
+ parent=SCHED_SLICE_TABLE)
+
+EXPERIMENTAL_SLICE_LAYOUT_TABLE = Table(
+ python_module=__file__,
+ class_name="ExperimentalSliceLayoutTable",
+ sql_name="experimental_slice_layout",
+ columns=[
+ C("layout_depth", CppUint32()),
+ C("filter_track_ids", CppString(), flags=ColumnFlag.HIDDEN),
+ ],
+ parent=SLICE_TABLE)
+
+# Keep this list sorted.
+ALL_TABLES = [
+ ANCESTOR_SLICE_BY_STACK_TABLE,
+ ANCESTOR_SLICE_TABLE,
+ ANCESTOR_STACK_PROFILE_CALLSITE_TABLE,
+ CONNECTED_FLOW_TABLE,
+ DESCENDANT_SLICE_BY_STACK_TABLE,
+ DESCENDANT_SLICE_TABLE,
+ EXPERIMENTAL_ANNOTATED_CALLSTACK_TABLE,
+ EXPERIMENTAL_COUNTER_DUR_TABLE,
+ EXPERIMENTAL_SCHED_UPID_TABLE,
+ EXPERIMENTAL_SLICE_LAYOUT_TABLE,
+]
diff --git a/src/trace_processor/prelude/tables_views/BUILD.gn b/src/trace_processor/prelude/tables_views/BUILD.gn
new file mode 100644
index 000000000..110d0b950
--- /dev/null
+++ b/src/trace_processor/prelude/tables_views/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../../../gn/perfetto.gni")
+import("../../../../gn/perfetto_sql.gni")
+
+assert(enable_perfetto_trace_processor_sqlite)
+
+perfetto_amalgamated_sql_header("tables_views") {
+ deps = [ ":sources" ]
+ generated_header = "tables_views.h"
+ namespace = "prelude::tables_views"
+}
+
+perfetto_sql_source_set("sources") {
+ sources = [
+ "tables.sql",
+ "views.sql",
+ ]
+}
diff --git a/src/trace_processor/prelude/tables_views/tables.sql b/src/trace_processor/prelude/tables_views/tables.sql
new file mode 100644
index 000000000..28ea0f57a
--- /dev/null
+++ b/src/trace_processor/prelude/tables_views/tables.sql
@@ -0,0 +1,25 @@
+CREATE TABLE perfetto_tables(name STRING);
+
+CREATE TABLE trace_bounds AS
+SELECT 0 AS start_ts, 0 AS end_ts;
+
+CREATE TABLE power_profile(
+ device STRING,
+ cpu INT,
+ cluster INT,
+ freq INT,
+ power DOUBLE,
+ UNIQUE(device, cpu, cluster, freq)
+);
+
+CREATE TABLE trace_metrics(name STRING);
+
+CREATE TABLE debug_slices(
+ id BIGINT,
+ name STRING,
+ ts BIGINT,
+ dur BIGINT,
+ depth BIGINT
+);
+
+CREATE VIRTUAL TABLE window USING window();
diff --git a/src/trace_processor/prelude/tables_views/views.sql b/src/trace_processor/prelude/tables_views/views.sql
new file mode 100644
index 000000000..6962baefe
--- /dev/null
+++ b/src/trace_processor/prelude/tables_views/views.sql
@@ -0,0 +1,55 @@
+CREATE VIEW counters AS
+SELECT *
+FROM counter v
+JOIN counter_track t ON v.track_id = t.id
+ORDER BY ts;
+
+CREATE VIEW slice AS
+SELECT
+ *,
+ category AS cat,
+ id AS slice_id
+FROM internal_slice;
+
+CREATE VIEW instant AS
+SELECT ts, track_id, name, arg_set_id
+FROM slice
+WHERE dur = 0;
+
+CREATE VIEW sched AS
+SELECT
+ *,
+ ts + dur as ts_end
+FROM sched_slice;
+
+CREATE VIEW slices AS
+SELECT * FROM slice;
+
+CREATE VIEW thread AS
+SELECT
+ id as utid,
+ *
+FROM internal_thread;
+
+CREATE VIEW process AS
+SELECT
+ id as upid,
+ *
+FROM internal_process;
+
+-- This should be kept in sync with GlobalArgsTracker::AddArgSet.
+CREATE VIEW args AS
+SELECT
+ *,
+ CASE value_type
+ WHEN 'int' THEN CAST(int_value AS text)
+ WHEN 'uint' THEN CAST(int_value AS text)
+ WHEN 'string' THEN string_value
+ WHEN 'real' THEN CAST(real_value AS text)
+ WHEN 'pointer' THEN printf('0x%x', int_value)
+ WHEN 'bool' THEN (
+ CASE WHEN int_value <> 0 THEN 'true'
+ ELSE 'false' END)
+ WHEN 'json' THEN string_value
+ ELSE NULL END AS display_value
+FROM internal_args;
diff --git a/src/trace_processor/read_trace_integrationtest.cc b/src/trace_processor/read_trace_integrationtest.cc
index 439f1fa16..818eb6d08 100644
--- a/src/trace_processor/read_trace_integrationtest.cc
+++ b/src/trace_processor/read_trace_integrationtest.cc
@@ -46,7 +46,23 @@ std::vector<uint8_t> ReadAllData(const base::ScopedFstream& f) {
return raw_trace;
}
-TEST(ReadTraceIntegrationTest, CompressedTrace) {
+bool ZlibSupported() {
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+ return true;
+#else
+ return false;
+#endif
+}
+
+class ReadTraceIntegrationTest : public testing::Test {
+ void SetUp() override {
+ if (!ZlibSupported()) {
+ GTEST_SKIP() << "Gzip not enabled";
+ }
+ }
+};
+
+TEST_F(ReadTraceIntegrationTest, CompressedTrace) {
base::ScopedFstream f = OpenTestTrace("test/data/compressed.pb");
std::vector<uint8_t> raw_trace = ReadAllData(f);
@@ -68,7 +84,7 @@ TEST(ReadTraceIntegrationTest, CompressedTrace) {
ASSERT_EQ(packet_count, 2412u);
}
-TEST(ReadTraceIntegrationTest, NonProtobufShouldNotDecompress) {
+TEST_F(ReadTraceIntegrationTest, NonProtobufShouldNotDecompress) {
base::ScopedFstream f = OpenTestTrace("test/data/unsorted_trace.json");
std::vector<uint8_t> raw_trace = ReadAllData(f);
@@ -78,7 +94,7 @@ TEST(ReadTraceIntegrationTest, NonProtobufShouldNotDecompress) {
ASSERT_FALSE(status.ok());
}
-TEST(ReadTraceIntegrationTest, OuterGzipDecompressTrace) {
+TEST_F(ReadTraceIntegrationTest, OuterGzipDecompressTrace) {
base::ScopedFstream f =
OpenTestTrace("test/data/example_android_trace_30s.pb.gz");
std::vector<uint8_t> raw_compressed_trace = ReadAllData(f);
@@ -96,7 +112,7 @@ TEST(ReadTraceIntegrationTest, OuterGzipDecompressTrace) {
ASSERT_EQ(decompressed, raw_trace);
}
-TEST(ReadTraceIntegrationTest, DoubleGzipDecompressTrace) {
+TEST_F(ReadTraceIntegrationTest, DoubleGzipDecompressTrace) {
base::ScopedFstream f = OpenTestTrace("test/data/compressed.pb.gz");
std::vector<uint8_t> raw_compressed_trace = ReadAllData(f);
diff --git a/src/trace_processor/sqlite/BUILD.gn b/src/trace_processor/sqlite/BUILD.gn
index 21ed49a23..704581567 100644
--- a/src/trace_processor/sqlite/BUILD.gn
+++ b/src/trace_processor/sqlite/BUILD.gn
@@ -21,48 +21,48 @@ source_set("sqlite") {
"db_sqlite_table.cc",
"db_sqlite_table.h",
"query_cache.h",
+ "scoped_db.h",
"sql_stats_table.cc",
"sql_stats_table.h",
- "sqlite_raw_table.cc",
- "sqlite_raw_table.h",
+ "sqlite_engine.cc",
+ "sqlite_engine.h",
+ "sqlite_table.cc",
+ "sqlite_table.h",
"sqlite_utils.cc",
"sqlite_utils.h",
+ "sqlite_utils.h",
"stats_table.cc",
"stats_table.h",
]
deps = [
+ ":query_constraints",
"..:metatrace",
"../../../gn:default_deps",
"../../../gn:sqlite",
+ "../../../include/perfetto/trace_processor",
"../../../protos/perfetto/trace/ftrace:zero",
"../../base",
"../containers",
"../db",
"../importers/common",
"../importers/ftrace:ftrace_descriptors",
- "../prelude/table_functions",
+ "../prelude/functions:interface",
+ "../prelude/table_functions:interface",
"../storage",
"../types",
"../util",
"../util:profile_builder",
]
- public_deps = [ ":sqlite_minimal" ]
}
-source_set("sqlite_minimal") {
+source_set("query_constraints") {
sources = [
"query_constraints.cc",
"query_constraints.h",
- "scoped_db.h",
- "sqlite_table.cc",
- "sqlite_table.h",
- "sqlite_utils.h",
]
deps = [
- "..:metatrace",
"../../../gn:default_deps",
"../../../gn:sqlite",
- "../../../include/perfetto/trace_processor",
"../../base",
]
}
@@ -75,8 +75,8 @@ perfetto_unittest_source_set("unittests") {
"sqlite_utils_unittest.cc",
]
deps = [
+ ":query_constraints",
":sqlite",
- ":sqlite_minimal",
"../../../gn:default_deps",
"../../../gn:gtest_and_gmock",
"../../../gn:sqlite",
diff --git a/src/trace_processor/sqlite/db_sqlite_table.cc b/src/trace_processor/sqlite/db_sqlite_table.cc
index a97ec8fbe..f73c5c1c2 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.cc
+++ b/src/trace_processor/sqlite/db_sqlite_table.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/sqlite/db_sqlite_table.h"
+#include "perfetto/base/status.h"
#include "perfetto/ext/base/small_vector.h"
#include "perfetto/ext/base/string_writer.h"
#include "src/trace_processor/containers/bit_vector.h"
@@ -134,30 +135,6 @@ DbSqliteTable::DbSqliteTable(sqlite3*, Context context)
generator_(std::move(context.generator)) {}
DbSqliteTable::~DbSqliteTable() = default;
-void DbSqliteTable::RegisterTable(sqlite3* db,
- QueryCache* cache,
- const Table* table,
- const std::string& name) {
- Context context{cache, TableComputation::kStatic, table, nullptr};
- SqliteTable::Register<DbSqliteTable, Context>(db, std::move(context), name);
-}
-
-void DbSqliteTable::RegisterTable(sqlite3* db,
- QueryCache* cache,
- std::unique_ptr<TableFunction> generator) {
- // Figure out if the table needs explicit args (in the form of constraints
- // on hidden columns) passed to it in order to make the query valid.
- base::Status status = generator->ValidateConstraints(
- QueryConstraints(std::numeric_limits<uint64_t>::max()));
- bool requires_args = !status.ok();
-
- std::string table_name = generator->TableName();
- Context context{cache, TableComputation::kDynamic, nullptr,
- std::move(generator)};
- SqliteTable::Register<DbSqliteTable, Context>(
- db, std::move(context), table_name, false, requires_args);
-}
-
base::Status DbSqliteTable::Init(int, const char* const*, Schema* schema) {
switch (computation_) {
case TableComputation::kStatic:
@@ -232,9 +209,9 @@ void DbSqliteTable::BestIndex(const Table::Schema& schema,
info->sqlite_omit_order_by = true;
}
-int DbSqliteTable::ModifyConstraints(QueryConstraints* qc) {
+base::Status DbSqliteTable::ModifyConstraints(QueryConstraints* qc) {
ModifyConstraints(schema_, qc);
- return SQLITE_OK;
+ return base::OkStatus();
}
void DbSqliteTable::ModifyConstraints(const Table::Schema& schema,
@@ -392,14 +369,15 @@ DbSqliteTable::QueryCost DbSqliteTable::EstimateCost(
return QueryCost{final_cost, current_row_count};
}
-std::unique_ptr<SqliteTable::Cursor> DbSqliteTable::CreateCursor() {
+std::unique_ptr<SqliteTable::BaseCursor> DbSqliteTable::CreateCursor() {
return std::unique_ptr<Cursor>(new Cursor(this, cache_));
}
DbSqliteTable::Cursor::Cursor(DbSqliteTable* sqlite_table, QueryCache* cache)
- : SqliteTable::Cursor(sqlite_table),
+ : SqliteTable::BaseCursor(sqlite_table),
db_sqlite_table_(sqlite_table),
cache_(cache) {}
+DbSqliteTable::Cursor::~Cursor() = default;
void DbSqliteTable::Cursor::TryCacheCreateSortedTable(
const QueryConstraints& qc,
@@ -453,9 +431,9 @@ void DbSqliteTable::Cursor::TryCacheCreateSortedTable(
});
}
-int DbSqliteTable::Cursor::Filter(const QueryConstraints& qc,
- sqlite3_value** argv,
- FilterHistory history) {
+base::Status DbSqliteTable::Cursor::Filter(const QueryConstraints& qc,
+ sqlite3_value** argv,
+ FilterHistory history) {
// Clear out the iterator before filtering to ensure the destructor is run
// before the table's destructor.
iterator_ = std::nullopt;
@@ -511,10 +489,8 @@ int DbSqliteTable::Cursor::Filter(const QueryConstraints& qc,
constraints_, orders_, cols_used_bv, computed_table);
if (!status.ok()) {
- auto* sqlite_err = sqlite3_mprintf(
- "%s: %s", db_sqlite_table_->name().c_str(), status.c_message());
- db_sqlite_table_->SetErrorMessage(sqlite_err);
- return SQLITE_CONSTRAINT;
+ return base::ErrStatus("%s: %s", db_sqlite_table_->name().c_str(),
+ status.c_message());
}
PERFETTO_DCHECK(computed_table);
dynamic_table_ = std::move(computed_table);
@@ -631,25 +607,24 @@ int DbSqliteTable::Cursor::Filter(const QueryConstraints& qc,
eof_ = !*iterator_;
}
-
- return SQLITE_OK;
+ return base::OkStatus();
}
-int DbSqliteTable::Cursor::Next() {
+base::Status DbSqliteTable::Cursor::Next() {
if (mode_ == Mode::kSingleRow) {
eof_ = true;
} else {
iterator_->Next();
eof_ = !*iterator_;
}
- return SQLITE_OK;
+ return base::OkStatus();
}
-int DbSqliteTable::Cursor::Eof() {
+bool DbSqliteTable::Cursor::Eof() {
return eof_;
}
-int DbSqliteTable::Cursor::Column(sqlite3_context* ctx, int raw_col) {
+base::Status DbSqliteTable::Cursor::Column(sqlite3_context* ctx, int raw_col) {
uint32_t column = static_cast<uint32_t>(raw_col);
SqlValue value = mode_ == Mode::kSingleRow
? SourceTable()->GetColumn(column).Get(*single_row_)
@@ -663,7 +638,7 @@ int DbSqliteTable::Cursor::Column(sqlite3_context* ctx, int raw_col) {
// SQLite no longer cares about the bytes pointer.
sqlite_utils::ReportSqlValue(ctx, value, sqlite_utils::kSqliteStatic,
sqlite_utils::kSqliteStatic);
- return SQLITE_OK;
+ return base::OkStatus();
}
} // namespace trace_processor
diff --git a/src/trace_processor/sqlite/db_sqlite_table.h b/src/trace_processor/sqlite/db_sqlite_table.h
index 6a2282d0f..96a63e51a 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.h
+++ b/src/trace_processor/sqlite/db_sqlite_table.h
@@ -17,6 +17,7 @@
#ifndef SRC_TRACE_PROCESSOR_SQLITE_DB_SQLITE_TABLE_H_
#define SRC_TRACE_PROCESSOR_SQLITE_DB_SQLITE_TABLE_H_
+#include "perfetto/base/status.h"
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/db/table.h"
#include "src/trace_processor/prelude/table_functions/table_function.h"
@@ -26,32 +27,48 @@
namespace perfetto {
namespace trace_processor {
+enum class DbSqliteTableComputation {
+ // Mode when the table is static (i.e. passed in at construction
+ // time).
+ kStatic,
+
+ // Mode when table is dynamically computed at filter time.
+ kDynamic,
+};
+
+struct DbSqliteTableContext {
+ QueryCache* cache;
+ DbSqliteTableComputation computation;
+
+ // Only valid when computation == TableComputation::kStatic.
+ const Table* static_table;
+
+ // Only valid when computation == TableComputation::kDynamic.
+ std::unique_ptr<TableFunction> generator;
+};
+
// Implements the SQLite table interface for db tables.
-class DbSqliteTable : public SqliteTable {
+class DbSqliteTable final
+ : public TypedSqliteTable<DbSqliteTable, DbSqliteTableContext> {
public:
- enum class TableComputation {
- // Mode when the table is static (i.e. passed in at construction
- // time).
- kStatic,
+ using TableComputation = DbSqliteTableComputation;
+ using Context = DbSqliteTableContext;
- // Mode when table is dynamically computed at filter time.
- kDynamic,
- };
-
- class Cursor : public SqliteTable::Cursor {
+ class Cursor final : public SqliteTable::BaseCursor {
public:
Cursor(DbSqliteTable*, QueryCache*);
+ ~Cursor() final;
Cursor(Cursor&&) noexcept = default;
Cursor& operator=(Cursor&&) = default;
// Implementation of SqliteTable::Cursor.
- int Filter(const QueryConstraints& qc,
- sqlite3_value** argv,
- FilterHistory) override;
- int Next() override;
- int Eof() override;
- int Column(sqlite3_context*, int N) override;
+ base::Status Filter(const QueryConstraints& qc,
+ sqlite3_value** argv,
+ FilterHistory);
+ base::Status Next();
+ bool Eof();
+ base::Status Column(sqlite3_context*, int N);
private:
enum class Mode {
@@ -108,36 +125,15 @@ class DbSqliteTable : public SqliteTable {
double cost;
uint32_t rows;
};
- struct Context {
- QueryCache* cache;
- TableComputation computation;
-
- // Only valid when computation == TableComputation::kStatic.
- const Table* static_table;
-
- // Only valid when computation == TableComputation::kDynamic.
- std::unique_ptr<TableFunction> generator;
- };
-
- static void RegisterTable(sqlite3* db,
- QueryCache* cache,
- const Table* table,
- const std::string& name);
-
- static void RegisterTable(sqlite3* db,
- QueryCache* cache,
- std::unique_ptr<TableFunction> generator);
DbSqliteTable(sqlite3*, Context context);
- virtual ~DbSqliteTable() override;
+ virtual ~DbSqliteTable() final;
// Table implementation.
- base::Status Init(int,
- const char* const*,
- SqliteTable::Schema*) override final;
- std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
- int ModifyConstraints(QueryConstraints*) override final;
- int BestIndex(const QueryConstraints&, BestIndexInfo*) override final;
+ base::Status Init(int, const char* const*, SqliteTable::Schema*) final;
+ std::unique_ptr<SqliteTable::BaseCursor> CreateCursor() final;
+ base::Status ModifyConstraints(QueryConstraints*) final;
+ int BestIndex(const QueryConstraints&, BestIndexInfo*) final;
// These static functions are useful to allow other callers to make use
// of them.
diff --git a/src/trace_processor/sqlite/query_cache.h b/src/trace_processor/sqlite/query_cache.h
index f3b822304..1bb9d69c9 100644
--- a/src/trace_processor/sqlite/query_cache.h
+++ b/src/trace_processor/sqlite/query_cache.h
@@ -16,6 +16,7 @@
#ifndef SRC_TRACE_PROCESSOR_SQLITE_QUERY_CACHE_H_
#define SRC_TRACE_PROCESSOR_SQLITE_QUERY_CACHE_H_
+
#include <optional>
#include "src/trace_processor/db/table.h"
diff --git a/src/trace_processor/sqlite/sql_stats_table.cc b/src/trace_processor/sqlite/sql_stats_table.cc
index aafc93fc7..e6cdf87be 100644
--- a/src/trace_processor/sqlite/sql_stats_table.cc
+++ b/src/trace_processor/sqlite/sql_stats_table.cc
@@ -22,6 +22,7 @@
#include <bitset>
#include <numeric>
+#include "perfetto/base/status.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
@@ -30,10 +31,7 @@ namespace trace_processor {
SqlStatsTable::SqlStatsTable(sqlite3*, const TraceStorage* storage)
: storage_(storage) {}
-
-void SqlStatsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
- SqliteTable::Register<SqlStatsTable>(db, storage, "sqlstats");
-}
+SqlStatsTable::~SqlStatsTable() = default;
base::Status SqlStatsTable::Init(int, const char* const*, Schema* schema) {
*schema = Schema(
@@ -50,8 +48,8 @@ base::Status SqlStatsTable::Init(int, const char* const*, Schema* schema) {
return util::OkStatus();
}
-std::unique_ptr<SqliteTable::Cursor> SqlStatsTable::CreateCursor() {
- return std::unique_ptr<SqliteTable::Cursor>(new Cursor(this));
+std::unique_ptr<SqliteTable::BaseCursor> SqlStatsTable::CreateCursor() {
+ return std::unique_ptr<SqliteTable::BaseCursor>(new Cursor(this));
}
int SqlStatsTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
@@ -59,28 +57,29 @@ int SqlStatsTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
}
SqlStatsTable::Cursor::Cursor(SqlStatsTable* table)
- : SqliteTable::Cursor(table), storage_(table->storage_), table_(table) {}
-
+ : SqliteTable::BaseCursor(table),
+ storage_(table->storage_),
+ table_(table) {}
SqlStatsTable::Cursor::~Cursor() = default;
-int SqlStatsTable::Cursor::Filter(const QueryConstraints&,
- sqlite3_value**,
- FilterHistory) {
+base::Status SqlStatsTable::Cursor::Filter(const QueryConstraints&,
+ sqlite3_value**,
+ FilterHistory) {
*this = Cursor(table_);
num_rows_ = storage_->sql_stats().size();
- return SQLITE_OK;
+ return base::OkStatus();
}
-int SqlStatsTable::Cursor::Next() {
+base::Status SqlStatsTable::Cursor::Next() {
row_++;
- return SQLITE_OK;
+ return base::OkStatus();
}
-int SqlStatsTable::Cursor::Eof() {
+bool SqlStatsTable::Cursor::Eof() {
return row_ >= num_rows_;
}
-int SqlStatsTable::Cursor::Column(sqlite3_context* context, int col) {
+base::Status SqlStatsTable::Cursor::Column(sqlite3_context* context, int col) {
const TraceStorage::SqlStats& stats = storage_->sql_stats();
switch (col) {
case Column::kQuery:
@@ -97,7 +96,7 @@ int SqlStatsTable::Cursor::Column(sqlite3_context* context, int col) {
sqlite3_result_int64(context, stats.times_ended()[row_]);
break;
}
- return SQLITE_OK;
+ return base::OkStatus();
}
} // namespace trace_processor
diff --git a/src/trace_processor/sqlite/sql_stats_table.h b/src/trace_processor/sqlite/sql_stats_table.h
index df8d9f540..d78224c7f 100644
--- a/src/trace_processor/sqlite/sql_stats_table.h
+++ b/src/trace_processor/sqlite/sql_stats_table.h
@@ -20,6 +20,7 @@
#include <limits>
#include <memory>
+#include "perfetto/base/status.h"
#include "src/trace_processor/sqlite/sqlite_table.h"
namespace perfetto {
@@ -30,7 +31,8 @@ class TraceStorage;
// A virtual table that allows to introspect performances of the SQL engine
// for the kMaxLogEntries queries.
-class SqlStatsTable : public SqliteTable {
+class SqlStatsTable final
+ : public TypedSqliteTable<SqlStatsTable, const TraceStorage*> {
public:
enum Column {
kQuery = 0,
@@ -40,18 +42,18 @@ class SqlStatsTable : public SqliteTable {
};
// Implementation of the SQLite cursor interface.
- class Cursor : public SqliteTable::Cursor {
+ class Cursor final : public SqliteTable::BaseCursor {
public:
- Cursor(SqlStatsTable* storage);
- ~Cursor() override;
+ explicit Cursor(SqlStatsTable* storage);
+ ~Cursor() final;
// Implementation of SqliteTable::Cursor.
- int Filter(const QueryConstraints&,
- sqlite3_value**,
- FilterHistory) override;
- int Next() override;
- int Eof() override;
- int Column(sqlite3_context*, int N) override;
+ base::Status Filter(const QueryConstraints&,
+ sqlite3_value**,
+ FilterHistory);
+ base::Status Next();
+ bool Eof();
+ base::Status Column(sqlite3_context*, int N);
private:
Cursor(Cursor&) = delete;
@@ -67,13 +69,12 @@ class SqlStatsTable : public SqliteTable {
};
SqlStatsTable(sqlite3*, const TraceStorage* storage);
-
- static void RegisterTable(sqlite3* db, const TraceStorage* storage);
+ ~SqlStatsTable() final;
// Table implementation.
- base::Status Init(int, const char* const*, Schema*) override;
- std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
- int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
+ base::Status Init(int, const char* const*, Schema*) final;
+ std::unique_ptr<SqliteTable::BaseCursor> CreateCursor() final;
+ int BestIndex(const QueryConstraints&, BestIndexInfo*) final;
private:
const TraceStorage* const storage_;
diff --git a/src/trace_processor/sqlite/sqlite_engine.cc b/src/trace_processor/sqlite/sqlite_engine.cc
new file mode 100644
index 000000000..7ffc3ed7e
--- /dev/null
+++ b/src/trace_processor/sqlite/sqlite_engine.cc
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/sqlite/sqlite_engine.h"
+
+#include <utility>
+
+#include "perfetto/base/status.h"
+#include "src/trace_processor/sqlite/db_sqlite_table.h"
+#include "src/trace_processor/sqlite/query_cache.h"
+#include "src/trace_processor/sqlite/sqlite_table.h"
+
+// In Android and Chromium tree builds, we don't have the percentile module.
+// Just don't include it.
+#if PERFETTO_BUILDFLAG(PERFETTO_TP_PERCENTILE)
+// defined in sqlite_src/ext/misc/percentile.c
+extern "C" int sqlite3_percentile_init(sqlite3* db,
+ char** error,
+ const sqlite3_api_routines* api);
+#endif // PERFETTO_BUILDFLAG(PERFETTO_TP_PERCENTILE)
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+void EnsureSqliteInitialized() {
+ // sqlite3_initialize isn't actually thread-safe despite being documented
+ // as such; we need to make sure multiple TraceProcessorImpl instances don't
+ // call it concurrently and only gets called once per process, instead.
+ static bool init_once = [] { return sqlite3_initialize() == SQLITE_OK; }();
+ PERFETTO_CHECK(init_once);
+}
+
+void InitializeSqlite(sqlite3* db) {
+ char* error = nullptr;
+ sqlite3_exec(db, "PRAGMA temp_store=2", nullptr, nullptr, &error);
+ if (error) {
+ PERFETTO_FATAL("Error setting pragma temp_store: %s", error);
+ }
+// In Android tree builds, we don't have the percentile module.
+// Just don't include it.
+#if PERFETTO_BUILDFLAG(PERFETTO_TP_PERCENTILE)
+ sqlite3_percentile_init(db, &error, nullptr);
+ if (error) {
+ PERFETTO_ELOG("Error initializing: %s", error);
+ sqlite3_free(error);
+ }
+#endif
+}
+
+} // namespace
+
+SqliteEngine::SqliteEngine() : query_cache_(new QueryCache()) {
+ sqlite3* db = nullptr;
+ EnsureSqliteInitialized();
+ PERFETTO_CHECK(sqlite3_open(":memory:", &db) == SQLITE_OK);
+ InitializeSqlite(db);
+ db_.reset(std::move(db));
+}
+
+SqliteEngine::~SqliteEngine() {
+ // It is important to unregister any functions that have been registered with
+ // the database before destroying it. This is because functions can hold onto
+ // prepared statements, which must be finalized before database destruction.
+ for (auto it = fn_ctx_.GetIterator(); it; ++it) {
+ int ret = sqlite3_create_function_v2(db_.get(), it.key().first.c_str(),
+ it.key().second, SQLITE_UTF8, nullptr,
+ nullptr, nullptr, nullptr, nullptr);
+ PERFETTO_CHECK(ret == 0);
+ }
+ fn_ctx_.Clear();
+}
+
+void SqliteEngine::RegisterTable(const Table& table,
+ const std::string& table_name) {
+ DbSqliteTable::Context context{query_cache_.get(),
+ DbSqliteTable::TableComputation::kStatic,
+ &table, nullptr};
+ RegisterVirtualTableModule<DbSqliteTable>(table_name, std::move(context),
+ SqliteTable::kEponymousOnly, false);
+
+ // Register virtual tables into an internal 'perfetto_tables' table.
+ // This is used for iterating through all the tables during a database
+ // export.
+ char* insert_sql = sqlite3_mprintf(
+ "INSERT INTO perfetto_tables(name) VALUES('%q')", table_name.c_str());
+ char* error = nullptr;
+ sqlite3_exec(db_.get(), insert_sql, nullptr, nullptr, &error);
+ sqlite3_free(insert_sql);
+ if (error) {
+ PERFETTO_ELOG("Error adding table to perfetto_tables: %s", error);
+ sqlite3_free(error);
+ }
+}
+
+void SqliteEngine::RegisterTableFunction(std::unique_ptr<TableFunction> fn) {
+ std::string table_name = fn->TableName();
+ DbSqliteTable::Context context{query_cache_.get(),
+ DbSqliteTable::TableComputation::kDynamic,
+ nullptr, std::move(fn)};
+ RegisterVirtualTableModule<DbSqliteTable>(table_name, std::move(context),
+ SqliteTable::kEponymousOnly, false);
+}
+
+base::Status SqliteEngine::DeclareVirtualTable(const std::string& create_stmt) {
+ int res = sqlite3_declare_vtab(db_.get(), create_stmt.c_str());
+ if (res != SQLITE_OK) {
+ return base::ErrStatus("Declare vtab failed: %s",
+ sqlite3_errmsg(db_.get()));
+ }
+ return base::OkStatus();
+}
+
+base::Status SqliteEngine::SaveSqliteTable(const std::string& table_name,
+ std::unique_ptr<SqliteTable> table) {
+ auto res = saved_tables_.Insert(table_name, {});
+ if (!res.second) {
+ return base::ErrStatus("Table with name %s already is saved",
+ table_name.c_str());
+ }
+ *res.first = std::move(table);
+ return base::OkStatus();
+}
+
+base::StatusOr<std::unique_ptr<SqliteTable>> SqliteEngine::RestoreSqliteTable(
+ const std::string& table_name) {
+ auto* res = saved_tables_.Find(table_name);
+ if (!res) {
+ return base::ErrStatus("Table with name %s does not exist in saved state",
+ table_name.c_str());
+ }
+ return std::move(*res);
+}
+
+void* SqliteEngine::GetFunctionContext(const std::string& name, int argc) {
+ auto* res = fn_ctx_.Find(std::make_pair(name, argc));
+ return res ? *res : nullptr;
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/sqlite/sqlite_engine.h b/src/trace_processor/sqlite/sqlite_engine.h
new file mode 100644
index 000000000..2af8b81d4
--- /dev/null
+++ b/src/trace_processor/sqlite/sqlite_engine.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_SQLITE_SQLITE_ENGINE_H_
+#define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_ENGINE_H_
+
+#include <sqlite3.h>
+#include <stdint.h>
+#include <functional>
+#include <memory>
+#include <type_traits>
+
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/hash.h"
+#include "src/trace_processor/db/table.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
+#include "src/trace_processor/prelude/table_functions/table_function.h"
+#include "src/trace_processor/sqlite/query_cache.h"
+#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/sqlite_table.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Wrapper class around SQLite C API.
+//
+// The goal of this class is to provide a one-stop-shop mechanism to use SQLite.
+// Benefits of this include:
+// 1) It allows us to add code which intercepts registration of functions
+// and tables and keeps track of this for later lookup.
+// 2) Allows easily auditing the SQLite APIs we use making it easy to determine
+// what functionality we rely on.
+class SqliteEngine {
+ public:
+ SqliteEngine();
+ ~SqliteEngine();
+
+ // Registers a trace processor C++ table with SQLite with an SQL name of
+ // |name|.
+ void RegisterTable(const Table& table, const std::string& name);
+
+ // Registers a trace processor C++ function to be runnable from SQL.
+ //
+ // The format of the function is given by the |SqlFunction|.
+ //
+ // |db|: sqlite3 database object
+ // |name|: name of the function in SQL
+ // |argc|: number of arguments for this function. This can be -1 if
+ // the number of arguments is variable.
+ // |ctx|: context object for the function (see SqlFunction::Run
+ // above);
+ // this object *must* outlive the function so should likely be
+ // either static or scoped to the lifetime of TraceProcessor.
+ // |determistic|: whether this function has deterministic output given the
+ // same set of arguments.
+ template <typename Function = SqlFunction>
+ base::Status RegisterSqlFunction(const char* name,
+ int argc,
+ typename Function::Context* ctx,
+ bool deterministic = true);
+
+ // Registers a trace processor C++ function to be runnable from SQL.
+ //
+ // This function is the same as the above except allows a unique_ptr to be
+ // passed for the context; this allows for SQLite to manage the lifetime of
+ // this pointer instead of the essentially static requirement of the context
+ // pointer above.
+ template <typename Function>
+ base::Status RegisterSqlFunction(
+ const char* name,
+ int argc,
+ std::unique_ptr<typename Function::Context> ctx,
+ bool deterministic = true);
+
+ // Registers a trace processor C++ table function with SQLite.
+ void RegisterTableFunction(std::unique_ptr<TableFunction> fn);
+
+ // Registers a SQLite virtual table module with the given name.
+ //
+ // This API only exists for internal/legacy use: most callers should use
+ // one of the RegisterTable* APIs above.
+ template <typename Vtab, typename Context>
+ void RegisterVirtualTableModule(const std::string& module_name,
+ Context ctx,
+ SqliteTable::TableType table_type,
+ bool updatable);
+
+ // Declares a virtual table with SQLite.
+ //
+ // This API only exists for internal use. Most callers should never call this
+ // directly: instead use one of the RegisterTable* APIs above.
+ base::Status DeclareVirtualTable(const std::string& create_stmt);
+
+ // Saves a SQLite table across a pair of xDisconnect/xConnect callbacks.
+ //
+ // This API only exists for internal use. Most callers should never call this
+ // directly.
+ base::Status SaveSqliteTable(const std::string& table_name,
+ std::unique_ptr<SqliteTable>);
+
+ // Restores a SQLite table across a pair of xDisconnect/xConnect callbacks.
+ //
+ // This API only exists for internal use. Most callers should never call this
+ // directly.
+ base::StatusOr<std::unique_ptr<SqliteTable>> RestoreSqliteTable(
+ const std::string& table_name);
+
+ // Gets the context for a registered SQL function.
+ //
+ // This API only exists for internal use. Most callers should never call this
+ // directly.
+ void* GetFunctionContext(const std::string& name, int argc);
+
+ sqlite3* db() const { return db_.get(); }
+
+ private:
+ struct FnHasher {
+ size_t operator()(const std::pair<std::string, int>& x) const {
+ base::Hasher hasher;
+ hasher.Update(x.first);
+ hasher.Update(x.second);
+ return static_cast<size_t>(hasher.digest());
+ }
+ };
+
+ std::unique_ptr<QueryCache> query_cache_;
+ base::FlatHashMap<std::string, std::unique_ptr<SqliteTable>> saved_tables_;
+ base::FlatHashMap<std::pair<std::string, int>, void*, FnHasher> fn_ctx_;
+
+ ScopedDb db_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+// The rest of this file is just implementation details which we need
+// in the header file because it is templated code. We separate it out
+// like this to keep the API people actually care about easy to read.
+
+namespace perfetto {
+namespace trace_processor {
+namespace sqlite_internal {
+
+// RAII type to call Function::Cleanup when destroyed.
+template <typename Function>
+struct ScopedCleanup {
+ typename Function::Context* ctx;
+ ~ScopedCleanup() { Function::Cleanup(ctx); }
+};
+
+template <typename Function>
+void WrapSqlFunction(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
+ using Context = typename Function::Context;
+ Context* ud = static_cast<Context*>(sqlite3_user_data(ctx));
+
+ ScopedCleanup<Function> scoped_cleanup{ud};
+ SqlValue value{};
+ SqlFunction::Destructors destructors{};
+ base::Status status =
+ Function::Run(ud, static_cast<size_t>(argc), argv, value, destructors);
+ if (!status.ok()) {
+ sqlite3_result_error(ctx, status.c_message(), -1);
+ return;
+ }
+
+ if (Function::kVoidReturn) {
+ if (!value.is_null()) {
+ sqlite3_result_error(ctx, "void SQL function returned value", -1);
+ return;
+ }
+
+ // If the function doesn't want to return anything, set the "VOID"
+ // pointer type to a non-null value. Note that because of the weird
+ // way |sqlite3_value_pointer| works, we need to set some value even
+ // if we don't actually read it - just set it to a pointer to an empty
+ // string for this reason.
+ static char kVoidValue[] = "";
+ sqlite3_result_pointer(ctx, kVoidValue, "VOID", nullptr);
+ } else {
+ sqlite_utils::ReportSqlValue(ctx, value, destructors.string_destructor,
+ destructors.bytes_destructor);
+ }
+
+ status = Function::VerifyPostConditions(ud);
+ if (!status.ok()) {
+ sqlite3_result_error(ctx, status.c_message(), -1);
+ return;
+ }
+}
+
+} // namespace sqlite_internal
+
+template <typename Function>
+base::Status SqliteEngine::RegisterSqlFunction(const char* name,
+ int argc,
+ typename Function::Context* ctx,
+ bool deterministic) {
+ int flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0);
+ int ret = sqlite3_create_function_v2(
+ db_.get(), name, static_cast<int>(argc), flags, ctx,
+ sqlite_internal::WrapSqlFunction<Function>, nullptr, nullptr, nullptr);
+ if (ret != SQLITE_OK) {
+ return base::ErrStatus("Unable to register function with name %s", name);
+ }
+ *fn_ctx_.Insert(std::make_pair(name, argc), ctx).first = ctx;
+ return base::OkStatus();
+}
+
+template <typename Function>
+base::Status SqliteEngine::RegisterSqlFunction(
+ const char* name,
+ int argc,
+ std::unique_ptr<typename Function::Context> user_data,
+ bool deterministic) {
+ int flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0);
+ void* fn_ctx = user_data.get();
+ int ret = sqlite3_create_function_v2(
+ db_.get(), name, static_cast<int>(argc), flags, user_data.release(),
+ sqlite_internal::WrapSqlFunction<Function>, nullptr, nullptr,
+ [](void* ptr) { delete static_cast<typename Function::Context*>(ptr); });
+ if (ret != SQLITE_OK) {
+ return base::ErrStatus("Unable to register function with name %s", name);
+ }
+ *fn_ctx_.Insert(std::make_pair(name, argc), fn_ctx).first = fn_ctx;
+ return base::OkStatus();
+}
+
+template <typename Vtab, typename Context>
+void SqliteEngine::RegisterVirtualTableModule(const std::string& module_name,
+ Context ctx,
+ SqliteTable::TableType table_type,
+ bool updatable) {
+ static_assert(std::is_base_of_v<SqliteTable, Vtab>,
+ "Must subclass TypedSqliteTable");
+
+ auto module_arg =
+ Vtab::CreateModuleArg(this, std::move(ctx), table_type, updatable);
+ sqlite3_module* module = &module_arg->module;
+ int res = sqlite3_create_module_v2(
+ db_.get(), module_name.c_str(), module, module_arg.release(),
+ [](void* arg) { delete static_cast<typename Vtab::ModuleArg*>(arg); });
+ PERFETTO_CHECK(res == SQLITE_OK);
+}
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_ENGINE_H_
diff --git a/src/trace_processor/sqlite/sqlite_table.cc b/src/trace_processor/sqlite/sqlite_table.cc
index a0c5ce997..2ad925c87 100644
--- a/src/trace_processor/sqlite/sqlite_table.cc
+++ b/src/trace_processor/sqlite/sqlite_table.cc
@@ -20,9 +20,16 @@
#include <algorithm>
#include <cinttypes>
#include <map>
+#include <memory>
#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/string_view.h"
+#include "sqlite3.h"
+#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "src/trace_processor/tp_metatrace.h"
+#include "src/trace_processor/util/status_macros.h"
namespace perfetto {
namespace trace_processor {
@@ -153,98 +160,16 @@ bool SqliteTable::debug = false;
SqliteTable::SqliteTable() = default;
SqliteTable::~SqliteTable() = default;
-int SqliteTable::OpenInternal(sqlite3_vtab_cursor** ppCursor) {
- // Freed in xClose().
- *ppCursor = static_cast<sqlite3_vtab_cursor*>(CreateCursor().release());
- return SQLITE_OK;
-}
-
-int SqliteTable::BestIndexInternal(sqlite3_index_info* idx) {
- QueryConstraints qc(idx->colUsed);
-
- for (int i = 0; i < idx->nConstraint; i++) {
- const auto& cs = idx->aConstraint[i];
- if (!cs.usable)
- continue;
- qc.AddConstraint(cs.iColumn, cs.op, i);
- }
-
- for (int i = 0; i < idx->nOrderBy; i++) {
- int column = idx->aOrderBy[i].iColumn;
- bool desc = idx->aOrderBy[i].desc;
- qc.AddOrderBy(column, desc);
- }
-
- int ret = ModifyConstraints(&qc);
- if (ret != SQLITE_OK)
- return ret;
-
- BestIndexInfo info;
- info.estimated_cost = idx->estimatedCost;
- info.estimated_rows = idx->estimatedRows;
- info.sqlite_omit_constraint.resize(qc.constraints().size());
-
- ret = BestIndex(qc, &info);
-
- if (ret != SQLITE_OK)
- return ret;
-
- idx->orderByConsumed = qc.order_by().empty() || info.sqlite_omit_order_by;
- idx->estimatedCost = info.estimated_cost;
- idx->estimatedRows = info.estimated_rows;
-
- // First pass: mark all constraints as omitted to ensure that any pruned
- // constraints are not checked for by SQLite.
- for (int i = 0; i < idx->nConstraint; ++i) {
- auto& u = idx->aConstraintUsage[i];
- u.omit = true;
- }
-
- // Second pass: actually set the correct omit and index values for all
- // retained constraints.
- for (uint32_t i = 0; i < qc.constraints().size(); ++i) {
- auto& u = idx->aConstraintUsage[qc.constraints()[i].a_constraint_idx];
- u.omit = info.sqlite_omit_constraint[i];
- u.argvIndex = static_cast<int>(i) + 1;
- }
-
- PERFETTO_TP_TRACE(
- metatrace::Category::QUERY, "SQLITE_TABLE_BEST_INDEX",
- [&](metatrace::Record* r) {
- r->AddArg("name", name_);
- WriteQueryConstraintsToMetatrace(r, qc, schema());
- r->AddArg("order_by_consumed", std::to_string(idx->orderByConsumed));
- r->AddArg("estimated_cost", std::to_string(idx->estimatedCost));
- r->AddArg("estimated_rows",
- std::to_string(static_cast<int64_t>(idx->estimatedRows)));
- });
-
- auto out_qc_str = qc.ToNewSqlite3String();
- if (SqliteTable::debug) {
- PERFETTO_LOG(
- "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%f "
- "estimatedRows=%" PRId64,
- name_.c_str(), QcDebugStr(qc, schema()).c_str(), idx->orderByConsumed,
- idx->estimatedCost, static_cast<int64_t>(idx->estimatedRows));
- }
-
- idx->idxStr = out_qc_str.release();
- idx->needToFreeIdxStr = true;
- idx->idxNum = ++best_index_num_;
-
- return SQLITE_OK;
-}
-
-int SqliteTable::ModifyConstraints(QueryConstraints*) {
- return SQLITE_OK;
+base::Status SqliteTable::ModifyConstraints(QueryConstraints*) {
+ return base::OkStatus();
}
int SqliteTable::FindFunction(const char*, FindFunctionFn*, void**) {
return 0;
}
-int SqliteTable::Update(int, sqlite3_value**, sqlite3_int64*) {
- return SQLITE_READONLY;
+base::Status SqliteTable::Update(int, sqlite3_value**, sqlite3_int64*) {
+ return base::ErrStatus("Updating not supported");
}
bool SqliteTable::ReadConstraints(int idxNum, const char* idxStr, int argc) {
@@ -274,16 +199,20 @@ bool SqliteTable::ReadConstraints(int idxNum, const char* idxStr, int argc) {
return cache_hit;
}
-SqliteTable::Cursor::Cursor(SqliteTable* table) : table_(table) {
+////////////////////////////////////////////////////////////////////////////////
+// SqliteTable::BaseCursor implementation
+////////////////////////////////////////////////////////////////////////////////
+
+SqliteTable::BaseCursor::BaseCursor(SqliteTable* table) : table_(table) {
// This is required to prevent us from leaving this field uninitialised if
// we ever move construct the Cursor.
pVtab = table;
}
-SqliteTable::Cursor::~Cursor() = default;
+SqliteTable::BaseCursor::~BaseCursor() = default;
-int SqliteTable::Cursor::RowId(sqlite3_int64*) {
- return SQLITE_ERROR;
-}
+////////////////////////////////////////////////////////////////////////////////
+// SqliteTable::Column implementation
+////////////////////////////////////////////////////////////////////////////////
SqliteTable::Column::Column(size_t index,
std::string name,
@@ -291,6 +220,12 @@ SqliteTable::Column::Column(size_t index,
bool hidden)
: index_(index), name_(name), type_(type), hidden_(hidden) {}
+////////////////////////////////////////////////////////////////////////////////
+// SqliteTable::Schema implementation
+////////////////////////////////////////////////////////////////////////////////
+
+SqliteTable::Schema::Schema() = default;
+
SqliteTable::Schema::Schema(std::vector<Column> columns,
std::vector<size_t> primary_keys)
: columns_(std::move(columns)), primary_keys_(std::move(primary_keys)) {
@@ -302,7 +237,6 @@ SqliteTable::Schema::Schema(std::vector<Column> columns,
}
}
-SqliteTable::Schema::Schema() = default;
SqliteTable::Schema::Schema(const Schema&) = default;
SqliteTable::Schema& SqliteTable::Schema::operator=(const Schema&) = default;
@@ -334,5 +268,170 @@ std::string SqliteTable::Schema::ToCreateTableStmt() const {
return stmt;
}
+////////////////////////////////////////////////////////////////////////////////
+// TypedSqliteTableBase implementation
+////////////////////////////////////////////////////////////////////////////////
+
+TypedSqliteTableBase::~TypedSqliteTableBase() = default;
+
+base::Status TypedSqliteTableBase::DeclareAndAssignVtab(
+ std::unique_ptr<SqliteTable> table,
+ sqlite3_vtab** tab) {
+ auto create_stmt = table->schema().ToCreateTableStmt();
+ PERFETTO_DLOG("Create table statement: %s", create_stmt.c_str());
+ RETURN_IF_ERROR(table->engine_->DeclareVirtualTable(create_stmt));
+ *tab = table.release();
+ return base::OkStatus();
+}
+
+int TypedSqliteTableBase::xDestroy(sqlite3_vtab* t) {
+ delete static_cast<SqliteTable*>(t);
+ return SQLITE_OK;
+}
+
+int TypedSqliteTableBase::xDestroyFatal(sqlite3_vtab*) {
+ PERFETTO_FATAL("xDestroy should not be called");
+}
+
+int TypedSqliteTableBase::xConnectRestoreTable(sqlite3*,
+ void* arg,
+ int,
+ const char* const* argv,
+ sqlite3_vtab** tab,
+ char** pzErr) {
+ auto* xArg = static_cast<BaseModuleArg*>(arg);
+
+ // SQLite guarantees that argv[2] contains the name of the table.
+ std::string table_name = argv[2];
+ base::StatusOr<std::unique_ptr<SqliteTable>> table =
+ xArg->engine->RestoreSqliteTable(table_name);
+ if (!table.status().ok()) {
+ *pzErr = sqlite3_mprintf("%s", table.status().c_message());
+ return SQLITE_ERROR;
+ }
+ base::Status status = DeclareAndAssignVtab(std::move(table.value()), tab);
+ if (!status.ok()) {
+ *pzErr = sqlite3_mprintf("%s", status.c_message());
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+int TypedSqliteTableBase::xDisconnectSaveTable(sqlite3_vtab* t) {
+ auto* table = static_cast<TypedSqliteTableBase*>(t);
+ base::Status status = table->engine_->SaveSqliteTable(
+ table->name(), std::unique_ptr<SqliteTable>(table));
+ return table->SetStatusAndReturn(status);
+}
+
+base::Status TypedSqliteTableBase::InitInternal(SqliteEngine* engine,
+ int argc,
+ const char* const* argv) {
+ // Set the engine to allow saving into it later.
+ engine_ = engine;
+
+ // SQLite guarantees that argv[0] will be the "module" name: this is the
+ // same as |table_name| passed to the Register function.
+ module_name_ = argv[0];
+
+ // SQLite guarantees that argv[2] contains the name of the table: for
+ // non-arg taking tables, this will be the same as |table_name| but for
+ // arg-taking tables, this will be the table name as defined by the
+ // user in the CREATE VIRTUAL TABLE call.
+ name_ = argv[2];
+
+ Schema schema;
+ RETURN_IF_ERROR(Init(argc, argv, &schema));
+ schema_ = std::move(schema);
+ return base::OkStatus();
+}
+
+int TypedSqliteTableBase::xOpen(sqlite3_vtab* t,
+ sqlite3_vtab_cursor** ppCursor) {
+ auto* table = static_cast<TypedSqliteTableBase*>(t);
+ *ppCursor =
+ static_cast<sqlite3_vtab_cursor*>(table->CreateCursor().release());
+ return SQLITE_OK;
+}
+
+int TypedSqliteTableBase::xBestIndex(sqlite3_vtab* t, sqlite3_index_info* idx) {
+ auto* table = static_cast<TypedSqliteTableBase*>(t);
+
+ QueryConstraints qc(idx->colUsed);
+
+ for (int i = 0; i < idx->nConstraint; i++) {
+ const auto& cs = idx->aConstraint[i];
+ if (!cs.usable)
+ continue;
+ qc.AddConstraint(cs.iColumn, cs.op, i);
+ }
+
+ for (int i = 0; i < idx->nOrderBy; i++) {
+ int column = idx->aOrderBy[i].iColumn;
+ bool desc = idx->aOrderBy[i].desc;
+ qc.AddOrderBy(column, desc);
+ }
+
+ int ret = table->SetStatusAndReturn(table->ModifyConstraints(&qc));
+ if (ret != SQLITE_OK)
+ return ret;
+
+ BestIndexInfo info;
+ info.estimated_cost = idx->estimatedCost;
+ info.estimated_rows = idx->estimatedRows;
+ info.sqlite_omit_constraint.resize(qc.constraints().size());
+
+ ret = table->BestIndex(qc, &info);
+
+ if (ret != SQLITE_OK)
+ return ret;
+
+ idx->orderByConsumed = qc.order_by().empty() || info.sqlite_omit_order_by;
+ idx->estimatedCost = info.estimated_cost;
+ idx->estimatedRows = info.estimated_rows;
+
+ // First pass: mark all constraints as omitted to ensure that any pruned
+ // constraints are not checked for by SQLite.
+ for (int i = 0; i < idx->nConstraint; ++i) {
+ auto& u = idx->aConstraintUsage[i];
+ u.omit = true;
+ }
+
+ // Second pass: actually set the correct omit and index values for all
+ // retained constraints.
+ for (uint32_t i = 0; i < qc.constraints().size(); ++i) {
+ auto& u = idx->aConstraintUsage[qc.constraints()[i].a_constraint_idx];
+ u.omit = info.sqlite_omit_constraint[i];
+ u.argvIndex = static_cast<int>(i) + 1;
+ }
+
+ PERFETTO_TP_TRACE(
+ metatrace::Category::QUERY, "SQLITE_TABLE_BEST_INDEX",
+ [&](metatrace::Record* r) {
+ r->AddArg("name", table->name());
+ WriteQueryConstraintsToMetatrace(r, qc, table->schema());
+ r->AddArg("order_by_consumed", std::to_string(idx->orderByConsumed));
+ r->AddArg("estimated_cost", std::to_string(idx->estimatedCost));
+ r->AddArg("estimated_rows",
+ std::to_string(static_cast<int64_t>(idx->estimatedRows)));
+ });
+
+ auto out_qc_str = qc.ToNewSqlite3String();
+ if (SqliteTable::debug) {
+ PERFETTO_LOG(
+ "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%f "
+ "estimatedRows=%" PRId64,
+ table->name().c_str(), QcDebugStr(qc, table->schema()).c_str(),
+ idx->orderByConsumed, idx->estimatedCost,
+ static_cast<int64_t>(idx->estimatedRows));
+ }
+
+ idx->idxStr = out_qc_str.release();
+ idx->needToFreeIdxStr = true;
+ idx->idxNum = ++table->best_index_num_;
+
+ return SQLITE_OK;
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/sqlite/sqlite_table.h b/src/trace_processor/sqlite/sqlite_table.h
index de946692a..2d0cabcc1 100644
--- a/src/trace_processor/sqlite/sqlite_table.h
+++ b/src/trace_processor/sqlite/sqlite_table.h
@@ -27,31 +27,30 @@
#include <vector>
#include "perfetto/base/status.h"
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/db/table.h"
#include "src/trace_processor/sqlite/query_constraints.h"
namespace perfetto {
namespace trace_processor {
-class TraceStorage;
+class SqliteEngine;
+class TypedSqliteTableBase;
// Abstract base class representing a SQLite virtual table. Implements the
// common bookeeping required across all tables and allows subclasses to
// implement a friendlier API than that required by SQLite.
class SqliteTable : public sqlite3_vtab {
public:
- template <typename Context>
- using Factory =
- std::function<std::unique_ptr<SqliteTable>(sqlite3*, Context)>;
-
// Custom opcodes used by subclasses of SqliteTable.
// Stored here as we need a central repository of opcodes to prevent clashes
// between different sub-classes.
enum CustomFilterOpcode {
kSourceGeqOpCode = SQLITE_INDEX_CONSTRAINT_FUNCTION + 1,
};
-
// Describes a column of this table.
class Column {
public:
@@ -74,15 +73,9 @@ class SqliteTable : public sqlite3_vtab {
bool hidden_ = false;
};
- // When set it logs all BestIndex and Filter actions on the console.
- static bool debug;
-
- // Public for unique_ptr destructor calls.
- virtual ~SqliteTable();
-
// Abstract base class representing an SQLite Cursor. Presents a friendlier
// API for subclasses to implement.
- class Cursor : public sqlite3_vtab_cursor {
+ class BaseCursor : public sqlite3_vtab_cursor {
public:
// Enum for the history of calls to Filter.
enum class FilterHistory : uint32_t {
@@ -97,39 +90,39 @@ class SqliteTable : public sqlite3_vtab {
kSame = 1,
};
- explicit Cursor(SqliteTable* table);
- virtual ~Cursor();
+ explicit BaseCursor(SqliteTable* table);
+ virtual ~BaseCursor();
// Methods to be implemented by derived table classes.
+ // Note: these methods are intentionally not virtual for performance
+ // reasons. As these methods are not defined, there will be compile errors
+ // thrown if any of these methods are missing.
// Called to intialise the cursor with the constraints of the query.
- virtual int Filter(const QueryConstraints& qc,
- sqlite3_value**,
- FilterHistory) = 0;
+ base::Status Filter(const QueryConstraints& qc,
+ sqlite3_value**,
+ FilterHistory);
// Called to forward the cursor to the next row in the table.
- virtual int Next() = 0;
+ base::Status Next();
// Called to check if the cursor has reached eof. Column will be called iff
// this method returns true.
- virtual int Eof() = 0;
+ bool Eof();
// Used to extract the value from the column at index |N|.
- virtual int Column(sqlite3_context* context, int N) = 0;
+ base::Status Column(sqlite3_context* context, int N);
- // Optional methods to implement.
- virtual int RowId(sqlite3_int64*);
+ SqliteTable* table() const { return table_; }
protected:
- Cursor(Cursor&) = delete;
- Cursor& operator=(const Cursor&) = delete;
+ BaseCursor(BaseCursor&) = delete;
+ BaseCursor& operator=(const BaseCursor&) = delete;
- Cursor(Cursor&&) noexcept = default;
- Cursor& operator=(Cursor&&) = default;
+ BaseCursor(BaseCursor&&) noexcept = default;
+ BaseCursor& operator=(BaseCursor&&) = default;
private:
- friend class SqliteTable;
-
SqliteTable* table_ = nullptr;
};
@@ -159,6 +152,24 @@ class SqliteTable : public sqlite3_vtab {
std::vector<size_t> primary_keys_;
};
+ enum TableType {
+ // A table which automatically exists in the main schema and cannot be
+ // created with CREATE VIRTUAL TABLE.
+ // Note: the name value here matches the naming in the vtable docs of
+ // SQLite.
+ kEponymousOnly,
+
+ // A table which must be explicitly created using a CREATE VIRTUAL TABLE
+ // statement (i.e. does exist automatically).
+ kExplicitCreate,
+ };
+
+ // Public for unique_ptr destructor calls.
+ virtual ~SqliteTable();
+
+ // When set it logs all BestIndex and Filter actions on the console.
+ static bool debug;
+
protected:
// Populated by a BestIndex call to allow subclasses to tweak SQLite's
// handling of sets of constraints.
@@ -185,187 +196,39 @@ class SqliteTable : public sqlite3_vtab {
int64_t estimated_rows = 0;
};
- template <typename Context>
- struct TableDescriptor {
- SqliteTable::Factory<Context> factory;
- Context context;
- sqlite3_module module = {};
- };
-
SqliteTable();
- // Called by derived classes to register themselves with the SQLite db.
- // |read_write| specifies whether the table can also be written to.
- // |requires_args| should be true if the table requires arguments in order to
- // be instantiated.
- // Note: this function is inlined here because we use the TTable template to
- // devirtualise the function calls.
- template <typename TTable, typename Context = const TraceStorage*>
- static void Register(sqlite3* db,
- Context ctx,
- const std::string& module_name,
- bool read_write = false,
- bool requires_args = false) {
- using TCursor = typename TTable::Cursor;
-
- std::unique_ptr<TableDescriptor<Context>> desc(
- new TableDescriptor<Context>());
- desc->context = std::move(ctx);
- desc->factory = GetFactory<TTable, Context>();
- sqlite3_module* module = &desc->module;
- memset(module, 0, sizeof(*module));
-
- auto create_fn = [](sqlite3* xdb, void* arg, int argc,
- const char* const* argv, sqlite3_vtab** tab,
- char** pzErr) {
- auto* xdesc = static_cast<TableDescriptor<Context>*>(arg);
- auto table = xdesc->factory(xdb, std::move(xdesc->context));
-
- // SQLite guarantees that argv[0] will be the "module" name: this is the
- // same as |table_name| passed to the Register function.
- table->module_name_ = argv[0];
-
- // SQLite guarantees that argv[2] contains the name of the table: for
- // non-arg taking tables, this will be the same as |table_name| but for
- // arg-taking tables, this will be the table name as defined by the user
- // in the CREATE VIRTUAL TABLE call.
- table->name_ = argv[2];
-
- Schema schema;
- base::Status status = table->Init(argc, argv, &schema);
- if (!status.ok()) {
- *pzErr = sqlite3_mprintf("%s", status.c_message());
- return SQLITE_ERROR;
- }
-
- auto create_stmt = schema.ToCreateTableStmt();
- PERFETTO_DLOG("Create table statement: %s", create_stmt.c_str());
-
- int res = sqlite3_declare_vtab(xdb, create_stmt.c_str());
- if (res != SQLITE_OK)
- return res;
-
- // Freed in xDisconnect().
- table->schema_ = std::move(schema);
- *tab = table.release();
-
- return SQLITE_OK;
- };
- auto destroy_fn = [](sqlite3_vtab* t) {
- delete static_cast<TTable*>(t);
- return SQLITE_OK;
- };
-
- module->xCreate = create_fn;
- module->xConnect = create_fn;
- module->xDisconnect = destroy_fn;
- module->xDestroy = destroy_fn;
- module->xOpen = [](sqlite3_vtab* t, sqlite3_vtab_cursor** c) {
- return static_cast<TTable*>(t)->OpenInternal(c);
- };
- module->xClose = [](sqlite3_vtab_cursor* c) {
- delete static_cast<TCursor*>(c);
- return SQLITE_OK;
- };
- module->xBestIndex = [](sqlite3_vtab* t, sqlite3_index_info* i) {
- return static_cast<TTable*>(t)->BestIndexInternal(i);
- };
- module->xFilter = [](sqlite3_vtab_cursor* vc, int i, const char* s, int a,
- sqlite3_value** v) {
- auto* c = static_cast<Cursor*>(vc);
- bool is_cached = c->table_->ReadConstraints(i, s, a);
-
- auto history = is_cached ? Cursor::FilterHistory::kSame
- : Cursor::FilterHistory::kDifferent;
- return static_cast<TCursor*>(c)->Filter(c->table_->qc_cache_, v, history);
- };
- module->xNext = [](sqlite3_vtab_cursor* c) {
- return static_cast<TCursor*>(c)->Next();
- };
- module->xEof = [](sqlite3_vtab_cursor* c) {
- return static_cast<TCursor*>(c)->Eof();
- };
- module->xColumn = [](sqlite3_vtab_cursor* c, sqlite3_context* a, int b) {
- return static_cast<TCursor*>(c)->Column(a, b);
- };
- module->xRowid = [](sqlite3_vtab_cursor* c, sqlite3_int64* r) {
- return static_cast<TCursor*>(c)->RowId(r);
- };
- module->xFindFunction =
- [](sqlite3_vtab* t, int, const char* name,
- void (**fn)(sqlite3_context*, int, sqlite3_value**), void** args) {
- return static_cast<TTable*>(t)->FindFunction(name, fn, args);
- };
-
- if (read_write) {
- module->xUpdate = [](sqlite3_vtab* t, int a, sqlite3_value** v,
- sqlite3_int64* r) {
- return static_cast<TTable*>(t)->Update(a, v, r);
- };
- }
-
- int res = sqlite3_create_module_v2(
- db, module_name.c_str(), module, desc.release(),
- [](void* arg) { delete static_cast<TableDescriptor<Context>*>(arg); });
- PERFETTO_CHECK(res == SQLITE_OK);
-
- // Register virtual tables into an internal 'perfetto_tables' table. This is
- // used for iterating through all the tables during a database export. Note
- // that virtual tables requiring arguments aren't registered because they
- // can't be automatically instantiated for exporting.
- if (!requires_args) {
- char* insert_sql =
- sqlite3_mprintf("INSERT INTO perfetto_tables(name) VALUES('%q')",
- module_name.c_str());
- char* error = nullptr;
- sqlite3_exec(db, insert_sql, nullptr, nullptr, &error);
- sqlite3_free(insert_sql);
- if (error) {
- PERFETTO_ELOG("Error registering table: %s", error);
- sqlite3_free(error);
- }
- }
- }
-
// Methods to be implemented by derived table classes.
virtual base::Status Init(int argc, const char* const* argv, Schema*) = 0;
- virtual std::unique_ptr<Cursor> CreateCursor() = 0;
+ virtual std::unique_ptr<BaseCursor> CreateCursor() = 0;
virtual int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) = 0;
// Optional metods to implement.
using FindFunctionFn = void (*)(sqlite3_context*, int, sqlite3_value**);
- virtual int ModifyConstraints(QueryConstraints* qc);
+ virtual base::Status ModifyConstraints(QueryConstraints* qc);
virtual int FindFunction(const char* name, FindFunctionFn* fn, void** args);
// At registration time, the function should also pass true for |read_write|.
- virtual int Update(int, sqlite3_value**, sqlite3_int64*);
+ virtual base::Status Update(int, sqlite3_value**, sqlite3_int64*);
- void SetErrorMessage(char* error) {
- sqlite3_free(zErrMsg);
- zErrMsg = error;
- }
+ bool ReadConstraints(int idxNum, const char* idxStr, int argc);
const Schema& schema() const { return schema_; }
const std::string& module_name() const { return module_name_; }
const std::string& name() const { return name_; }
private:
- template <typename TableType, typename Context>
- static Factory<Context> GetFactory() {
- return [](sqlite3* db, Context ctx) {
- return std::unique_ptr<SqliteTable>(new TableType(db, std::move(ctx)));
- };
- }
-
- bool ReadConstraints(int idxNum, const char* idxStr, int argc);
-
- // Overriden functions from sqlite3_vtab.
- int OpenInternal(sqlite3_vtab_cursor**);
- int BestIndexInternal(sqlite3_index_info*);
+ template <typename, typename>
+ friend class TypedSqliteTable;
+ friend class TypedSqliteTableBase;
SqliteTable(const SqliteTable&) = delete;
SqliteTable& operator=(const SqliteTable&) = delete;
+ // The engine class this table is registered with. Used for restoring/saving
+ // the table.
+ SqliteEngine* engine_ = nullptr;
+
// This name of the table. For tables created using CREATE VIRTUAL TABLE, this
// will be the name of the table specified by the query. For automatically
// created tables, this will be the same as the module name passed to
@@ -384,6 +247,177 @@ class SqliteTable : public sqlite3_vtab {
int best_index_num_ = 0;
};
+class TypedSqliteTableBase : public SqliteTable {
+ protected:
+ struct BaseModuleArg {
+ sqlite3_module module;
+ SqliteEngine* engine;
+ };
+
+ ~TypedSqliteTableBase() override;
+
+ static int xDestroy(sqlite3_vtab*);
+ static int xDestroyFatal(sqlite3_vtab*);
+
+ static int xConnectRestoreTable(sqlite3* xdb,
+ void* arg,
+ int argc,
+ const char* const* argv,
+ sqlite3_vtab** tab,
+ char** pzErr);
+ static int xDisconnectSaveTable(sqlite3_vtab*);
+
+ static int xOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
+ static int xBestIndex(sqlite3_vtab*, sqlite3_index_info*);
+
+ static base::Status DeclareAndAssignVtab(std::unique_ptr<SqliteTable> table,
+ sqlite3_vtab** tab);
+
+ base::Status InitInternal(SqliteEngine* engine,
+ int argc,
+ const char* const* argv);
+
+ int SetStatusAndReturn(base::Status status) {
+ if (!status.ok()) {
+ sqlite3_free(zErrMsg);
+ zErrMsg = sqlite3_mprintf("%s", status.c_message());
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+ }
+};
+
+template <typename SubTable, typename Context>
+class TypedSqliteTable : public TypedSqliteTableBase {
+ public:
+ struct ModuleArg : BaseModuleArg {
+ Context context;
+ };
+
+ static std::unique_ptr<ModuleArg> CreateModuleArg(SqliteEngine* engine,
+ Context ctx,
+ TableType table_type,
+ bool updatable) {
+ auto arg = std::make_unique<ModuleArg>();
+ arg->module = CreateModule(table_type, updatable);
+ arg->engine = engine;
+ arg->context = std::move(ctx);
+ return arg;
+ }
+
+ private:
+ static constexpr sqlite3_module CreateModule(TableType table_type,
+ bool updatable) {
+ sqlite3_module module;
+ memset(&module, 0, sizeof(sqlite3_module));
+ switch (table_type) {
+ case TableType::kEponymousOnly:
+ // Neither xCreate nor xDestroy should ever be called for
+ // eponymous-only tables.
+ module.xCreate = nullptr;
+ module.xDestroy = &xDestroyFatal;
+
+ // xConnect and xDisconnect will automatically be called with
+ // |module_name| == |name|.
+ module.xConnect = &xCreate;
+ module.xDisconnect = &xDestroy;
+ break;
+ case TableType::kExplicitCreate:
+ // xConnect and xDestroy will be called when the table is CREATE-ed and
+ // DROP-ed respectively.
+ module.xCreate = &xCreate;
+ module.xDestroy = &xDestroy;
+
+ // xConnect and xDisconnect can be called at any time.
+ module.xConnect = &xConnectRestoreTable;
+ module.xDisconnect = &xDisconnectSaveTable;
+ break;
+ }
+ module.xOpen = &xOpen;
+ module.xClose = &xClose;
+ module.xBestIndex = &xBestIndex;
+ module.xFindFunction = &xFindFunction;
+ module.xFilter = &xFilter;
+ module.xNext = &xNext;
+ module.xEof = &xEof;
+ module.xColumn = &xColumn;
+ module.xRowid = &xRowid;
+ if (updatable) {
+ module.xUpdate = &xUpdate;
+ }
+ return module;
+ }
+
+ static int xCreate(sqlite3* xdb,
+ void* arg,
+ int argc,
+ const char* const* argv,
+ sqlite3_vtab** tab,
+ char** pzErr) {
+ auto* xdesc = static_cast<ModuleArg*>(arg);
+ std::unique_ptr<SubTable> table(
+ new SubTable(xdb, std::move(xdesc->context)));
+ base::Status status = table->InitInternal(xdesc->engine, argc, argv);
+ if (!status.ok()) {
+ *pzErr = sqlite3_mprintf("%s", status.c_message());
+ return SQLITE_ERROR;
+ }
+ status = DeclareAndAssignVtab(std::move(table), tab);
+ if (!status.ok()) {
+ *pzErr = sqlite3_mprintf("%s", status.c_message());
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+ }
+ static int xClose(sqlite3_vtab_cursor* c) {
+ delete static_cast<typename SubTable::Cursor*>(c);
+ return SQLITE_OK;
+ }
+ static int xFindFunction(sqlite3_vtab* t,
+ int,
+ const char* name,
+ void (**fn)(sqlite3_context*, int, sqlite3_value**),
+ void** args) {
+ return static_cast<SubTable*>(t)->FindFunction(name, fn, args);
+ }
+ static int xFilter(sqlite3_vtab_cursor* vc,
+ int i,
+ const char* s,
+ int a,
+ sqlite3_value** v) {
+ auto* cursor = static_cast<typename SubTable::Cursor*>(vc);
+ bool is_cached = cursor->table()->ReadConstraints(i, s, a);
+ auto history = is_cached ? BaseCursor::FilterHistory::kSame
+ : BaseCursor::FilterHistory::kDifferent;
+ auto* table = static_cast<SubTable*>(cursor->table());
+ return table->SetStatusAndReturn(
+ cursor->Filter(cursor->table()->qc_cache_, v, history));
+ }
+ static int xNext(sqlite3_vtab_cursor* c) {
+ auto* cursor = static_cast<typename SubTable::Cursor*>(c);
+ auto* table = static_cast<SubTable*>(cursor->table());
+ return table->SetStatusAndReturn(cursor->Next());
+ }
+ static int xEof(sqlite3_vtab_cursor* c) {
+ return static_cast<int>(static_cast<typename SubTable::Cursor*>(c)->Eof());
+ }
+ static int xColumn(sqlite3_vtab_cursor* c, sqlite3_context* a, int b) {
+ auto* cursor = static_cast<typename SubTable::Cursor*>(c);
+ auto* table = static_cast<SubTable*>(cursor->table());
+ return table->SetStatusAndReturn(cursor->Column(a, b));
+ }
+ static int xRowid(sqlite3_vtab_cursor*, sqlite3_int64*) {
+ return SQLITE_ERROR;
+ }
+ static int xUpdate(sqlite3_vtab* t,
+ int a,
+ sqlite3_value** v,
+ sqlite3_int64* r) {
+ auto* table = static_cast<SubTable*>(t);
+ return table->SetStatusAndReturn(table->Update(a, v, r));
+ }
+};
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/sqlite/stats_table.cc b/src/trace_processor/sqlite/stats_table.cc
index e4b7787c5..296a2f501 100644
--- a/src/trace_processor/sqlite/stats_table.cc
+++ b/src/trace_processor/sqlite/stats_table.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/sqlite/stats_table.h"
+#include "perfetto/base/status.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
namespace perfetto {
@@ -24,9 +25,7 @@ namespace trace_processor {
StatsTable::StatsTable(sqlite3*, const TraceStorage* storage)
: storage_(storage) {}
-void StatsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
- SqliteTable::Register<StatsTable>(db, storage, "stats");
-}
+StatsTable::~StatsTable() = default;
util::Status StatsTable::Init(int, const char* const*, Schema* schema) {
*schema = Schema(
@@ -46,8 +45,8 @@ util::Status StatsTable::Init(int, const char* const*, Schema* schema) {
return util::OkStatus();
}
-std::unique_ptr<SqliteTable::Cursor> StatsTable::CreateCursor() {
- return std::unique_ptr<SqliteTable::Cursor>(new Cursor(this));
+std::unique_ptr<SqliteTable::BaseCursor> StatsTable::CreateCursor() {
+ return std::unique_ptr<SqliteTable::BaseCursor>(new Cursor(this));
}
int StatsTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
@@ -55,16 +54,20 @@ int StatsTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
}
StatsTable::Cursor::Cursor(StatsTable* table)
- : SqliteTable::Cursor(table), table_(table), storage_(table->storage_) {}
+ : SqliteTable::BaseCursor(table),
+ table_(table),
+ storage_(table->storage_) {}
+
+StatsTable::Cursor::~Cursor() = default;
-int StatsTable::Cursor::Filter(const QueryConstraints&,
- sqlite3_value**,
- FilterHistory) {
+base::Status StatsTable::Cursor::Filter(const QueryConstraints&,
+ sqlite3_value**,
+ FilterHistory) {
*this = Cursor(table_);
- return SQLITE_OK;
+ return base::OkStatus();
}
-int StatsTable::Cursor::Column(sqlite3_context* ctx, int N) {
+base::Status StatsTable::Cursor::Column(sqlite3_context* ctx, int N) {
const auto kSqliteStatic = sqlite_utils::kSqliteStatic;
switch (N) {
case Column::kName:
@@ -114,16 +117,16 @@ int StatsTable::Cursor::Column(sqlite3_context* ctx, int N) {
PERFETTO_FATAL("Unknown column %d", N);
break;
}
- return SQLITE_OK;
+ return base::OkStatus();
}
-int StatsTable::Cursor::Next() {
+base::Status StatsTable::Cursor::Next() {
static_assert(stats::kTypes[0] == stats::kSingle,
"the first stats entry cannot be indexed");
const auto* cur_entry = &storage_->stats()[key_];
if (stats::kTypes[key_] == stats::kIndexed) {
if (++index_ != cur_entry->indexed_values.end()) {
- return SQLITE_OK;
+ return base::OkStatus();
}
}
while (++key_ < stats::kNumKeys) {
@@ -134,10 +137,10 @@ int StatsTable::Cursor::Next() {
break;
}
}
- return SQLITE_OK;
+ return base::OkStatus();
}
-int StatsTable::Cursor::Eof() {
+bool StatsTable::Cursor::Eof() {
return key_ >= stats::kNumKeys;
}
diff --git a/src/trace_processor/sqlite/stats_table.h b/src/trace_processor/sqlite/stats_table.h
index 3213a2a1d..2824cb62b 100644
--- a/src/trace_processor/sqlite/stats_table.h
+++ b/src/trace_processor/sqlite/stats_table.h
@@ -30,20 +30,22 @@ namespace trace_processor {
// The stats table contains diagnostic info and errors that are either:
// - Collected at trace time (e.g., ftrace buffer overruns).
// - Generated at parsing time (e.g., clock events out-of-order).
-class StatsTable : public SqliteTable {
+class StatsTable final
+ : public TypedSqliteTable<StatsTable, const TraceStorage*> {
public:
enum Column { kName = 0, kIndex, kSeverity, kSource, kValue, kDescription };
- class Cursor : public SqliteTable::Cursor {
+ class Cursor final : public SqliteTable::BaseCursor {
public:
- Cursor(StatsTable*);
+ explicit Cursor(StatsTable*);
+ ~Cursor() final;
// Implementation of SqliteTable::Cursor.
- int Filter(const QueryConstraints&,
- sqlite3_value**,
- FilterHistory) override;
- int Next() override;
- int Eof() override;
- int Column(sqlite3_context*, int N) override;
+ base::Status Filter(const QueryConstraints&,
+ sqlite3_value**,
+ FilterHistory);
+ base::Status Next();
+ bool Eof();
+ base::Status Column(sqlite3_context*, int N);
private:
Cursor(Cursor&) = delete;
@@ -58,14 +60,13 @@ class StatsTable : public SqliteTable {
TraceStorage::Stats::IndexMap::const_iterator index_{};
};
- static void RegisterTable(sqlite3* db, const TraceStorage* storage);
-
StatsTable(sqlite3*, const TraceStorage*);
+ ~StatsTable() final;
// Table implementation.
- util::Status Init(int, const char* const*, SqliteTable::Schema*) override;
- std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
- int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
+ util::Status Init(int, const char* const*, SqliteTable::Schema*) final;
+ std::unique_ptr<SqliteTable::BaseCursor> CreateCursor() final;
+ int BestIndex(const QueryConstraints&, BestIndexInfo*) final;
private:
const TraceStorage* const storage_;
diff --git a/src/trace_processor/stdlib/android/BUILD.gn b/src/trace_processor/stdlib/android/BUILD.gn
index 86bdf6d91..9596be885 100644
--- a/src/trace_processor/stdlib/android/BUILD.gn
+++ b/src/trace_processor/stdlib/android/BUILD.gn
@@ -18,9 +18,12 @@ perfetto_sql_source_set("android") {
deps = [ "startup" ]
sources = [
"battery.sql",
+ "battery_stats.sql",
"binder.sql",
"monitor_contention.sql",
+ "network_packets.sql",
"process_metadata.sql",
"slices.sql",
+ "statsd.sql",
]
}
diff --git a/src/trace_processor/stdlib/android/battery_stats.sql b/src/trace_processor/stdlib/android/battery_stats.sql
new file mode 100644
index 000000000..2507cb1fa
--- /dev/null
+++ b/src/trace_processor/stdlib/android/battery_stats.sql
@@ -0,0 +1,210 @@
+--
+-- Copyright 2023 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+SELECT IMPORT('common.timestamps');
+
+-- Converts a battery_stats counter value to human readable string.
+--
+-- @arg track STRING The counter track name (e.g. 'battery_stats.audio').
+-- @arg value LONG The counter value.
+-- @ret STRING The human-readable name for the counter value.
+SELECT CREATE_FUNCTION(
+ 'BATTERY_STATS_COUNTER_TO_STRING(track STRING, value FLOAT)',
+ 'STRING',
+ '
+ SELECT
+ CASE
+ WHEN ($track = "battery_stats.wifi_scan" OR
+ $track = "battery_stats.wifi_radio" OR
+ $track = "battery_stats.mobile_radio" OR
+ $track = "battery_stats.audio" OR
+ $track = "battery_stats.video" OR
+ $track = "battery_stats.camera" OR
+ $track = "battery_stats.power_save" OR
+ $track = "battery_stats.phone_in_call")
+ THEN
+ CASE $value
+ WHEN 0 THEN "inactive"
+ WHEN 1 THEN "active"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.wifi"
+ THEN
+ CASE $value
+ WHEN 0 THEN "off"
+ WHEN 1 THEN "on"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.phone_state"
+ THEN
+ CASE $value
+ WHEN 0 THEN "in"
+ WHEN 1 THEN "out"
+ WHEN 2 THEN "emergency"
+ WHEN 3 THEN "off"
+ ELSE "unknown"
+ END
+ WHEN ($track = "battery_stats.phone_signal_strength" OR
+ $track = "battery_stats.wifi_signal_strength")
+ THEN
+ CASE $value
+ WHEN 0 THEN "none"
+ WHEN 1 THEN "poor"
+ WHEN 2 THEN "moderate"
+ WHEN 3 THEN "good"
+ WHEN 4 THEN "great"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.wifi_suppl"
+ THEN
+ CASE $value
+ WHEN 0 THEN "invalid"
+ WHEN 1 THEN "disconn"
+ WHEN 2 THEN "disabled"
+ WHEN 3 THEN "inactive"
+ WHEN 4 THEN "scanning"
+ WHEN 5 THEN "authenticating"
+ WHEN 6 THEN "associating"
+ WHEN 7 THEN "associated"
+ WHEN 8 THEN "4-way-handshake"
+ WHEN 9 THEN "group-handshake"
+ WHEN 10 THEN "completed"
+ WHEN 11 THEN "dormant"
+ WHEN 12 THEN "uninit"
+ ELSE "unknown"
+ END
+ WHEN $track = "battery_stats.data_conn"
+ THEN
+ CASE $value
+ WHEN 0 THEN "oos"
+ WHEN 1 THEN "gprs"
+ WHEN 2 THEN "edge"
+ WHEN 3 THEN "umts"
+ WHEN 4 THEN "cdma"
+ WHEN 5 THEN "evdo_0"
+ WHEN 6 THEN "evdo_A"
+ WHEN 7 THEN "1xrtt"
+ WHEN 8 THEN "hsdpa"
+ WHEN 9 THEN "hsupa"
+ WHEN 10 THEN "hspa"
+ WHEN 11 THEN "iden"
+ WHEN 12 THEN "evdo_b"
+ WHEN 13 THEN "lte"
+ WHEN 14 THEN "ehrpd"
+ WHEN 15 THEN "hspap"
+ WHEN 16 THEN "gsm"
+ WHEN 17 THEN "td_scdma"
+ WHEN 18 THEN "iwlan"
+ WHEN 19 THEN "lte_ca"
+ WHEN 20 THEN "nr"
+ WHEN 21 THEN "emngcy"
+ WHEN 22 THEN "other"
+ ELSE "unknown"
+ END
+ ELSE CAST($value AS text)
+ END
+ '
+);
+
+
+-- View of human readable battery stats counter-based states. These are recorded
+-- by BatteryStats as a bitmap where each 'category' has a unique value at any
+-- given time.
+--
+-- @column ts Timestamp in nanoseconds.
+-- @column dur The duration the state was active.
+-- @column track_name The name of the counter track.
+-- @column value The counter value as a number.
+-- @column value_name The counter value as a human-readable string.
+CREATE VIEW android_battery_stats_state AS
+SELECT
+ ts,
+ name AS track_name,
+ CAST(value AS INT64) AS value,
+ BATTERY_STATS_COUNTER_TO_STRING(name, value) AS value_name,
+ IFNULL(LEAD(ts) OVER (PARTITION BY track_id ORDER BY ts) - ts, -1) AS dur
+FROM counter
+JOIN counter_track
+ ON counter.track_id = counter_track.id
+WHERE counter_track.name GLOB 'battery_stats.*';
+
+
+-- View of slices derived from battery_stats events. Battery stats records all
+-- events as instants, however some may indicate whether something started or
+-- stopped with a '+' or '-' prefix. Events such as jobs, top apps, foreground
+-- apps or long wakes include these details and allow drawing slices between
+-- instant events found in a trace.
+--
+-- For example, we may see an event like the following on 'battery_stats.top':
+--
+-- -top=10215:"com.google.android.apps.nexuslauncher"
+--
+-- This view will find the associated start ('+top') with the matching suffix
+-- (everything after the '=') to construct a slice. It computes the timestamp
+-- and duration from the events and extract the details as follows:
+--
+-- track_name='battery_stats.top'
+-- str_value='com.google.android.apps.nexuslauncher'
+-- int_value=10215
+--
+-- @column track_name The battery stats track name.
+-- @column ts Timestamp in nanoseconds.
+-- @column dur The duration of the event.
+-- @column str_value The string part of the event identifier.
+-- @column int_value The integer part of the event identifier.
+CREATE VIEW android_battery_stats_event_slices AS
+WITH
+ event_markers AS (
+ SELECT
+ ts,
+ track.name AS track_name,
+ str_split(slice.name, '=', 1) AS key,
+ substr(slice.name, 1, 1) = '+' AS start
+ FROM slice
+ JOIN track
+ ON slice.track_id = track.id
+ WHERE
+ track_name GLOB 'battery_stats.*'
+ AND substr(slice.name, 1, 1) IN ('+', '-')
+ ),
+ with_neighbors AS (
+ SELECT
+ *,
+ LAG(ts) OVER (PARTITION BY track_name, key ORDER BY ts) AS last_ts,
+ LEAD(ts) OVER (PARTITION BY track_name, key ORDER BY ts) AS next_ts
+ FROM event_markers
+ ),
+ -- Note: query performance depends on the ability to push down filters on
+ -- the track_name. It would be more clear below to have two queries and union
+ -- them, but doing so prevents push down through the above window functions.
+ event_spans AS (
+ SELECT
+ track_name, key,
+ IIF(start, ts, TRACE_START()) AS ts,
+ IIF(start, next_ts, ts) AS end_ts
+ FROM with_neighbors
+ -- For the majority of events, we take the `start` event and compute the dur
+ -- based on next_ts. In the off chance we get an end event with no prior
+ -- start (matched by the second half of this where), we can create an event
+ -- starting from the beginning of the trace ending at the current event.
+ WHERE (start OR last_ts IS NULL)
+ )
+SELECT
+ ts,
+ IFNULL(end_ts-ts, -1) AS dur,
+ track_name,
+ str_split(key, '"', 1) AS str_value,
+ CAST(str_split(key, ':', 0) AS INT64) AS int_value
+FROM event_spans;
diff --git a/src/trace_processor/stdlib/android/binder.sql b/src/trace_processor/stdlib/android/binder.sql
index 51a9d75f7..a31fff0f1 100644
--- a/src/trace_processor/stdlib/android/binder.sql
+++ b/src/trace_processor/stdlib/android/binder.sql
@@ -90,6 +90,7 @@ WITH
thread.name AS thread_name,
thread.utid AS utid,
thread.tid AS tid,
+ process.pid AS pid,
process.upid AS upid,
slice.ts,
slice.dur,
@@ -112,6 +113,7 @@ WITH
reply_process.name AS server_process,
reply_thread.utid AS server_utid,
reply_thread.tid AS server_tid,
+ reply_process.pid AS server_pid,
reply_process.upid AS server_upid,
aidl.name AS aidl_name
FROM binder_txn
@@ -132,6 +134,7 @@ SELECT
upid AS client_upid,
utid AS client_utid,
tid AS client_tid,
+ pid AS client_pid,
is_main_thread,
ts AS client_ts,
dur AS client_dur,
@@ -141,6 +144,7 @@ SELECT
server_upid,
server_utid,
server_tid,
+ server_pid,
server_ts,
server_dur
FROM binder_reply
diff --git a/src/trace_processor/stdlib/android/monitor_contention.sql b/src/trace_processor/stdlib/android/monitor_contention.sql
index c1de58f44..595c1fed3 100644
--- a/src/trace_processor/stdlib/android/monitor_contention.sql
+++ b/src/trace_processor/stdlib/android/monitor_contention.sql
@@ -192,10 +192,13 @@ SELECT
slice.dur,
slice.track_id,
thread.is_main_thread AS is_blocked_thread_main,
+ thread.tid AS blocked_thread_tid,
blocking_thread.is_main_thread AS is_blocking_thread_main,
+ blocking_thread.tid AS blocking_thread_tid,
binder_reply.id AS binder_reply_id,
binder_reply.ts AS binder_reply_ts,
- binder_reply_thread.tid AS binder_reply_tid
+ binder_reply_thread.tid AS binder_reply_tid,
+ process.pid
FROM slice
JOIN thread_track
ON thread_track.id = slice.track_id
diff --git a/src/trace_processor/stdlib/android/network_packets.sql b/src/trace_processor/stdlib/android/network_packets.sql
new file mode 100644
index 000000000..a88615afc
--- /dev/null
+++ b/src/trace_processor/stdlib/android/network_packets.sql
@@ -0,0 +1,52 @@
+--
+-- Copyright 2023 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+-- Android network packet events (from android.network_packets data source).
+--
+-- @column ts Timestamp in nanoseconds.
+-- @column dur Duration (non-zero only in aggregate events)
+-- @column track_name The track name (interface and direction)
+-- @column package_name Traffic package source (or uid=$X if not found)
+-- @column iface Traffic interface name (linux interface name)
+-- @column direction Traffic direction ('Transmitted' or 'Received')
+-- @column packet_count Number of packets in this event
+-- @column packet_length Number of bytes in this event (wire size)
+-- @column packet_transport Transport used for traffic in this event
+-- @column packet_tcp_flags TCP flags used by tcp frames in this event
+-- @column socket_tag The Android traffic tag of the network socket
+-- @column socket_uid The Linux user id of the network socket
+-- @column local_port The local port number (for udp or tcp only)
+-- @column remote_port The remote port number (for udp or tcp only)
+CREATE VIEW android_network_packets AS
+SELECT
+ ts,
+ dur,
+ track.name AS track_name,
+ slice.name AS package_name,
+ str_split(track.name, ' ', 0) AS iface,
+ str_split(track.name, ' ', 1) AS direction,
+ ifnull(extract_arg(arg_set_id, 'packet_count'), 1) AS packet_count,
+ extract_arg(arg_set_id, 'packet_length') AS packet_length,
+ extract_arg(arg_set_id, 'packet_transport') AS packet_transport,
+ extract_arg(arg_set_id, 'packet_tcp_flags') AS packet_tcp_flags,
+ extract_arg(arg_set_id, 'socket_tag') AS socket_tag,
+ extract_arg(arg_set_id, 'socket_uid') AS socket_uid,
+ extract_arg(arg_set_id, 'local_port') AS local_port,
+ extract_arg(arg_set_id, 'remote_port') AS remote_port
+FROM slice
+JOIN track
+ ON slice.track_id = track.id
+WHERE (track.name GLOB '* Transmitted' OR
+ track.name GLOB '* Received');
diff --git a/src/trace_processor/stdlib/android/process_metadata.sql b/src/trace_processor/stdlib/android/process_metadata.sql
index 20fb82e28..6154f00af 100644
--- a/src/trace_processor/stdlib/android/process_metadata.sql
+++ b/src/trace_processor/stdlib/android/process_metadata.sql
@@ -50,11 +50,19 @@ FROM process
LEFT JOIN internal_uid_package_count ON process.android_appid = internal_uid_package_count.uid
LEFT JOIN package_list plist
ON (
- process.android_appid = plist.uid
- AND internal_uid_package_count.uid = plist.uid
- AND (
- -- unique match
- internal_uid_package_count.cnt = 1
- -- or process name starts with the package name
- OR process.name GLOB plist.package_name || '*')
+ (
+ process.android_appid = plist.uid
+ AND internal_uid_package_count.uid = plist.uid
+ AND (
+ -- unique match
+ internal_uid_package_count.cnt = 1
+ -- or process name starts with the package name
+ OR process.name GLOB plist.package_name || '*')
+ )
+ OR
+ (
+ -- isolated processes can only be matched based on the name prefix
+ process.android_appid >= 90000 AND process.android_appid < 100000
+ AND STR_SPLIT(process.name, ':', 0) GLOB plist.package_name || '*'
+ )
);
diff --git a/src/trace_processor/stdlib/android/statsd.sql b/src/trace_processor/stdlib/android/statsd.sql
new file mode 100644
index 000000000..9ce6bf18b
--- /dev/null
+++ b/src/trace_processor/stdlib/android/statsd.sql
@@ -0,0 +1,60 @@
+--
+-- Copyright 2023 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Statsd atoms.
+--
+-- A subset of the slice table containing statsd atom instant events.
+--
+-- @column id,
+-- @column type,
+-- @column ts,
+-- @column dur,
+-- @column arg_set_id,
+-- @column thread_instruction_count,
+-- @column thread_instruction_delta,
+-- @column track_id,
+-- @column category,
+-- @column name,
+-- @column depth,
+-- @column stack_id,
+-- @column parent_stack_id,
+-- @column parent_id,
+-- @column thread_ts,
+-- @column thread_dur,
+CREATE VIEW android_statsd_atoms AS
+SELECT
+ slice.id AS id,
+ slice.type AS type,
+ slice.ts AS ts,
+ slice.dur AS dur,
+ slice.arg_set_id AS arg_set_id,
+ slice.thread_instruction_count AS thread_instruction_count,
+ slice.thread_instruction_delta AS thread_instruction_delta,
+ slice.track_id AS track_id,
+ slice.category AS category,
+ slice.name AS name,
+ slice.depth AS depth,
+ slice.stack_id AS stack_id,
+ slice.parent_stack_id AS parent_stack_id,
+ slice.parent_id AS parent_id,
+ slice.thread_ts AS thread_ts,
+ slice.thread_dur AS thread_dur
+FROM slice
+JOIN track ON slice.track_id = track.id
+WHERE
+ track.name = 'Statsd Atoms';
+
+
diff --git a/src/trace_processor/stdlib/chrome/BUILD.gn b/src/trace_processor/stdlib/chrome/BUILD.gn
index b3ea475bc..7ba85fd17 100644
--- a/src/trace_processor/stdlib/chrome/BUILD.gn
+++ b/src/trace_processor/stdlib/chrome/BUILD.gn
@@ -15,5 +15,8 @@
import("../../../../gn/perfetto_sql.gni")
perfetto_sql_source_set("chrome_sql") {
- sources = [ "cpu_powerups.sql" ]
+ sources = [
+ "chrome_scrolls.sql",
+ "cpu_powerups.sql",
+ ]
}
diff --git a/src/trace_processor/stdlib/chrome/chrome_scrolls.sql b/src/trace_processor/stdlib/chrome/chrome_scrolls.sql
new file mode 100644
index 000000000..1ad7f31ab
--- /dev/null
+++ b/src/trace_processor/stdlib/chrome/chrome_scrolls.sql
@@ -0,0 +1,68 @@
+-- Copyright 2023 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+DROP VIEW IF EXISTS chrome_scrolls;
+
+-- Defines slices for all of the individual scrolls in a trace based on the
+-- LatencyInfo-based scroll definition.
+--
+-- @column id The unique identifier of the scroll.
+-- @column ts The start timestamp of the scroll.
+-- @column dur The duration of the scroll.
+--
+-- NOTE: this view of top level scrolls is based on the LatencyInfo definition
+-- of a scroll, which differs subtly from the definition based on
+-- EventLatencies.
+-- TODO(b/278684408): add support for tracking scrolls across multiple Chrome/
+-- WebView instances. Currently gesture_scroll_id unique within an instance, but
+-- is not unique across multiple instances. Switching to an EventLatency based
+-- definition of scrolls should resolve this.
+CREATE VIEW chrome_scrolls AS
+WITH all_scrolls AS (
+ SELECT
+ name,
+ ts,
+ dur,
+ extract_arg(arg_set_id, 'chrome_latency_info.gesture_scroll_id') AS scroll_id
+ FROM slice
+ WHERE name GLOB 'InputLatency::GestureScroll*'
+ AND extract_arg(arg_set_id, 'chrome_latency_info.gesture_scroll_id') IS NOT NULL
+),
+scroll_starts AS (
+ SELECT
+ scroll_id,
+ MIN(ts) AS scroll_start_ts
+ FROM all_scrolls
+ WHERE name = 'InputLatency::GestureScrollBegin'
+ GROUP BY scroll_id
+), scroll_ends AS (
+ SELECT
+ scroll_id,
+ MIN(ts) AS scroll_end_ts
+ FROM all_scrolls
+ WHERE name = 'InputLatency::GestureScrollEnd'
+ GROUP BY scroll_id
+)
+SELECT
+ sa.scroll_id AS id,
+ MIN(ts) AS ts,
+ CAST(MAX(ts + dur) - MIN(ts) AS INT) AS dur,
+ IFNULL(ss.scroll_start_ts, -1) AS scroll_start_ts,
+ IFNULL(se.scroll_end_ts, -1) AS scroll_end_ts
+FROM all_scrolls sa
+ LEFT JOIN scroll_starts ss ON
+ sa.scroll_id = ss.scroll_id
+ LEFT JOIN scroll_ends se ON
+ sa.scroll_id = se.scroll_id
+GROUP BY sa.scroll_id; \ No newline at end of file
diff --git a/src/trace_processor/stdlib/common/BUILD.gn b/src/trace_processor/stdlib/common/BUILD.gn
index 8147bcf33..38088fc4c 100644
--- a/src/trace_processor/stdlib/common/BUILD.gn
+++ b/src/trace_processor/stdlib/common/BUILD.gn
@@ -17,6 +17,7 @@ import("../../../../gn/perfetto_sql.gni")
perfetto_sql_source_set("common") {
sources = [
"counters.sql",
+ "cpus.sql",
"metadata.sql",
"percentiles.sql",
"slices.sql",
diff --git a/src/trace_processor/stdlib/common/cpus.sql b/src/trace_processor/stdlib/common/cpus.sql
new file mode 100644
index 000000000..3caec3f3f
--- /dev/null
+++ b/src/trace_processor/stdlib/common/cpus.sql
@@ -0,0 +1,60 @@
+--
+-- Copyright 2023 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+
+CREATE TABLE internal_cpu_sizes AS
+SELECT 0 AS n, 'little' AS size
+UNION
+SELECT 1 AS n, 'big' AS size
+UNION
+SELECT 2 AS n, 'huge' AS size;
+
+CREATE TABLE internal_ranked_cpus AS
+SELECT
+ (DENSE_RANK() OVER win) - 1 AS n,
+ cpu
+FROM (
+ SELECT
+ track.cpu AS cpu,
+ MAX(counter.value) AS maxfreq
+ FROM counter
+ JOIN cpu_counter_track AS track
+ ON (counter.track_id = track.id)
+ WHERE track.name = "cpufreq"
+ GROUP BY track.cpu
+)
+WINDOW win AS (ORDER BY maxfreq);
+
+-- Guess size of CPU.
+-- On some multicore devices the cores are heterogeneous and divided
+-- into two or more 'sizes'. In a typical case a device might have 8
+-- cores of which 4 are 'little' (low power & low performance) and 4
+-- are 'big' (high power & high performance). This functions attempts
+-- to map a given CPU index onto the relevant descriptor. For
+-- homogeneous systems this returns NULL.
+--
+-- @arg cpu_index INT Index of the CPU whose size we will guess.
+-- @ret STRING A descriptive size ('little', 'big', 'huge', etc) or NULL if we have insufficient information.
+SELECT CREATE_FUNCTION(
+ 'GUESS_CPU_SIZE(cpu_index INT)',
+ 'STRING',
+ '
+ SELECT
+ IIF((SELECT COUNT(DISTINCT n) FROM internal_ranked_cpus) >= 2, size, null) as size
+ FROM internal_ranked_cpus
+ LEFT JOIN internal_cpu_sizes USING(n)
+ WHERE cpu = $cpu_index;
+ '
+);
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index 4fe2071e0..66fc9409f 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -513,6 +513,13 @@ class TraceStorage {
const tables::RawTable& raw_table() const { return raw_table_; }
tables::RawTable* mutable_raw_table() { return &raw_table_; }
+ const tables::FtraceEventTable& ftrace_event_table() const {
+ return ftrace_event_table_;
+ }
+ tables::FtraceEventTable* mutable_ftrace_event_table() {
+ return &ftrace_event_table_;
+ }
+
const tables::CpuTable& cpu_table() const { return cpu_table_; }
tables::CpuTable* mutable_cpu_table() { return &cpu_table_; }
@@ -895,11 +902,8 @@ class TraceStorage {
SqlStats sql_stats_;
- // Raw events are every ftrace event in the trace. The raw event includes
- // the timestamp and the pid. The args for the raw event will be in the
- // args table. This table can be used to generate a text version of the
- // trace.
tables::RawTable raw_table_{&string_pool_};
+ tables::FtraceEventTable ftrace_event_table_{&string_pool_, &raw_table_};
tables::CpuTable cpu_table_{&string_pool_};
diff --git a/src/trace_processor/tables/BUILD.gn b/src/trace_processor/tables/BUILD.gn
index 83145a487..9ec397ffc 100644
--- a/src/trace_processor/tables/BUILD.gn
+++ b/src/trace_processor/tables/BUILD.gn
@@ -32,12 +32,7 @@ perfetto_tp_tables("tables_python") {
source_set("tables") {
sources = [
- "counter_tables.h",
- "flow_tables.h",
- "macros.h",
"macros_internal.h",
- "profiler_tables.h",
- "slice_tables.h",
"table_destructors.cc",
]
deps = [
@@ -54,10 +49,7 @@ perfetto_tp_tables("py_tables_unittest") {
source_set("unittests") {
testonly = true
- sources = [
- "macros_unittest.cc",
- "py_tables_unittest.cc",
- ]
+ sources = [ "py_tables_unittest.cc" ]
deps = [
":py_tables_unittest",
":tables",
@@ -71,10 +63,13 @@ if (enable_perfetto_benchmarks) {
source_set("benchmarks") {
testonly = true
deps = [
- ":tables",
+ ":py_tables_benchmark",
"../../../gn:benchmark",
"../../../gn:default_deps",
]
- sources = [ "macros_benchmark.cc" ]
+ sources = [ "py_tables_benchmark.cc" ]
+ }
+ perfetto_tp_tables("py_tables_benchmark") {
+ sources = [ "py_tables_benchmark.py" ]
}
}
diff --git a/src/trace_processor/tables/android_tables.py b/src/trace_processor/tables/android_tables.py
index b77afcbc8..03dff073b 100644
--- a/src/trace_processor/tables/android_tables.py
+++ b/src/trace_processor/tables/android_tables.py
@@ -28,6 +28,7 @@ from python.generators.trace_processor_table.public import CppUint32
from src.trace_processor.tables.metadata_tables import THREAD_TABLE
ANDROID_LOG_TABLE = Table(
+ python_module=__file__,
class_name="AndroidLogTable",
sql_name="android_logs",
columns=[
@@ -54,6 +55,7 @@ ANDROID_LOG_TABLE = Table(
}))
ANDROID_GAME_INTERVENTION_LIST_TABLE = Table(
+ python_module=__file__,
class_name='AndroidGameInterventionListTable',
sql_name='android_game_intervention_list',
columns=[
@@ -126,6 +128,7 @@ This is generated by the game_mode_intervention data-source.
}))
ANDROID_DUMPSTATE_TABLE = Table(
+ python_module=__file__,
class_name='AndroidDumpstateTable',
sql_name='android_dumpstate',
columns=[
diff --git a/src/trace_processor/tables/counter_tables.h b/src/trace_processor/tables/counter_tables.h
deleted file mode 100644
index 69668b2bb..000000000
--- a/src/trace_processor/tables/counter_tables.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_TABLES_COUNTER_TABLES_H_
-#define SRC_TRACE_PROCESSOR_TABLES_COUNTER_TABLES_H_
-
-#include "src/trace_processor/tables/macros.h"
-#include "src/trace_processor/tables/track_tables_py.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace tables {
-
-// @tablegroup Events
-// @param arg_set_id {@joinable args.arg_set_id}
-#define PERFETTO_TP_COUNTER_TABLE_DEF(NAME, PARENT, C) \
- NAME(CounterTable, "counter") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(int64_t, ts, Column::Flag::kSorted) \
- C(CounterTrackTable::Id, track_id) \
- C(double, value) \
- C(std::optional<uint32_t>, arg_set_id)
-
-} // namespace tables
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_TABLES_COUNTER_TABLES_H_
diff --git a/src/trace_processor/tables/counter_tables.py b/src/trace_processor/tables/counter_tables.py
index 1dd649539..e88245210 100644
--- a/src/trace_processor/tables/counter_tables.py
+++ b/src/trace_processor/tables/counter_tables.py
@@ -26,6 +26,7 @@ from python.generators.trace_processor_table.public import CppUint32
from src.trace_processor.tables.track_tables import COUNTER_TRACK_TABLE
COUNTER_TABLE = Table(
+ python_module=__file__,
class_name='CounterTable',
sql_name='counter',
columns=[
diff --git a/src/trace_processor/tables/flow_tables.h b/src/trace_processor/tables/flow_tables.h
deleted file mode 100644
index a00ee8921..000000000
--- a/src/trace_processor/tables/flow_tables.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_TABLES_FLOW_TABLES_H_
-#define SRC_TRACE_PROCESSOR_TABLES_FLOW_TABLES_H_
-
-#include "src/trace_processor/tables/macros.h"
-#include "src/trace_processor/tables/slice_tables.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace tables {
-
-// @param arg_set_id {@joinable args.arg_set_id}
-#define PERFETTO_TP_FLOW_TABLE_DEF(NAME, PARENT, C) \
- NAME(FlowTable, "flow") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(SliceTable::Id, slice_out) \
- C(SliceTable::Id, slice_in) \
- C(uint32_t, arg_set_id)
-
-} // namespace tables
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_TABLES_FLOW_TABLES_H_
diff --git a/src/trace_processor/tables/flow_tables.py b/src/trace_processor/tables/flow_tables.py
index 0491a3111..df0ae4c82 100644
--- a/src/trace_processor/tables/flow_tables.py
+++ b/src/trace_processor/tables/flow_tables.py
@@ -22,6 +22,7 @@ from python.generators.trace_processor_table.public import CppUint32
from src.trace_processor.tables.slice_tables import SLICE_TABLE
FLOW_TABLE = Table(
+ python_module=__file__,
class_name='FlowTable',
sql_name='flow',
columns=[
diff --git a/src/trace_processor/tables/macros.h b/src/trace_processor/tables/macros.h
deleted file mode 100644
index a085066ab..000000000
--- a/src/trace_processor/tables/macros.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_TABLES_MACROS_H_
-#define SRC_TRACE_PROCESSOR_TABLES_MACROS_H_
-
-#include "src/trace_processor/tables/macros_internal.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// Usage of the below macros
-// These macros have two different invocation patterns depending on whether you
-// are defining a root table or a derived table (see below for definitions and
-// examples). If you're not sure which one you need, you probably want a derived
-// table.
-//
-// Root tables
-// Root tables act as the ultimate parent of a heirarcy of tables. All rows of
-// child tables will be some subset of rows in the parent. Real world examples
-// of root tables include EventTable and TrackTable.
-//
-// All root tables implicitly contain an 'id' column which contains the row
-// index for each row in the table.
-//
-// Suppose we want to define EventTable with columns 'ts' and 'arg_set_id'.
-//
-// Then we would invoke the macro as follows:
-// #define PERFETTO_TP_EVENT_TABLE_DEF(NAME, PARENT, C)
-// NAME(EventTable, "event")
-// PERFETTO_TP_ROOT_TABLE(PARENT, C)
-// C(int64_t, ts, Column::kSorted)
-// C(uint32_t, arg_set_id)
-// PERFETTO_TP_TABLE(PERFETTO_TP_EVENT_TABLE_DEF);
-//
-// Note the call to PERFETTO_TP_ROOT_TABLE; this macro (defined below) should
-// be called by root tables passing the PARENT and C and allows for correct type
-// checking of root tables.
-//
-// Derived tables
-// Suppose we want to derive a table called SliceTable which inherits all
-// columns from EventTable (with EventTable's definition macro being
-// PERFETTO_TP_EVENT_TABLE_DEF) and columns 'dur' and 'depth'.
-//
-// Then, we would invoke the macro as follows:
-// #define PERFETTO_TP_SLICE_TABLE_DEF(NAME, PARENT, C)
-// NAME(SliceTable, "slice")
-// PARENT(PERFETTO_TP_EVENT_TABLE_DEF, C)
-// C(int64_t, dur)
-// C(uint8_t, depth)
-// PERFETTO_TP_TABLE(PERFETTO_TP_SLICE_TABLE_DEF);
-
-// Macro definition using when defining a new root table.
-//
-// This macro should be called by passing PARENT and C in root tables; this
-// allows for correct type-checking of columns.
-//
-// See the top of the file for how this should be used.
-#define PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C)
-
-// The macro used to define storage backed tables.
-// See the top of the file for how this should be used.
-//
-// This macro takes one argument: the full definition of the table; the
-// definition is a function macro taking three arguments:
-// 1. NAME, a function macro taking two argument: the name of the new class
-// being defined and the name of the table when exposed to SQLite.
-// 2. PARENT, a function macro taking two arguments: a) the definition of
-// the parent table if this table
-// is a root table b) C, the third parameter of the macro definition (see
-// below). For root tables, PARENT and C are passsed to
-// PERFETTO_TP_ROOT_TABLE instead of PARENT called directly.
-// 3. C, a function macro taking two or three parameters:
-// a) the type of a column
-// b) the name of a column
-// c) (optional) the flags of the column (see Column::Flag
-// for details).
-// This macro should be invoked as many times as there are columns in the
-// table with the information about them.
-#define PERFETTO_TP_TABLE(DEF) \
- PERFETTO_TP_TABLE_INTERNAL( \
- PERFETTO_TP_TABLE_NAME(DEF), PERFETTO_TP_TABLE_CLASS(DEF), \
- PERFETTO_TP_TABLE_CLASS(PERFETTO_TP_PARENT_DEF(DEF)), DEF)
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_TABLES_MACROS_H_
diff --git a/src/trace_processor/tables/macros_internal.h b/src/trace_processor/tables/macros_internal.h
index 059e7b7ad..b2f1f1526 100644
--- a/src/trace_processor/tables/macros_internal.h
+++ b/src/trace_processor/tables/macros_internal.h
@@ -57,30 +57,6 @@ class RootParentTable : public Table {
explicit RootParentTable(std::nullptr_t);
};
-// IdHelper is used to figure out the Id type for a table.
-//
-// We do this using templates with the following algorithm:
-// 1. If the parent class is anything but RootParentTable, the Id of the
-// table is the same as the Id of the parent.
-// 2. If the parent class is RootParentTable (i.e. the table is a root
-// table), then the Id is the one defined in the table itself.
-// The net result of this is that all tables in the hierarchy get the
-// same type of Id - the one defined in the root table of that hierarchy.
-//
-// Reasoning: We do this because using uint32_t is very overloaded and
-// having a wrapper type for ids is very helpful to avoid confusion with
-// row indices (especially because ids and row indices often appear in
-// similar places in the codebase - that is at insertion in parsers and
-// in trackers).
-template <typename ParentClass, typename Class>
-struct IdHelper {
- using Id = typename ParentClass::Id;
-};
-template <typename Class>
-struct IdHelper<RootParentTable, Class> {
- using Id = typename Class::DefinedId;
-};
-
// The parent class for all macro generated tables.
// This class is used to extract common code from the macro tables to reduce
// code size.
@@ -284,665 +260,6 @@ class AbstractConstRowReference {
};
} // namespace macros_internal
-
-// Ignore GCC warning about a missing argument for a variadic macro parameter.
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC system_header
-#endif
-
-// Basic helper macros.
-#define PERFETTO_TP_NOOP(...)
-
-// Gets the class name from a table definition.
-#define PERFETTO_TP_EXTRACT_TABLE_CLASS(class_name, ...) class_name
-#define PERFETTO_TP_TABLE_CLASS(DEF) \
- DEF(PERFETTO_TP_EXTRACT_TABLE_CLASS, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP)
-
-// Gets the table name from the table definition.
-#define PERFETTO_TP_EXTRACT_TABLE_NAME(_, table_name) table_name
-#define PERFETTO_TP_TABLE_NAME(DEF) \
- DEF(PERFETTO_TP_EXTRACT_TABLE_NAME, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP)
-
-// Gets the parent definition from a table definition.
-#define PERFETTO_TP_EXTRACT_PARENT_DEF(PARENT_DEF, _) PARENT_DEF
-#define PERFETTO_TP_PARENT_DEF(DEF) \
- DEF(PERFETTO_TP_NOOP, PERFETTO_TP_EXTRACT_PARENT_DEF, PERFETTO_TP_NOOP)
-
-// Invokes FN on each column in the definition of the table. We define a
-// recursive macro as we need to walk up the hierarchy until we hit the root.
-// Currently, we hardcode 5 levels but this can be increased as necessary.
-#define PERFETTO_TP_ALL_COLUMNS_0(DEF, arg) \
- static_assert(false, "Macro recursion depth exceeded");
-#define PERFETTO_TP_ALL_COLUMNS_1(DEF, arg) \
- DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_0, arg)
-#define PERFETTO_TP_ALL_COLUMNS_2(DEF, arg) \
- DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_1, arg)
-#define PERFETTO_TP_ALL_COLUMNS_3(DEF, arg) \
- DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_2, arg)
-#define PERFETTO_TP_ALL_COLUMNS_4(DEF, arg) \
- DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_3, arg)
-#define PERFETTO_TP_ALL_COLUMNS(DEF, arg) \
- DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_4, arg)
-
-// Invokes FN on each column in the table definition.
-#define PERFETTO_TP_TABLE_COLUMNS(DEF, FN) \
- DEF(PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, FN)
-
-// Invokes FN on each column in every ancestor of the table.
-#define PERFETTO_TP_PARENT_COLUMNS(DEF, FN) \
- PERFETTO_TP_ALL_COLUMNS(PERFETTO_TP_PARENT_DEF(DEF), FN)
-
-// Basic macros for extracting column info from a schema.
-#define PERFETTO_TP_NAME_COMMA(type, name, ...) name,
-#define PERFETTO_TP_TYPE_NAME_COMMA(type, name, ...) type name,
-
-// Constructor parameters of Table::Row.
-// We name this name_c to avoid a clash with the field names of
-// Table::Row.
-#define PERFETTO_TP_ROW_CONSTRUCTOR(type, name, ...) type name##_c = {},
-
-// Constructor parameters for parent of Row.
-#define PERFETTO_TP_PARENT_ROW_CONSTRUCTOR(type, name, ...) name##_c,
-
-// Initializes the members of Table::Row.
-#define PERFETTO_TP_ROW_INITIALIZER(type, name, ...) name = name##_c;
-
-// Defines the variable in Table::Row.
-#define PERFETTO_TP_ROW_DEFINITION(type, name, ...) type name = {};
-
-// Used to generate an equality implementation on Table::Row.
-#define PERFETTO_TP_ROW_EQUALS(type, name, ...) \
- TypedColumn<type>::Equals(other.name, name)&&
-
-// Defines the parent row field in Insert.
-#define PERFETTO_TP_PARENT_ROW_INSERT(type, name, ...) row.name,
-
-// Defines the member variable in the Table.
-#define PERFETTO_TP_TABLE_MEMBER(type, name, ...) \
- ColumnStorage<TypedColumn<type>::stored_type> name##_;
-
-#define PERFETTO_TP_COLUMN_FLAG_HAS_FLAG_COL(type, name, flags) \
- static constexpr uint32_t name##_flags() { \
- return static_cast<uint32_t>(flags) | TypedColumn<type>::default_flags(); \
- }
-
-#define PERFETTO_TP_COLUMN_FLAG_NO_FLAG_COL(type, name) \
- static constexpr uint32_t name##_flags() { \
- return TypedColumn<type>::default_flags(); \
- }
-
-#define PERFETTO_TP_PARENT_COLUMN_FLAG_HAS_FLAG_COL(type, name, flags) \
- static constexpr uint32_t name##_flags() { \
- return (static_cast<uint32_t>(flags) | \
- TypedColumn<type>::default_flags()) & \
- ~Column::kNoCrossTableInheritFlags; \
- }
-
-#define PERFETTO_TP_PARENT_COLUMN_FLAG_NO_FLAG_COL(type, name) \
- static constexpr uint32_t name##_flags() { \
- return TypedColumn<type>::default_flags() & \
- ~Column::kNoCrossTableInheritFlags; \
- }
-
-#define PERFETTO_TP_COLUMN_FLAG_CHOOSER(type, name, maybe_flags, fn, ...) fn
-
-// MSVC has slightly different rules about __VA_ARGS__ expansion. This makes it
-// behave similarly to GCC/Clang.
-// See https://stackoverflow.com/q/5134523/14028266 .
-#define PERFETTO_TP_EXPAND_VA_ARGS(x) x
-
-#define PERFETTO_TP_COLUMN_FLAG(...) \
- PERFETTO_TP_EXPAND_VA_ARGS(PERFETTO_TP_COLUMN_FLAG_CHOOSER( \
- __VA_ARGS__, PERFETTO_TP_COLUMN_FLAG_HAS_FLAG_COL, \
- PERFETTO_TP_COLUMN_FLAG_NO_FLAG_COL)(__VA_ARGS__))
-
-#define PERFETTO_TP_PARENT_COLUMN_FLAG(...) \
- PERFETTO_TP_EXPAND_VA_ARGS(PERFETTO_TP_COLUMN_FLAG_CHOOSER( \
- __VA_ARGS__, PERFETTO_TP_PARENT_COLUMN_FLAG_HAS_FLAG_COL, \
- PERFETTO_TP_PARENT_COLUMN_FLAG_NO_FLAG_COL)(__VA_ARGS__))
-
-// Creates the sparse vector with the given flags.
-#define PERFETTO_TP_TABLE_CONSTRUCTOR_SV(type, name, ...) \
- name##_(ColumnStorage<TypedColumn<type>::stored_type>::Create< \
- (name##_flags() & Column::Flag::kDense) != 0>()),
-
-// Invokes the chosen column constructor by passing the given args.
-#define PERFETTO_TP_TABLE_CONSTRUCTOR_COLUMN(type, name, ...) \
- columns_.emplace_back(#name, &name##_, name##_flags(), this, \
- static_cast<uint32_t>(columns_.size()), \
- static_cast<uint32_t>(overlays_.size()) - 1);
-
-// Inserts the value into the corresponding column.
-#define PERFETTO_TP_COLUMN_APPEND(type, name, ...) \
- mutable_##name()->Append(std::move(row.name));
-
-// Creates a schema entry for the corresponding column.
-#define PERFETTO_TP_COLUMN_SCHEMA(type, name, ...) \
- schema.columns.emplace_back(Table::Schema::Column{ \
- #name, TypedColumn<type>::SqlValueType(), false, \
- static_cast<bool>(name##_flags() & Column::Flag::kSorted), \
- static_cast<bool>(name##_flags() & Column::Flag::kHidden), \
- static_cast<bool>(name##_flags() & Column::Flag::kSetId)});
-
-// Defines the immutable accessor for a column.
-#define PERFETTO_TP_TABLE_COL_GETTER(type, name, ...) \
- const TypedColumn<type>& name() const { \
- return static_cast<const TypedColumn<type>&>(columns_[ColumnIndex::name]); \
- }
-
-// Defines the accessors for a column.
-#define PERFETTO_TP_TABLE_MUTABLE_COL_GETTER(type, name, ...) \
- TypedColumn<type>* mutable_##name() { \
- return static_cast<TypedColumn<type>*>(&columns_[ColumnIndex::name]); \
- }
-
-// Defines the accessors for a column.
-#define PERFETTO_TP_TABLE_STATIC_ASSERT_FLAG(type, name, ...) \
- static_assert(Column::IsFlagsAndTypeValid<TypedColumn<type>::stored_type>( \
- name##_flags()), \
- "Column type and flag combination is not valid");
-
-// Defines the parameter for the |ExtendParent| function.
-#define PERFETTO_TP_TABLE_EXTEND_PARAM(type, name, ...) \
- ColumnStorage<TypedColumn<type>::stored_type> name,
-
-// Defines the parameter passing for the |ExtendParent| function.
-#define PERFETTO_TP_TABLE_EXTEND_PARAM_PASSING(type, name, ...) std::move(name),
-
-// Sets the table nullable vector to the parameter passed in the
-// |SelectAndExtendParent| function.
-#define PERFETTO_TP_TABLE_EXTEND_SET_NV(type, name, ...) \
- PERFETTO_DCHECK(name.size() == parent_overlay.size()); \
- name##_ = std::move(name);
-
-// Definition used as the parent of root tables.
-#define PERFETTO_TP_ROOT_TABLE_PARENT_DEF(NAME, PARENT, C) \
- NAME(macros_internal::RootParentTable, "root")
-
-// Defines the getter for the column value in the RowReference.
-#define PERFETTO_TP_TABLE_CONST_ROW_REF_GETTER(type, name, ...) \
- type name() const { return table_->name()[row_number_]; }
-
-// Defines the accessor for the column value in the RowReference.
-#define PERFETTO_TP_TABLE_ROW_REF_SETTER(type, name, ...) \
- void set_##name(TypedColumn<type>::non_optional_type v) const { \
- return mutable_table()->mutable_##name()->Set(row_number_, v); \
- }
-
-// Defines the getter for the column value in the ConstIterator.
-#define PERFETTO_TP_TABLE_CONST_IT_GETTER(type, name, ...) \
- type name() const { \
- const auto& col = table_->name(); \
- return col.GetAtIdx(its_[col.overlay_index()].index()); \
- }
-
-// Defines the setter for the column value in the Iterator.
-#define PERFETTO_TP_TABLE_IT_SETTER(type, name, ...) \
- void set_##name(TypedColumn<type>::non_optional_type v) { \
- auto* col = mutable_table_->mutable_##name(); \
- col->SetAtIdx(its_[col->overlay_index()].index(), v); \
- }
-
-// Defines the column index constexpr declaration.
-#define PERFETTO_TP_COLUMN_INDEX(type, name, ...) \
- static constexpr uint32_t name = static_cast<uint32_t>(ColumnIndexEnum::name);
-
-// Defines an alias for column type for each column.
-#define PERFETTO_TP_COLUMN_TYPE_USING(type, name, ...) \
- using name = TypedColumn<type>;
-
-// Calls ShrinkToFit on each column.
-#define PERFETTO_TP_COLUMN_SHRINK_TO_FIT(type, name, ...) name##_.ShrinkToFit();
-
-// For more general documentation, see PERFETTO_TP_TABLE in macros.h.
-#define PERFETTO_TP_TABLE_INTERNAL(table_name, class_name, parent_class_name, \
- DEF) \
- class class_name : public macros_internal::MacroTable { \
- public: \
- /* Forward declaration to allow free usage below. */ \
- class ConstRowReference; \
- class RowReference; \
- class RowNumber; \
- class ConstIterator; \
- \
- private: \
- /* \
- * Allows IdHelper to access DefinedId for root tables. \
- * Needs to be defined here to allow the public using declaration of Id \
- * below to work correctly. \
- */ \
- friend struct macros_internal::IdHelper<parent_class_name, class_name>; \
- \
- /* Whether or not this is a root table */ \
- static constexpr bool kIsRootTable = \
- std::is_same<parent_class_name, \
- macros_internal::RootParentTable>::value; \
- \
- /* Aliases to reduce clutter in class defintions below. */ \
- using AbstractRowNumber = macros_internal:: \
- AbstractRowNumber<class_name, ConstRowReference, RowReference>; \
- using AbstractConstRowReference = \
- macros_internal::AbstractConstRowReference<class_name, RowNumber>; \
- using AbstractConstIterator = \
- macros_internal::AbstractConstIterator<ConstIterator, \
- class_name, \
- RowNumber, \
- ConstRowReference>; \
- \
- enum class ColumnIndexEnum { \
- id, \
- type, /* Expands to col1, col2, ... */ \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_NAME_COMMA) kNumCols \
- }; \
- \
- /* \
- * Defines a new id type for a hierarchy of tables. \
- * We define it here as we need this type to be visible for the public \
- * using declaration of Id below. \
- * Note: This type will only used if this table is a root table. \
- */ \
- struct DefinedId : public BaseId { \
- DefinedId() = default; \
- explicit constexpr DefinedId(uint32_t v) : BaseId(v) {} \
- }; \
- static_assert(std::is_trivially_destructible<DefinedId>::value, \
- "Inheritance used without trivial destruction"); \
- \
- static constexpr uint32_t id_flags() { return Column::kIdFlags; } \
- static constexpr uint32_t type_flags() { return Column::kNoFlag; } \
- PERFETTO_TP_PARENT_COLUMNS(DEF, PERFETTO_TP_PARENT_COLUMN_FLAG) \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_COLUMN_FLAG) \
- \
- public: \
- /* \
- * This defines the type of the id to be the type of the root \
- * table of the hierarchy - see IdHelper for more details. \
- */ \
- using Id = macros_internal::IdHelper<parent_class_name, class_name>::Id; \
- \
- struct ColumnIndex { \
- static constexpr uint32_t id = \
- static_cast<uint32_t>(ColumnIndexEnum::id); \
- static constexpr uint32_t type = \
- static_cast<uint32_t>(ColumnIndexEnum::type); \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_COLUMN_INDEX) \
- }; \
- \
- struct ColumnType { \
- using id = IdColumn<Id>; \
- using type = TypedColumn<StringPool::Id>; \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_COLUMN_TYPE_USING) \
- }; \
- \
- struct Row : parent_class_name::Row { \
- /* \
- * Expands to Row(col_type1 col1_c, std::optional<col_type2> col2_c, \
- * ...) \
- */ \
- Row(PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_ROW_CONSTRUCTOR) \
- std::nullptr_t = nullptr) \
- : parent_class_name::Row(PERFETTO_TP_PARENT_COLUMNS( \
- DEF, \
- PERFETTO_TP_PARENT_ROW_CONSTRUCTOR) nullptr) { \
- type_ = table_name; \
- \
- /* \
- * Expands to \
- * col1 = col1_c; \
- * ... \
- */ \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_ROW_INITIALIZER) \
- } \
- \
- bool operator==(const class_name::Row& other) const { \
- return PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_ROW_EQUALS) true; \
- } \
- \
- /* \
- * Expands to \
- * col_type1 col1 = {}; \
- * ... \
- */ \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_ROW_DEFINITION) \
- }; \
- static_assert(std::is_trivially_destructible<Row>::value, \
- "Inheritance used without trivial destruction"); \
- \
- /* \
- * Reference to a row which exists in the table. \
- * \
- * Allows caller code to store and instances of this object without \
- * having to interact with row numbers. \
- */ \
- class ConstRowReference : public AbstractConstRowReference { \
- public: \
- ConstRowReference(const class_name* table, uint32_t row_number) \
- : AbstractConstRowReference(table, row_number) {} \
- \
- PERFETTO_TP_TABLE_CONST_ROW_REF_GETTER(Id, id) \
- PERFETTO_TP_TABLE_CONST_ROW_REF_GETTER(StringPool::Id, type) \
- \
- /* \
- * Expands to \
- * col1_type col1() const { return table_->col1()[row_]; } \
- * ... \
- */ \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_CONST_ROW_REF_GETTER) \
- }; \
- static_assert(std::is_trivially_destructible<ConstRowReference>::value, \
- "Inheritance used without trivial destruction"); \
- \
- /* \
- * Reference to a row which exists in the table. \
- * \
- * Allows caller code to store and instances of this object without \
- * having to interact with row numbers. \
- */ \
- class RowReference : public ConstRowReference { \
- public: \
- RowReference(class_name* table, uint32_t row_number) \
- : ConstRowReference(table, row_number) {} \
- \
- /* \
- * Expands to \
- * void set_col1(col1_type v) { table_->mutable_col1()->Set(row, v); } \
- * ... \
- */ \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_ROW_REF_SETTER) \
- \
- private: \
- class_name* mutable_table() const { \
- return const_cast<class_name*>(table_); \
- } \
- }; \
- static_assert(std::is_trivially_destructible<RowReference>::value, \
- "Inheritance used without trivial destruction"); \
- \
- /* \
- * Strongly typed wrapper around the row index. Prefer storing this over \
- * storing RowReference to reduce memory usage \
- */ \
- class RowNumber : public AbstractRowNumber { \
- public: \
- explicit RowNumber(uint32_t row_number) \
- : AbstractRowNumber(row_number) {} \
- }; \
- static_assert(std::is_trivially_destructible<RowNumber>::value, \
- "Inheritance used without trivial destruction"); \
- \
- /* Return value of Insert giving access to id and row number */ \
- struct IdAndRow { \
- Id id; \
- uint32_t row; \
- RowReference row_reference; \
- RowNumber row_number; \
- }; \
- \
- /* \
- * Strongly typed const iterator for this macro table. \
- * \
- * Allows efficient retrieval of values from this table without having to \
- * deal with row numbers, ColumnStorageOverlays or indices. \
- */ \
- class ConstIterator : public AbstractConstIterator { \
- public: \
- PERFETTO_TP_TABLE_CONST_IT_GETTER(Id, id) \
- PERFETTO_TP_TABLE_CONST_IT_GETTER(StringPool::Id, type) \
- \
- /* \
- * Expands to \
- * col1_type col1() const { return table_->col1().GetAtIdx(i); } \
- * ... \
- */ \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_CONST_IT_GETTER) \
- \
- protected: \
- /* \
- * Must not be public to avoid buggy code because of inheritance \
- * without virtual destructor. \
- */ \
- explicit ConstIterator(const class_name* table, \
- std::vector<ColumnStorageOverlay> overlays) \
- : AbstractConstIterator(table, std::move(overlays)) {} \
- \
- uint32_t CurrentRowNumber() const { \
- /* \
- * Because the last ColumnStorageOverlay belongs to this table it \
- * will be dense (i.e. every row in the table will be part of this \
- * ColumnStorageOverlay + will be represented with a range). This \
- * means that the index() of the last ColumnStorageOverlay iterator \
- * is precisely the row number in table! \
- */ \
- return its_.back().index(); \
- } \
- \
- private: \
- friend class class_name; \
- friend class AbstractConstIterator; \
- }; \
- \
- /* \
- * Strongly typed iterator for this macro table. \
- * \
- * Enhances ConstIterator by also allowing values in the table to be set \
- * as well as retrieved. \
- */ \
- class Iterator : public ConstIterator { \
- public: \
- /* \
- * Expands to \
- * void set_col1(col1_type v) { table_->mut_col1()->SetAtIdx(i, v); } \
- * ... \
- */ \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_IT_SETTER) \
- \
- /* \
- * Returns a RowReference to the current row. \
- */ \
- RowReference row_reference() const { \
- return RowReference(mutable_table_, CurrentRowNumber()); \
- } \
- \
- private: \
- friend class class_name; \
- \
- /* \
- * Must not be public to avoid buggy code because of inheritance \
- * without virtual destructor. \
- */ \
- explicit Iterator(class_name* table, \
- std::vector<ColumnStorageOverlay> overlays) \
- : ConstIterator(table, std::move(overlays)), \
- mutable_table_(table) {} \
- \
- class_name* mutable_table_ = nullptr; \
- }; \
- \
- class_name(StringPool* pool, parent_class_name* parent) \
- : macros_internal::MacroTable(pool, parent), \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_CONSTRUCTOR_SV) \
- parent_(parent) { \
- PERFETTO_CHECK(kIsRootTable == (parent == nullptr)); \
- \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_STATIC_ASSERT_FLAG) \
- \
- /* \
- * Expands to \
- * columns_.emplace_back("col1", col1_, Column::kNoFlag, this, \
- * static_cast<uint32_t>(columns_.size()), \
- * static_cast<uint32_t>(overlays_.size()) - 1); \
- * ... \
- */ \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_CONSTRUCTOR_COLUMN); \
- } \
- ~class_name() override; \
- \
- IdAndRow Insert(const Row& row) { \
- PERFETTO_DCHECK(allow_inserts_); \
- \
- Id id; \
- uint32_t row_number = row_count(); \
- if (kIsRootTable) { \
- id = Id{row_number}; \
- type_.Append(string_pool_->InternString(row.type())); \
- } else { \
- PERFETTO_DCHECK(parent_); \
- id = Id{parent_->Insert(row).id}; \
- UpdateOverlaysAfterParentInsert(); \
- } \
- \
- /* \
- * Expands to \
- * col1_.Append(row.col1); \
- * ... \
- */ \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_COLUMN_APPEND); \
- \
- UpdateSelfOverlayAfterInsert(); \
- return {id, row_number, RowReference(this, row_number), \
- RowNumber(row_number)}; \
- } \
- \
- static Table::Schema ComputeStaticSchema() { \
- Table::Schema schema; \
- schema.columns.emplace_back(Table::Schema::Column{ \
- "id", SqlValue::Type::kLong, true, true, false, false}); \
- schema.columns.emplace_back(Table::Schema::Column{ \
- "type", SqlValue::Type::kString, false, false, false, false}); \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_COLUMN_SCHEMA); \
- return schema; \
- } \
- \
- void ShrinkToFit() { \
- type_.ShrinkToFit(); \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_COLUMN_SHRINK_TO_FIT); \
- } \
- \
- /* Iterates the table. */ \
- ConstIterator IterateRows() const { \
- return ConstIterator(this, CopyOverlays()); \
- } \
- \
- /* Iterates the table. */ \
- Iterator IterateRows() { return Iterator(this, CopyOverlays()); } \
- \
- /* Filters the Table using the specified filter constraints. */ \
- ConstIterator FilterToIterator( \
- const std::vector<Constraint>& cs, \
- RowMap::OptimizeFor opt = RowMap::OptimizeFor::kMemory) const { \
- return ConstIterator(this, FilterAndApplyToOverlays(cs, opt)); \
- } \
- \
- /* Filters the Table using the specified filter constraints. */ \
- Iterator FilterToIterator( \
- const std::vector<Constraint>& cs, \
- RowMap::OptimizeFor opt = RowMap::OptimizeFor::kMemory) { \
- return Iterator(this, FilterAndApplyToOverlays(cs, opt)); \
- } \
- \
- /* Returns a ConstRowReference to the row pointed to by |find_id|. */ \
- std::optional<ConstRowReference> FindById(Id find_id) const { \
- std::optional<uint32_t> row = id().IndexOf(find_id); \
- if (!row) \
- return std::nullopt; \
- return ConstRowReference(this, *row); \
- } \
- \
- /* Returns a RowReference to the row pointed to by |find_id|. */ \
- std::optional<RowReference> FindById(Id find_id) { \
- std::optional<uint32_t> row = id().IndexOf(find_id); \
- if (!row) \
- return std::nullopt; \
- return RowReference(this, *row); \
- } \
- \
- const IdColumn<Id>& id() const { \
- return static_cast<const IdColumn<Id>&>( \
- columns_[static_cast<uint32_t>(ColumnIndex::id)]); \
- } \
- PERFETTO_TP_TABLE_COL_GETTER(StringPool::Id, type) \
- \
- /* Returns the name of the table */ \
- static constexpr const char* Name() { return table_name; } \
- \
- /* \
- * Creates a filled instance of this class by selecting all rows in \
- * parent and filling the table columns with the provided vectors. \
- */ \
- static std::unique_ptr<Table> ExtendParent( \
- const parent_class_name& parent, \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_EXTEND_PARAM) \
- std::nullptr_t = nullptr) { \
- return std::unique_ptr<Table>(new class_name( \
- parent.string_pool(), parent, RowMap(0, parent.row_count()), \
- PERFETTO_TP_TABLE_COLUMNS( \
- DEF, PERFETTO_TP_TABLE_EXTEND_PARAM_PASSING) nullptr)); \
- } \
- \
- /* \
- * Creates a filled instance of this class by first selecting all rows in \
- * parent given by |rows| and filling the table columns with the provided \
- * vectors. \
- */ \
- static std::unique_ptr<Table> SelectAndExtendParent( \
- const parent_class_name& parent, \
- std::vector<parent_class_name::RowNumber> parent_row_overlay, \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_EXTEND_PARAM) \
- std::nullptr_t = nullptr) { \
- std::vector<uint32_t> prs_untyped(parent_row_overlay.size()); \
- for (uint32_t i = 0; i < parent_row_overlay.size(); ++i) { \
- prs_untyped[i] = parent_row_overlay[i].row_number(); \
- } \
- return std::unique_ptr<Table>(new class_name( \
- parent.string_pool(), parent, RowMap(std::move(prs_untyped)), \
- PERFETTO_TP_TABLE_COLUMNS( \
- DEF, PERFETTO_TP_TABLE_EXTEND_PARAM_PASSING) nullptr)); \
- } \
- \
- /* \
- * Expands to \
- * const TypedColumn<col1_type>& col1() { return col1_; } \
- * ... \
- */ \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_COL_GETTER) \
- \
- /* \
- * Expands to \
- * TypedColumn<col1_type>* mutable_col1() { return &col1_; } \
- * ... \
- */ \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_MUTABLE_COL_GETTER) \
- \
- private: \
- class_name(StringPool* pool, \
- const parent_class_name& parent, \
- RowMap parent_overlay, \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_EXTEND_PARAM) \
- std::nullptr_t = nullptr) \
- : macros_internal::MacroTable(pool, parent, parent_overlay) { \
- PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_STATIC_ASSERT_FLAG) \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_EXTEND_SET_NV) \
- \
- /* \
- * Expands to \
- * columns_.emplace_back("col1", col1_, Column::kNoFlag, this, \
- * static_cast<uint32_t>(columns_.size()), \
- * static_cast<uint32_t>(overlays_.size()) - 1); \
- * ... \
- */ \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_CONSTRUCTOR_COLUMN); \
- } \
- \
- /* \
- * Expands to \
- * NullableVector<col1_type> col1_; \
- * ... \
- */ \
- PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_MEMBER) \
- \
- parent_class_name* parent_ = nullptr; \
- }
-
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/tables/memory_tables.py b/src/trace_processor/tables/memory_tables.py
index 65263f87d..f270aa7e0 100644
--- a/src/trace_processor/tables/memory_tables.py
+++ b/src/trace_processor/tables/memory_tables.py
@@ -26,6 +26,7 @@ from python.generators.trace_processor_table.public import CppUint32
from src.trace_processor.tables.track_tables import TRACK_TABLE
MEMORY_SNAPSHOT_TABLE = Table(
+ python_module=__file__,
class_name='MemorySnapshotTable',
sql_name='memory_snapshot',
columns=[
@@ -43,6 +44,7 @@ MEMORY_SNAPSHOT_TABLE = Table(
}))
PROCESS_MEMORY_SNAPSHOT_TABLE = Table(
+ python_module=__file__,
class_name='ProcessMemorySnapshotTable',
sql_name='process_memory_snapshot',
columns=[
@@ -58,6 +60,7 @@ PROCESS_MEMORY_SNAPSHOT_TABLE = Table(
}))
MEMORY_SNAPSHOT_NODE_TABLE = Table(
+ python_module=__file__,
class_name='MemorySnapshotNodeTable',
sql_name='memory_snapshot_node',
columns=[
@@ -81,6 +84,7 @@ MEMORY_SNAPSHOT_NODE_TABLE = Table(
}))
MEMORY_SNAPSHOT_EDGE_TABLE = Table(
+ python_module=__file__,
class_name='MemorySnapshotEdgeTable',
sql_name='memory_snapshot_edge',
columns=[
diff --git a/src/trace_processor/tables/metadata_tables.py b/src/trace_processor/tables/metadata_tables.py
index 621f3fcfa..0219aa980 100644
--- a/src/trace_processor/tables/metadata_tables.py
+++ b/src/trace_processor/tables/metadata_tables.py
@@ -29,6 +29,7 @@ from python.generators.trace_processor_table.public import CppSelfTableId
from python.generators.trace_processor_table.public import WrappingSqlView
PROCESS_TABLE = Table(
+ python_module=__file__,
class_name='ProcessTable',
sql_name='internal_process',
columns=[
@@ -100,6 +101,7 @@ PROCESS_TABLE = Table(
}))
THREAD_TABLE = Table(
+ python_module=__file__,
class_name='ThreadTable',
sql_name='internal_thread',
columns=[
@@ -159,27 +161,59 @@ THREAD_TABLE = Table(
}))
RAW_TABLE = Table(
+ python_module=__file__,
class_name='RawTable',
sql_name='raw',
columns=[
C('ts', CppInt64(), flags=ColumnFlag.SORTED),
C('name', CppString()),
C('cpu', CppUint32()),
- C('utid', CppUint32()),
+ C('utid', CppTableId(THREAD_TABLE)),
C('arg_set_id', CppUint32()),
],
tabledoc=TableDoc(
- doc='''''',
+ doc='''
+ Contains 'raw' events from the trace for some types of events. This
+ table only exists for debugging purposes and should not be relied on
+ in production usecases (i.e. metrics, standard library etc).
+ ''',
group='Misc',
columns={
- 'arg_set_id': '''''',
- 'ts': '''''',
- 'name': '''''',
- 'cpu': '''''',
- 'utid': ''''''
+ 'arg_set_id':
+ ColumnDoc(
+ 'The set of key/value pairs associated with this event.',
+ joinable='args.arg_set_id'),
+ 'ts':
+ 'The timestamp of this event.',
+ 'name':
+ '''
+ The name of the event. For ftrace events, this will be the
+ ftrace event name.
+ ''',
+ 'cpu':
+ 'The CPU this event was emitted on.',
+ 'utid':
+ 'The thread this event was emitted on.'
}))
+FTRACE_EVENT_TABLE = Table(
+ python_module=__file__,
+ class_name='FtraceEventTable',
+ sql_name='ftrace_event',
+ parent=RAW_TABLE,
+ columns=[],
+ tabledoc=TableDoc(
+ doc='''
+ Contains all the ftrace events in the trace. This table exists only for
+ debugging purposes and should not be relied on in production usecases
+ (i.e. metrics, standard library etc). Note also that this table might
+ be empty if raw ftrace parsing has been disabled.
+ ''',
+ group='Misc',
+ columns={}))
+
ARG_TABLE = Table(
+ python_module=__file__,
class_name='ArgTable',
sql_name='internal_args',
columns=[
@@ -206,6 +240,7 @@ ARG_TABLE = Table(
}))
METADATA_TABLE = Table(
+ python_module=__file__,
class_name='MetadataTable',
sql_name='metadata',
columns=[
@@ -225,6 +260,7 @@ METADATA_TABLE = Table(
}))
FILEDESCRIPTOR_TABLE = Table(
+ python_module=__file__,
class_name='FiledescriptorTable',
sql_name='filedescriptor',
columns=[
@@ -261,6 +297,7 @@ number.'''
}))
EXP_MISSING_CHROME_PROC_TABLE = Table(
+ python_module=__file__,
class_name='ExpMissingChromeProcTable',
sql_name='experimental_missing_chrome_processes',
columns=[
@@ -278,6 +315,7 @@ EXP_MISSING_CHROME_PROC_TABLE = Table(
}))
CPU_TABLE = Table(
+ python_module=__file__,
class_name='CpuTable',
sql_name='cpu',
columns=[
@@ -298,6 +336,7 @@ the same cluster''',
}))
CPU_FREQ_TABLE = Table(
+ python_module=__file__,
class_name='CpuFreqTable',
sql_name='cpu_freq',
columns=[
@@ -311,6 +350,7 @@ CPU_FREQ_TABLE = Table(
}))
CLOCK_SNAPSHOT_TABLE = Table(
+ python_module=__file__,
class_name='ClockSnapshotTable',
sql_name='clock_snapshot',
columns=[
@@ -344,7 +384,15 @@ otherwise.''',
# Keep this list sorted.
ALL_TABLES = [
- ARG_TABLE, CLOCK_SNAPSHOT_TABLE, CPU_FREQ_TABLE, CPU_TABLE,
- EXP_MISSING_CHROME_PROC_TABLE, FILEDESCRIPTOR_TABLE, METADATA_TABLE,
- PROCESS_TABLE, RAW_TABLE, THREAD_TABLE
+ ARG_TABLE,
+ CLOCK_SNAPSHOT_TABLE,
+ CPU_FREQ_TABLE,
+ CPU_TABLE,
+ EXP_MISSING_CHROME_PROC_TABLE,
+ FILEDESCRIPTOR_TABLE,
+ METADATA_TABLE,
+ PROCESS_TABLE,
+ RAW_TABLE,
+ THREAD_TABLE,
+ FTRACE_EVENT_TABLE,
]
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
deleted file mode 100644
index f0e84b259..000000000
--- a/src/trace_processor/tables/profiler_tables.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_TABLES_PROFILER_TABLES_H_
-#define SRC_TRACE_PROCESSOR_TABLES_PROFILER_TABLES_H_
-
-#include "src/trace_processor/tables/macros.h"
-#include "src/trace_processor/tables/track_tables_py.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace tables {
-
-// A callsite. This is a list of frames that were on the stack.
-// This is generated by the stack profilers: heapprofd and traced_perf.
-// @param depth distance from the bottom-most frame of the callstack.
-// @param parent_id parent frame on the callstack. NULL for the bottom-most.
-// @param frame_id frame at this position in the callstack.
-// @tablegroup Callstack profilers
-#define PERFETTO_TP_STACK_PROFILE_CALLSITE_DEF(NAME, PARENT, C) \
- NAME(StackProfileCallsiteTable, "stack_profile_callsite") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(uint32_t, depth) \
- C(std::optional<StackProfileCallsiteTable::Id>, parent_id) \
- C(StackProfileFrameTable::Id, frame_id)
-
-} // namespace tables
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_TABLES_PROFILER_TABLES_H_
diff --git a/src/trace_processor/tables/profiler_tables.py b/src/trace_processor/tables/profiler_tables.py
index d42800969..c712adff9 100644
--- a/src/trace_processor/tables/profiler_tables.py
+++ b/src/trace_processor/tables/profiler_tables.py
@@ -28,6 +28,7 @@ from python.generators.trace_processor_table.public import CppUint32
from src.trace_processor.tables.track_tables import TRACK_TABLE
PROFILER_SMAPS_TABLE = Table(
+ python_module=__file__,
class_name='ProfilerSmapsTable',
sql_name='profiler_smaps',
columns=[
@@ -94,6 +95,7 @@ timestamp.''',
}))
PACKAGE_LIST_TABLE = Table(
+ python_module=__file__,
class_name='PackageListTable',
sql_name='package_list',
columns=[
@@ -123,6 +125,7 @@ This is generated by the packages_list data-source.
}))
STACK_PROFILE_MAPPING_TABLE = Table(
+ python_module=__file__,
class_name='StackProfileMappingTable',
sql_name='stack_profile_mapping',
columns=[
@@ -151,6 +154,7 @@ This is generated by the stack profilers: heapprofd and traced_perf.
}))
STACK_PROFILE_FRAME_TABLE = Table(
+ python_module=__file__,
class_name='StackProfileFrameTable',
sql_name='stack_profile_frame',
columns=[
@@ -181,6 +185,7 @@ symbol information of this frame.''',
}))
STACK_PROFILE_CALLSITE_TABLE = Table(
+ python_module=__file__,
class_name='StackProfileCallsiteTable',
sql_name='stack_profile_callsite',
columns=[
@@ -204,6 +209,7 @@ This is generated by the stack profilers: heapprofd and traced_perf.
}))
STACK_SAMPLE_TABLE = Table(
+ python_module=__file__,
class_name='StackSampleTable',
sql_name='stack_sample',
columns=[
@@ -221,6 +227,7 @@ STACK_SAMPLE_TABLE = Table(
}))
CPU_PROFILE_STACK_SAMPLE_TABLE = Table(
+ python_module=__file__,
class_name='CpuProfileStackSampleTable',
sql_name='cpu_profile_stack_sample',
columns=[
@@ -239,6 +246,7 @@ CPU_PROFILE_STACK_SAMPLE_TABLE = Table(
}))
PERF_SAMPLE_TABLE = Table(
+ python_module=__file__,
class_name='PerfSampleTable',
sql_name='perf_sample',
columns=[
@@ -278,6 +286,7 @@ streams (i.e. multiple data sources).'''
}))
SYMBOL_TABLE = Table(
+ python_module=__file__,
class_name='SymbolTable',
sql_name='stack_profile_symbol',
columns=[
@@ -323,6 +332,7 @@ SYMBOL_TABLE = Table(
}))
HEAP_PROFILE_ALLOCATION_TABLE = Table(
+ python_module=__file__,
class_name='HeapProfileAllocationTable',
sql_name='heap_profile_allocation',
columns=[
@@ -367,6 +377,7 @@ that were freed.''',
}))
EXPERIMENTAL_FLAMEGRAPH_NODES_TABLE = Table(
+ python_module=__file__,
class_name='ExperimentalFlamegraphNodesTable',
sql_name='experimental_flamegraph_nodes',
columns=[
@@ -421,6 +432,7 @@ EXPERIMENTAL_FLAMEGRAPH_NODES_TABLE = Table(
}))
HEAP_GRAPH_CLASS_TABLE = Table(
+ python_module=__file__,
class_name='HeapGraphClassTable',
sql_name='heap_graph_class',
columns=[
@@ -455,6 +467,7 @@ TODO(lalitm): resolve this''',
}))
HEAP_GRAPH_OBJECT_TABLE = Table(
+ python_module=__file__,
class_name='HeapGraphObjectTable',
sql_name='heap_graph_object',
columns=[
@@ -500,6 +513,7 @@ false, this object is uncollected garbage.''',
}))
HEAP_GRAPH_REFERENCE_TABLE = Table(
+ python_module=__file__,
class_name='HeapGraphReferenceTable',
sql_name='heap_graph_reference',
columns=[
@@ -537,6 +551,7 @@ deobfuscation mapping was provided for it, the deobfuscated name.'''
}))
VULKAN_MEMORY_ALLOCATIONS_TABLE = Table(
+ python_module=__file__,
class_name='VulkanMemoryAllocationsTable',
sql_name='vulkan_memory_allocations',
columns=[
@@ -576,6 +591,7 @@ VULKAN_MEMORY_ALLOCATIONS_TABLE = Table(
}))
GPU_COUNTER_GROUP_TABLE = Table(
+ python_module=__file__,
class_name='GpuCounterGroupTable',
sql_name='gpu_counter_group',
columns=[
diff --git a/src/trace_processor/tables/macros_benchmark.cc b/src/trace_processor/tables/py_tables_benchmark.cc
index c946696bd..45a96e897 100644
--- a/src/trace_processor/tables/macros_benchmark.cc
+++ b/src/trace_processor/tables/py_tables_benchmark.cc
@@ -16,35 +16,16 @@
#include <benchmark/benchmark.h>
-#include "src/trace_processor/tables/macros.h"
+#include "src/trace_processor/tables/py_tables_benchmark_py.h"
namespace perfetto {
namespace trace_processor {
-namespace {
-
-#define PERFETTO_TP_ROOT_TEST_TABLE(NAME, PARENT, C) \
- NAME(RootTestTable, "root_table") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(uint32_t, root_sorted, Column::Flag::kSorted) \
- C(uint32_t, root_non_null) \
- C(uint32_t, root_non_null_2) \
- C(std::optional<uint32_t>, root_nullable)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_ROOT_TEST_TABLE);
-
-#define PERFETTO_TP_CHILD_TABLE(NAME, PARENT, C) \
- NAME(ChildTestTable, "child_table") \
- PARENT(PERFETTO_TP_ROOT_TEST_TABLE, C) \
- C(uint32_t, child_sorted, Column::Flag::kSorted) \
- C(uint32_t, child_non_null) \
- C(std::optional<uint32_t>, child_nullable)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_CHILD_TABLE);
+namespace tables {
RootTestTable::~RootTestTable() = default;
ChildTestTable::~ChildTestTable() = default;
-} // namespace
+} // namespace tables
} // namespace trace_processor
} // namespace perfetto
@@ -74,16 +55,16 @@ void TableSortArgs(benchmark::internal::Benchmark* b) {
} // namespace
-using perfetto::trace_processor::ChildTestTable;
-using perfetto::trace_processor::RootTestTable;
using perfetto::trace_processor::RowMap;
using perfetto::trace_processor::SqlValue;
using perfetto::trace_processor::StringPool;
using perfetto::trace_processor::Table;
+using perfetto::trace_processor::tables::ChildTestTable;
+using perfetto::trace_processor::tables::RootTestTable;
static void BM_TableInsert(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
for (auto _ : state) {
benchmark::DoNotOptimize(root.Insert({}));
@@ -93,7 +74,7 @@ BENCHMARK(BM_TableInsert);
static void BM_TableIteratorChild(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -116,7 +97,7 @@ BENCHMARK(BM_TableIteratorChild)->Apply(TableFilterArgs);
static void BM_TableFilterAndSortRoot(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t partitions = 8;
@@ -140,7 +121,7 @@ BENCHMARK(BM_TableFilterAndSortRoot)->Apply(TableFilterArgs);
static void BM_TableFilterRootId(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
for (uint32_t i = 0; i < size; ++i)
@@ -154,7 +135,7 @@ BENCHMARK(BM_TableFilterRootId)->Apply(TableFilterArgs);
static void BM_TableFilterRootIdAndOther(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -173,7 +154,7 @@ BENCHMARK(BM_TableFilterRootIdAndOther)->Apply(TableFilterArgs);
static void BM_TableFilterChildId(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -190,7 +171,7 @@ BENCHMARK(BM_TableFilterChildId)->Apply(TableFilterArgs);
static void BM_TableFilterChildIdAndSortedInRoot(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -213,7 +194,7 @@ BENCHMARK(BM_TableFilterChildIdAndSortedInRoot)->Apply(TableFilterArgs);
static void BM_TableFilterRootNonNullEqMatchMany(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t partitions = size / 1024;
@@ -232,7 +213,7 @@ BENCHMARK(BM_TableFilterRootNonNullEqMatchMany)->Apply(TableFilterArgs);
static void BM_TableFilterRootMultipleNonNull(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t partitions = size / 512;
@@ -254,7 +235,7 @@ BENCHMARK(BM_TableFilterRootMultipleNonNull)->Apply(TableFilterArgs);
static void BM_TableFilterRootNullableEqMatchMany(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t partitions = size / 512;
@@ -277,7 +258,7 @@ BENCHMARK(BM_TableFilterRootNullableEqMatchMany)->Apply(TableFilterArgs);
static void BM_TableFilterChildNonNullEqMatchMany(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -299,7 +280,7 @@ BENCHMARK(BM_TableFilterChildNonNullEqMatchMany)->Apply(TableFilterArgs);
static void BM_TableFilterChildNullableEqMatchMany(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -325,7 +306,7 @@ BENCHMARK(BM_TableFilterChildNullableEqMatchMany)->Apply(TableFilterArgs);
static void BM_TableFilterChildNonNullEqMatchManyInParent(
benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -349,7 +330,7 @@ BENCHMARK(BM_TableFilterChildNonNullEqMatchManyInParent)
static void BM_TableFilterChildNullableEqMatchManyInParent(
benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -372,7 +353,7 @@ BENCHMARK(BM_TableFilterChildNullableEqMatchManyInParent)
static void BM_TableFilterParentSortedEq(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -390,7 +371,7 @@ BENCHMARK(BM_TableFilterParentSortedEq)->Apply(TableFilterArgs);
static void BM_TableFilterParentSortedAndOther(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -415,7 +396,7 @@ BENCHMARK(BM_TableFilterParentSortedAndOther)->Apply(TableFilterArgs);
static void BM_TableFilterChildSortedEq(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -435,7 +416,7 @@ BENCHMARK(BM_TableFilterChildSortedEq)->Apply(TableFilterArgs);
static void BM_TableFilterChildSortedEqInParent(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -458,7 +439,7 @@ BENCHMARK(BM_TableFilterChildSortedEqInParent)->Apply(TableFilterArgs);
static void BM_TableSortRootNonNull(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -479,7 +460,7 @@ BENCHMARK(BM_TableSortRootNonNull)->Apply(TableSortArgs);
static void BM_TableSortRootNullable(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -501,7 +482,7 @@ BENCHMARK(BM_TableSortRootNullable)->Apply(TableSortArgs);
static void BM_TableSortChildNonNullInParent(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
@@ -529,7 +510,7 @@ BENCHMARK(BM_TableSortChildNonNullInParent)->Apply(TableSortArgs);
static void BM_TableSortChildNullableInParent(benchmark::State& state) {
StringPool pool;
- RootTestTable root(&pool, nullptr);
+ RootTestTable root(&pool);
ChildTestTable child(&pool, &root);
uint32_t size = static_cast<uint32_t>(state.range(0));
diff --git a/src/trace_processor/tables/py_tables_benchmark.py b/src/trace_processor/tables/py_tables_benchmark.py
new file mode 100644
index 000000000..8a2c1f900
--- /dev/null
+++ b/src/trace_processor/tables/py_tables_benchmark.py
@@ -0,0 +1,48 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Contains tables for unittesting."""
+
+from python.generators.trace_processor_table.public import Column as C
+from python.generators.trace_processor_table.public import ColumnFlag
+from python.generators.trace_processor_table.public import Table
+from python.generators.trace_processor_table.public import CppOptional
+from python.generators.trace_processor_table.public import CppUint32
+
+ROOT_TABLE = Table(
+ python_module=__file__,
+ class_name="RootTestTable",
+ sql_name="root_table",
+ columns=[
+ C("root_sorted", CppUint32(), flags=ColumnFlag.SORTED),
+ C("root_non_null", CppUint32()),
+ C("root_non_null_2", CppUint32()),
+ C("root_nullable", CppOptional(CppUint32())),
+ ])
+
+CHILD_TABLE = Table(
+ python_module=__file__,
+ class_name="ChildTestTable",
+ sql_name="child_table",
+ parent=ROOT_TABLE,
+ columns=[
+ C("child_sorted", CppUint32(), flags=ColumnFlag.SORTED),
+ C("child_non_null", CppUint32()),
+ C("child_nullable", CppOptional(CppUint32())),
+ ])
+
+# Keep this list sorted.
+ALL_TABLES = [
+ ROOT_TABLE,
+ CHILD_TABLE,
+]
diff --git a/src/trace_processor/tables/py_tables_unittest.cc b/src/trace_processor/tables/py_tables_unittest.cc
index 71b5f3947..36facd63d 100644
--- a/src/trace_processor/tables/py_tables_unittest.cc
+++ b/src/trace_processor/tables/py_tables_unittest.cc
@@ -15,6 +15,7 @@
*/
#include "src/trace_processor/db/column.h"
+#include "src/trace_processor/db/column_storage.h"
#include "src/trace_processor/tables/py_tables_unittest_py.h"
#include "test/gtest_and_gmock.h"
@@ -24,6 +25,7 @@ namespace trace_processor {
namespace tables {
TestEventTable::~TestEventTable() = default;
+TestEventChildTable::~TestEventChildTable() = default;
TestSliceTable::~TestSliceTable() = default;
TestArgsTable::~TestArgsTable() = default;
@@ -34,6 +36,7 @@ class PyTablesUnittest : public ::testing::Test {
StringPool pool_;
TestEventTable event_{&pool_};
+ TestEventChildTable event_child_{&pool_, &event_};
TestSliceTable slice_{&pool_, &event_};
TestArgsTable args_{&pool_};
};
@@ -163,6 +166,150 @@ TEST_F(PyTablesUnittest, ParentAndChildInsert) {
ASSERT_EQ(slice_.dur()[1], 20);
}
+TEST_F(PyTablesUnittest, Extend) {
+ event_.Insert(TestEventTable::Row(50, 0));
+ event_.Insert(TestEventTable::Row(100, 1));
+ event_.Insert(TestEventTable::Row(150, 2));
+
+ ColumnStorage<int64_t> dur;
+ dur.Append(512);
+ dur.Append(1024);
+ dur.Append(2048);
+
+ auto slice_ext = TestSliceTable::ExtendParent(event_, std::move(dur));
+ ASSERT_EQ(slice_ext->row_count(), 3u);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::ts].Get(0).AsLong(),
+ 50);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::dur].Get(0).AsLong(),
+ 512);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::ts].Get(1).AsLong(),
+ 100);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::dur].Get(1).AsLong(),
+ 1024);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::ts].Get(2).AsLong(),
+ 150);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::dur].Get(2).AsLong(),
+ 2048);
+}
+
+TEST_F(PyTablesUnittest, SelectAndExtend) {
+ event_.Insert(TestEventTable::Row(50, 0));
+ event_.Insert(TestEventTable::Row(100, 1));
+ event_.Insert(TestEventTable::Row(150, 2));
+
+ std::vector<TestEventTable::RowNumber> rows;
+ rows.emplace_back(TestEventTable::RowNumber(1));
+ ColumnStorage<int64_t> dur;
+ dur.Append(1024);
+
+ auto slice_ext = TestSliceTable::SelectAndExtendParent(
+ event_, std::move(rows), std::move(dur));
+ ASSERT_EQ(slice_ext->row_count(), 1u);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::ts].Get(0).AsLong(),
+ 100);
+ ASSERT_EQ(
+ slice_ext->columns()[TestSliceTable::ColumnIndex::dur].Get(0).AsLong(),
+ 1024);
+}
+
+TEST_F(PyTablesUnittest, SetIdColumns) {
+ StringPool pool;
+ TestArgsTable table{&pool};
+
+ table.Insert(TestArgsTable::Row(0, 100));
+ table.Insert(TestArgsTable::Row(0, 200));
+ table.Insert(TestArgsTable::Row(2, 200));
+ table.Insert(TestArgsTable::Row(3, 300));
+ table.Insert(TestArgsTable::Row(4, 200));
+ table.Insert(TestArgsTable::Row(4, 500));
+ table.Insert(TestArgsTable::Row(4, 900));
+ table.Insert(TestArgsTable::Row(4, 200));
+ table.Insert(TestArgsTable::Row(8, 400));
+
+ ASSERT_EQ(table.row_count(), 9u);
+ ASSERT_TRUE(table.arg_set_id().IsSetId());
+
+ // Verify that not-present ids are not returned.
+ {
+ static constexpr uint32_t kFilterArgSetId = 1;
+ auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
+ ASSERT_EQ(res.row_count(), 0u);
+ }
+ {
+ static constexpr uint32_t kFilterArgSetId = 9;
+ auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
+ ASSERT_EQ(res.row_count(), 0u);
+ }
+
+ // Verify that kSetId flag is correctly removed after filtering/sorting.
+ {
+ static constexpr uint32_t kFilterArgSetId = 3;
+ auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
+ ASSERT_EQ(res.row_count(), 1u);
+ ASSERT_FALSE(res.GetColumnByName("arg_set_id")->IsSetId());
+ }
+ {
+ auto res = table.Sort({table.type().descending()});
+ ASSERT_FALSE(res.GetColumnByName("arg_set_id")->IsSetId());
+ }
+
+ uint32_t arg_set_id_col_idx =
+ static_cast<uint32_t>(TestArgsTable::ColumnIndex::arg_set_id);
+
+ // Verify that filtering equality for real arg set ids works as expected.
+ {
+ static constexpr uint32_t kFilterArgSetId = 4;
+ auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
+ ASSERT_EQ(res.row_count(), 4u);
+ for (auto it = res.IterateRows(); it; it.Next()) {
+ uint32_t arg_set_id =
+ static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
+ ASSERT_EQ(arg_set_id, kFilterArgSetId);
+ }
+ }
+ {
+ static constexpr uint32_t kFilterArgSetId = 0;
+ auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
+ ASSERT_EQ(res.row_count(), 2u);
+ for (auto it = res.IterateRows(); it; it.Next()) {
+ uint32_t arg_set_id =
+ static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
+ ASSERT_EQ(arg_set_id, kFilterArgSetId);
+ }
+ }
+ {
+ static constexpr uint32_t kFilterArgSetId = 8;
+ auto res = table.Filter({table.arg_set_id().eq(kFilterArgSetId)});
+ ASSERT_EQ(res.row_count(), 1u);
+ for (auto it = res.IterateRows(); it; it.Next()) {
+ uint32_t arg_set_id =
+ static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
+ ASSERT_EQ(arg_set_id, kFilterArgSetId);
+ }
+ }
+
+ // Verify that filtering equality for arg set ids after filtering another
+ // column works.
+ {
+ static constexpr uint32_t kFilterArgSetId = 4;
+ auto res = table.Filter(
+ {table.int_value().eq(200), table.arg_set_id().eq(kFilterArgSetId)});
+ ASSERT_EQ(res.row_count(), 2u);
+ for (auto it = res.IterateRows(); it; it.Next()) {
+ uint32_t arg_set_id =
+ static_cast<uint32_t>(it.Get(arg_set_id_col_idx).AsLong());
+ ASSERT_EQ(arg_set_id, kFilterArgSetId);
+ }
+ }
+}
+
} // namespace
} // namespace tables
} // namespace trace_processor
diff --git a/src/trace_processor/tables/py_tables_unittest.py b/src/trace_processor/tables/py_tables_unittest.py
index 24cb17c62..8acc68810 100644
--- a/src/trace_processor/tables/py_tables_unittest.py
+++ b/src/trace_processor/tables/py_tables_unittest.py
@@ -17,40 +17,48 @@ from python.generators.trace_processor_table.public import Column as C
from python.generators.trace_processor_table.public import ColumnFlag
from python.generators.trace_processor_table.public import CppInt64
from python.generators.trace_processor_table.public import Table
-from python.generators.trace_processor_table.public import TableDoc
from python.generators.trace_processor_table.public import CppUint32
EVENT_TABLE = Table(
+ python_module=__file__,
class_name="TestEventTable",
sql_name="event",
columns=[
C("ts", CppInt64(), flags=ColumnFlag.SORTED),
C("arg_set_id", CppUint32()),
- ],
- tabledoc=TableDoc(doc='', group='', columns={}))
+ ])
+
+EVENT_CHILD_TABLE = Table(
+ python_module=__file__,
+ class_name="TestEventChildTable",
+ sql_name="event",
+ parent=EVENT_TABLE,
+ columns=[])
SLICE_TABLE = Table(
+ python_module=__file__,
class_name="TestSliceTable",
sql_name="slice",
parent=EVENT_TABLE,
columns=[
C("dur", CppInt64()),
- ],
- tabledoc=TableDoc(doc='', group='', columns={}))
+ ])
ARGS_TABLE = Table(
+ python_module=__file__,
class_name="TestArgsTable",
sql_name="args",
columns=[
C("arg_set_id",
CppUint32(),
flags=ColumnFlag.SET_ID | ColumnFlag.SORTED),
- ],
- tabledoc=TableDoc(doc='', group='', columns={}))
+ C("int_value", CppInt64()),
+ ])
# Keep this list sorted.
ALL_TABLES = [
ARGS_TABLE,
EVENT_TABLE,
+ EVENT_CHILD_TABLE,
SLICE_TABLE,
]
diff --git a/src/trace_processor/tables/slice_tables.h b/src/trace_processor/tables/slice_tables.h
deleted file mode 100644
index e33ae19af..000000000
--- a/src/trace_processor/tables/slice_tables.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_TABLES_SLICE_TABLES_H_
-#define SRC_TRACE_PROCESSOR_TABLES_SLICE_TABLES_H_
-
-#include "src/trace_processor/tables/macros.h"
-#include "src/trace_processor/tables/track_tables_py.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace tables {
-
-#define PERFETTO_TP_SLICE_TABLE_DEF(NAME, PARENT, C) \
- NAME(SliceTable, "internal_slice") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(int64_t, ts, Column::Flag::kSorted) \
- C(int64_t, dur) \
- C(TrackTable::Id, track_id) \
- C(std::optional<StringPool::Id>, category) \
- C(std::optional<StringPool::Id>, name) \
- C(uint32_t, depth) \
- C(int64_t, stack_id) \
- C(int64_t, parent_stack_id) \
- C(std::optional<SliceTable::Id>, parent_id) \
- C(uint32_t, arg_set_id) \
- C(std::optional<int64_t>, thread_ts) \
- C(std::optional<int64_t>, thread_dur) \
- C(std::optional<int64_t>, thread_instruction_count) \
- C(std::optional<int64_t>, thread_instruction_delta)
-
-#define PERFETTO_TP_SCHED_SLICE_TABLE_DEF(NAME, PARENT, C) \
- NAME(SchedSliceTable, "sched_slice") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(int64_t, ts, Column::Flag::kSorted) \
- C(int64_t, dur) \
- C(uint32_t, cpu) \
- C(uint32_t, utid) \
- C(StringPool::Id, end_state) \
- C(int32_t, priority)
-
-} // namespace tables
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_TABLES_SLICE_TABLES_H_
diff --git a/src/trace_processor/tables/slice_tables.py b/src/trace_processor/tables/slice_tables.py
index 50b8c3edb..f58d53d7e 100644
--- a/src/trace_processor/tables/slice_tables.py
+++ b/src/trace_processor/tables/slice_tables.py
@@ -11,9 +11,10 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Contains tables for relevant for TODO."""
+"""Contains tables for relevant for slices."""
from python.generators.trace_processor_table.public import Column as C
+from python.generators.trace_processor_table.public import ColumnDoc
from python.generators.trace_processor_table.public import ColumnFlag
from python.generators.trace_processor_table.public import CppInt32
from python.generators.trace_processor_table.public import CppInt64
@@ -29,6 +30,7 @@ from python.generators.trace_processor_table.public import WrappingSqlView
from src.trace_processor.tables.track_tables import TRACK_TABLE
SLICE_TABLE = Table(
+ python_module=__file__,
class_name='SliceTable',
sql_name='internal_slice',
columns=[
@@ -49,26 +51,77 @@ SLICE_TABLE = Table(
],
wrapping_sql_view=WrappingSqlView('slice'),
tabledoc=TableDoc(
- doc='''''',
+ doc='''
+ Contains slices from userspace which explains what threads were doing
+ during the trace.
+ ''',
group='Events',
columns={
- 'ts': '''timestamp of the start of the slice (in nanoseconds)''',
- 'dur': '''duration of the slice (in nanoseconds)''',
- 'arg_set_id': '''''',
- 'thread_instruction_count': '''to the end of the slice.''',
- 'thread_instruction_delta': '''The change in value from''',
- 'track_id': '''''',
- 'category': '''''',
- 'name': '''''',
- 'depth': '''''',
- 'stack_id': '''''',
- 'parent_stack_id': '''''',
- 'parent_id': '''''',
- 'thread_ts': '''''',
- 'thread_dur': ''''''
+ 'ts':
+ 'The timestamp at the start of the slice (in nanoseconds).',
+ 'dur':
+ 'The duration of the slice (in nanoseconds).',
+ 'track_id':
+ 'The id of the track this slice is located on.',
+ 'category':
+ '''
+ The "category" of the slice. If this slice originated with
+ track_event, this column contains the category emitted.
+ Otherwise, it is likely to be null (with limited exceptions).
+ ''',
+ 'name':
+ '''
+ The name of the slice. The name describes what was happening
+ during the slice.
+ ''',
+ 'depth':
+ 'The depth of the slice in the current stack of slices.',
+ 'stack_id':
+ '''
+ A unique identifier obtained from the names of all slices
+ in this stack. This is rarely useful and kept around only
+ for legacy reasons.
+ ''',
+ 'parent_stack_id':
+ 'The stack_id for the parent of this slice. Rarely useful.',
+ 'parent_id':
+ '''
+ The id of the parent (i.e. immediate ancestor) slice for this
+ slice
+ ''',
+ 'arg_set_id':
+ ColumnDoc(
+ 'The id of the argument set associated with this slice',
+ joinable='args.arg_set_id'),
+ 'thread_ts':
+ '''
+ The thread timestamp at the start of the slice. This column
+ will only be populated if thread timestamp collection is
+ enabled with track_event.
+ ''',
+ 'thread_dur':
+ ''''
+ The thread time used by this slice. This column will only be
+ populated if thread timestamp collection is enabled with
+ track_event.
+ ''',
+ 'thread_instruction_count':
+ '''
+ The value of the CPU instruction counter at the start of the
+ slice. This column will only be populated if thread
+ instruction collection is enabled with track_event.
+ ''',
+ 'thread_instruction_delta':
+ '''
+ The change in value of the CPU instruction counter between the
+ start and end of the slice. This column will only be
+ populated if thread instruction collection is enabled with
+ track_event.
+ ''',
}))
SCHED_SLICE_TABLE = Table(
+ python_module=__file__,
class_name='SchedSliceTable',
sql_name='sched_slice',
columns=[
@@ -82,8 +135,8 @@ SCHED_SLICE_TABLE = Table(
tabledoc=TableDoc(
doc='''
This table holds slices with kernel thread scheduling information.
-These slices are collected when the Linux "ftrace" data source is
-used with the "sched/switch" and "sched/wakeup*" events enabled.
+ These slices are collected when the Linux "ftrace" data source is
+ used with the "sched/switch" and "sched/wakeup*" events enabled.
''',
group='Events',
columns={
@@ -96,45 +149,69 @@ used with the "sched/switch" and "sched/wakeup*" events enabled.
'cpu':
'''The CPU that the slice executed on.''',
'end_state':
- '''A string representing the scheduling state of the
-kernel thread at the end of the slice. The individual characters in
-the string mean the following: R (runnable), S (awaiting a wakeup),
-D (in an uninterruptible sleep), T (suspended), t (being traced),
-X (exiting), P (parked), W (waking), I (idle), N (not contributing
-to the load average), K (wakeable on fatal signals) and
-Z (zombie, awaiting cleanup).''',
+ '''
+ A string representing the scheduling state of the kernel
+ thread at the end of the slice. The individual characters in
+ the string mean the following: R (runnable), S (awaiting a
+ wakeup), D (in an uninterruptible sleep), T (suspended),
+ t (being traced), X (exiting), P (parked), W (waking),
+ I (idle), N (not contributing to the load average),
+ K (wakeable on fatal signals) and Z (zombie, awaiting
+ cleanup).
+ ''',
'priority':
'''The kernel priority that the thread ran at.'''
}))
THREAD_STATE_TABLE = Table(
+ python_module=__file__,
class_name='ThreadStateTable',
sql_name='thread_state',
columns=[
- C('utid', CppUint32()),
C('ts', CppInt64()),
C('dur', CppInt64()),
C('cpu', CppOptional(CppUint32())),
+ C('utid', CppUint32()),
C('state', CppString()),
C('io_wait', CppOptional(CppUint32())),
C('blocked_function', CppOptional(CppString())),
C('waker_utid', CppOptional(CppUint32())),
],
tabledoc=TableDoc(
- doc='''''',
+ doc='''
+ This table contains the scheduling state of every thread on the
+ system during the trace. It is a subset of the |sched_slice| (sched)
+ table which only contains the times where threads were actually
+ scheduled.
+ ''',
group='Events',
columns={
- 'utid': '''''',
- 'ts': '''''',
- 'dur': '''''',
- 'cpu': '''''',
- 'state': '''''',
- 'io_wait': '''''',
- 'blocked_function': '''''',
- 'waker_utid': ''''''
+ 'ts':
+ 'The timestamp at the start of the slice (in nanoseconds).',
+ 'dur':
+ 'The duration of the slice (in nanoseconds).',
+ 'cpu':
+ '''The CPU that the slice executed on.''',
+ 'utid':
+ '''The thread's unique id in the trace..''',
+ 'state':
+ '''
+ The scheduling state of the thread. Can be "Running" or any
+ of the states described in |sched_slice.end_state|.
+ ''',
+ 'io_wait':
+ 'Indicates whether this thread was blocked on IO.',
+ 'blocked_function':
+ 'The function in the kernel this thread was blocked on.',
+ 'waker_utid':
+ '''
+ The unique thread id of the thread which caused a wakeup of
+ this thread.
+ '''
}))
GPU_SLICE_TABLE = Table(
+ python_module=__file__,
class_name='GpuSliceTable',
sql_name='gpu_slice',
columns=[
@@ -169,6 +246,7 @@ GPU_SLICE_TABLE = Table(
}))
GRAPHICS_FRAME_SLICE_TABLE = Table(
+ python_module=__file__,
class_name='GraphicsFrameSliceTable',
sql_name='frame_slice',
columns=[
@@ -191,6 +269,7 @@ GRAPHICS_FRAME_SLICE_TABLE = Table(
}))
EXPECTED_FRAME_TIMELINE_SLICE_TABLE = Table(
+ python_module=__file__,
class_name='ExpectedFrameTimelineSliceTable',
sql_name='expected_frame_timeline_slice',
columns=[
@@ -202,7 +281,7 @@ EXPECTED_FRAME_TIMELINE_SLICE_TABLE = Table(
parent=SLICE_TABLE,
tabledoc=TableDoc(
doc='''''',
- group='Misc',
+ group='Events',
columns={
'display_frame_token': '''''',
'surface_frame_token': '''''',
@@ -211,6 +290,7 @@ EXPECTED_FRAME_TIMELINE_SLICE_TABLE = Table(
}))
ACTUAL_FRAME_TIMELINE_SLICE_TABLE = Table(
+ python_module=__file__,
class_name='ActualFrameTimelineSliceTable',
sql_name='actual_frame_timeline_slice',
columns=[
@@ -228,7 +308,7 @@ ACTUAL_FRAME_TIMELINE_SLICE_TABLE = Table(
parent=SLICE_TABLE,
tabledoc=TableDoc(
doc='''''',
- group='Misc',
+ group='Events',
columns={
'display_frame_token': '''''',
'surface_frame_token': '''''',
@@ -243,6 +323,7 @@ ACTUAL_FRAME_TIMELINE_SLICE_TABLE = Table(
}))
EXPERIMENTAL_FLAT_SLICE_TABLE = Table(
+ python_module=__file__,
class_name='ExperimentalFlatSliceTable',
sql_name='experimental_flat_slice',
columns=[
@@ -257,18 +338,35 @@ EXPERIMENTAL_FLAT_SLICE_TABLE = Table(
C('end_bound', CppInt64(), flags=ColumnFlag.HIDDEN),
],
tabledoc=TableDoc(
- doc='''''',
+ doc='''
+ An experimental table which "flattens" stacks of slices to contain
+ only the "deepest" slice at any point in time on each track.
+ ''',
group='Misc',
columns={
- 'ts': '''''',
- 'dur': '''''',
- 'track_id': '''''',
- 'category': '''''',
- 'name': '''''',
- 'arg_set_id': '''''',
- 'source_id': '''''',
- 'start_bound': '''''',
- 'end_bound': ''''''
+ 'ts':
+ '''The timestamp at the start of the slice (in nanoseconds).''',
+ 'dur':
+ '''The duration of the slice (in nanoseconds).''',
+ 'track_id':
+ 'The id of the track this slice is located on.',
+ 'category':
+ '''
+ The "category" of the slice. If this slice originated with
+ track_event, this column contains the category emitted.
+ Otherwise, it is likely to be null (with limited exceptions).
+ ''',
+ 'name':
+ '''
+ The name of the slice. The name describes what was happening
+ during the slice.
+ ''',
+ 'arg_set_id':
+ ColumnDoc(
+ 'The id of the argument set associated with this slice',
+ joinable='args.arg_set_id'),
+ 'source_id':
+ 'The id of the slice which this row originated from.',
}))
# Keep this list sorted.
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index 5025ab3fa..3dcf1130f 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -42,6 +42,7 @@ CounterTable::~CounterTable() = default;
// metadata_tables_py.h
RawTable::~RawTable() = default;
+FtraceEventTable::~FtraceEventTable() = default;
ArgTable::~ArgTable() = default;
ExpMissingChromeProcTable::~ExpMissingChromeProcTable() = default;
MetadataTable::~MetadataTable() = default;
diff --git a/src/trace_processor/tables/trace_proto_tables.h b/src/trace_processor/tables/trace_proto_tables.h
deleted file mode 100644
index aa57b593c..000000000
--- a/src/trace_processor/tables/trace_proto_tables.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_TABLES_TRACE_PROTO_TABLES_H_
-#define SRC_TRACE_PROCESSOR_TABLES_TRACE_PROTO_TABLES_H_
-
-#include "src/trace_processor/tables/macros.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace tables {
-
-// Experimental table, subject to arbitrary breaking changes.
-#define PERFETTO_TP_EXPERIMENTAL_PROTO_PATH_TABLE_DEF(NAME, PARENT, C) \
- NAME(ExperimentalProtoPathTable, "experimental_proto_path") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(std::optional<ExperimentalProtoPathTable::Id>, parent_id) \
- C(StringPool::Id, field_type) \
- C(std::optional<StringPool::Id>, field_name) \
- C(std::optional<uint32_t>, arg_set_id)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_EXPERIMENTAL_PROTO_PATH_TABLE_DEF);
-
-#define PERFETTO_TP_EXPERIMENTAL_PROTO_CONTENT_TABLE_DEF(NAME, PARENT, C) \
- NAME(ExperimentalProtoContentTable, "experimental_proto_content") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(StringPool::Id, path) \
- C(ExperimentalProtoPathTable::Id, path_id) \
- C(int64_t, total_size) \
- C(int64_t, size) \
- C(int64_t, count)
-
-PERFETTO_TP_TABLE(PERFETTO_TP_EXPERIMENTAL_PROTO_CONTENT_TABLE_DEF);
-
-} // namespace tables
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_TABLES_TRACE_PROTO_TABLES_H_
diff --git a/src/trace_processor/tables/trace_proto_tables.py b/src/trace_processor/tables/trace_proto_tables.py
index f6f5f9d74..e9c975452 100644
--- a/src/trace_processor/tables/trace_proto_tables.py
+++ b/src/trace_processor/tables/trace_proto_tables.py
@@ -24,6 +24,7 @@ from python.generators.trace_processor_table.public import CppTableId
from python.generators.trace_processor_table.public import CppUint32
EXPERIMENTAL_PROTO_PATH_TABLE = Table(
+ python_module=__file__,
class_name='ExperimentalProtoPathTable',
sql_name='experimental_proto_path',
columns=[
@@ -45,6 +46,7 @@ EXPERIMENTAL_PROTO_PATH_TABLE = Table(
}))
EXPERIMENTAL_PROTO_CONTENT_TABLE = Table(
+ python_module=__file__,
class_name='ExperimentalProtoContentTable',
sql_name='experimental_proto_content',
columns=[
diff --git a/src/trace_processor/tables/track_tables.py b/src/trace_processor/tables/track_tables.py
index bb5a0df9a..3cbce7689 100644
--- a/src/trace_processor/tables/track_tables.py
+++ b/src/trace_processor/tables/track_tables.py
@@ -25,6 +25,7 @@ from python.generators.trace_processor_table.public import CppSelfTableId
from python.generators.trace_processor_table.public import CppUint32
TRACK_TABLE = Table(
+ python_module=__file__,
class_name="TrackTable",
sql_name="track",
columns=[
@@ -62,6 +63,7 @@ TRACK_TABLE = Table(
}))
PROCESS_TRACK_TABLE = Table(
+ python_module=__file__,
class_name="ProcessTrackTable",
sql_name="process_track",
columns=[
@@ -81,6 +83,7 @@ PROCESS_TRACK_TABLE = Table(
}))
THREAD_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='ThreadTrackTable',
sql_name='thread_track',
columns=[
@@ -101,6 +104,7 @@ THREAD_TRACK_TABLE = Table(
}))
CPU_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='CpuTrackTable',
sql_name='cpu_track',
columns=[
@@ -113,6 +117,7 @@ CPU_TRACK_TABLE = Table(
columns={'cpu': 'The CPU associated with this track'}))
GPU_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='GpuTrackTable',
sql_name='gpu_track',
columns=[
@@ -134,6 +139,7 @@ GPU_TRACK_TABLE = Table(
}))
COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='CounterTrackTable',
sql_name='counter_track',
columns=[
@@ -156,6 +162,7 @@ COUNTER_TRACK_TABLE = Table(
}))
THREAD_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='ThreadCounterTrackTable',
sql_name='thread_counter_track',
columns=[
@@ -174,6 +181,7 @@ THREAD_COUNTER_TRACK_TABLE = Table(
}))
PROCESS_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='ProcessCounterTrackTable',
sql_name='process_counter_track',
columns=[
@@ -193,6 +201,7 @@ PROCESS_COUNTER_TRACK_TABLE = Table(
}))
CPU_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='CpuCounterTrackTable',
sql_name='cpu_counter_track',
columns=[
@@ -205,6 +214,7 @@ CPU_COUNTER_TRACK_TABLE = Table(
columns={'cpu': 'The CPU this track is associated with'}))
IRQ_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='IrqCounterTrackTable',
sql_name='irq_counter_track',
columns=[
@@ -217,6 +227,7 @@ IRQ_COUNTER_TRACK_TABLE = Table(
columns={'irq': 'The identifier for the hardirq.'}))
SOFTIRQ_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='SoftirqCounterTrackTable',
sql_name='softirq_counter_track',
columns=[
@@ -229,6 +240,7 @@ SOFTIRQ_COUNTER_TRACK_TABLE = Table(
columns={'softirq': 'The identifier for the softirq.'}))
GPU_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='GpuCounterTrackTable',
sql_name='gpu_counter_track',
columns=[
@@ -241,6 +253,7 @@ GPU_COUNTER_TRACK_TABLE = Table(
columns={'gpu_id': 'The identifier for the GPU.'}))
PERF_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='PerfCounterTrackTable',
sql_name='perf_counter_track',
columns=[
@@ -265,6 +278,7 @@ PERF_COUNTER_TRACK_TABLE = Table(
}))
ENERGY_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='EnergyCounterTrackTable',
sql_name='energy_counter_track',
columns=[
@@ -286,6 +300,7 @@ ENERGY_COUNTER_TRACK_TABLE = Table(
}))
UID_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='UidCounterTrackTable',
sql_name='uid_counter_track',
columns=[
@@ -298,6 +313,7 @@ UID_COUNTER_TRACK_TABLE = Table(
columns={'uid': 'uid of process for which breakdowns are emitted'}))
ENERGY_PER_UID_COUNTER_TRACK_TABLE = Table(
+ python_module=__file__,
class_name='EnergyPerUidCounterTrackTable',
sql_name='energy_per_uid_counter_track',
columns=[
diff --git a/src/trace_processor/tp_metatrace.cc b/src/trace_processor/tp_metatrace.cc
index 79e6dbcc5..bf44dcf4c 100644
--- a/src/trace_processor/tp_metatrace.cc
+++ b/src/trace_processor/tp_metatrace.cc
@@ -24,19 +24,14 @@ namespace {
using ProtoEnum = protos::pbzero::MetatraceCategories;
ProtoEnum MetatraceCategoriesToProtoEnum(MetatraceCategories categories) {
- switch (categories) {
- case MetatraceCategories::TOPLEVEL:
- return ProtoEnum::TOPLEVEL;
- case MetatraceCategories::FUNCTION:
- return ProtoEnum::FUNCTION;
- case MetatraceCategories::QUERY:
- return ProtoEnum::QUERY;
- case MetatraceCategories::ALL:
- return ProtoEnum::ALL;
- case MetatraceCategories::NONE:
- return ProtoEnum::NONE;
- }
- return ProtoEnum::NONE;
+ ProtoEnum result = ProtoEnum::NONE;
+ if (categories & MetatraceCategories::TOPLEVEL)
+ result = static_cast<ProtoEnum>(result | ProtoEnum::TOPLEVEL);
+ if (categories & MetatraceCategories::FUNCTION)
+ result = static_cast<ProtoEnum>(result | ProtoEnum::FUNCTION);
+ if (categories & MetatraceCategories::QUERY)
+ result = static_cast<ProtoEnum>(result | ProtoEnum::QUERY);
+ return result;
}
} // namespace
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index ee3f5d948..f64b1c16c 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -53,9 +53,10 @@
#include "src/trace_processor/prelude/functions/import.h"
#include "src/trace_processor/prelude/functions/layout_functions.h"
#include "src/trace_processor/prelude/functions/pprof_functions.h"
-#include "src/trace_processor/prelude/functions/register_function.h"
+#include "src/trace_processor/prelude/functions/sql_function.h"
#include "src/trace_processor/prelude/functions/sqlite3_str_split.h"
#include "src/trace_processor/prelude/functions/stack_functions.h"
+#include "src/trace_processor/prelude/functions/to_ftrace.h"
#include "src/trace_processor/prelude/functions/utils.h"
#include "src/trace_processor/prelude/functions/window_functions.h"
#include "src/trace_processor/prelude/operators/span_join_operator.h"
@@ -71,9 +72,9 @@
#include "src/trace_processor/prelude/table_functions/experimental_slice_layout.h"
#include "src/trace_processor/prelude/table_functions/table_function.h"
#include "src/trace_processor/prelude/table_functions/view.h"
+#include "src/trace_processor/prelude/tables_views/tables_views.h"
#include "src/trace_processor/sqlite/scoped_db.h"
#include "src/trace_processor/sqlite/sql_stats_table.h"
-#include "src/trace_processor/sqlite/sqlite_raw_table.h"
#include "src/trace_processor/sqlite/sqlite_table.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/sqlite/stats_table.h"
@@ -96,15 +97,6 @@
#include "src/trace_processor/metrics/sql/amalgamated_sql_metrics.h"
#include "src/trace_processor/stdlib/amalgamated_stdlib.h"
-// In Android and Chromium tree builds, we don't have the percentile module.
-// Just don't include it.
-#if PERFETTO_BUILDFLAG(PERFETTO_TP_PERCENTILE)
-// defined in sqlite_src/ext/misc/percentile.c
-extern "C" int sqlite3_percentile_init(sqlite3* db,
- char** error,
- const sqlite3_api_routines* api);
-#endif // PERFETTO_BUILDFLAG(PERFETTO_TP_PERCENTILE)
-
namespace perfetto {
namespace trace_processor {
namespace {
@@ -114,35 +106,17 @@ const char kAllTablesQuery[] =
"* FROM sqlite_temp_master)";
template <typename SqlFunction, typename Ptr = typename SqlFunction::Context*>
-void RegisterFunction(sqlite3* db,
+void RegisterFunction(SqliteEngine* engine,
const char* name,
int argc,
Ptr context = nullptr,
bool deterministic = true) {
- auto status = RegisterSqlFunction<SqlFunction>(
- db, name, argc, std::move(context), deterministic);
+ auto status = engine->RegisterSqlFunction<SqlFunction>(
+ name, argc, std::move(context), deterministic);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
}
-void InitializeSqlite(sqlite3* db) {
- char* error = nullptr;
- sqlite3_exec(db, "PRAGMA temp_store=2", nullptr, nullptr, &error);
- if (error) {
- PERFETTO_FATAL("Error setting pragma temp_store: %s", error);
- }
- sqlite3_str_split_init(db);
-// In Android tree builds, we don't have the percentile module.
-// Just don't include it.
-#if PERFETTO_BUILDFLAG(PERFETTO_TP_PERCENTILE)
- sqlite3_percentile_init(db, &error, nullptr);
- if (error) {
- PERFETTO_ELOG("Error initializing: %s", error);
- sqlite3_free(error);
- }
-#endif
-}
-
void BuildBoundsTable(sqlite3* db, std::pair<int64_t, int64_t> bounds) {
char* error = nullptr;
sqlite3_exec(db, "DELETE FROM trace_bounds", nullptr, nullptr, &error);
@@ -152,167 +126,16 @@ void BuildBoundsTable(sqlite3* db, std::pair<int64_t, int64_t> bounds) {
return;
}
- char* insert_sql = sqlite3_mprintf("INSERT INTO trace_bounds VALUES(%" PRId64
- ", %" PRId64 ")",
- bounds.first, bounds.second);
-
- sqlite3_exec(db, insert_sql, nullptr, nullptr, &error);
- sqlite3_free(insert_sql);
+ base::StackString<1024> sql("INSERT INTO trace_bounds VALUES(%" PRId64
+ ", %" PRId64 ")",
+ bounds.first, bounds.second);
+ sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &error);
if (error) {
PERFETTO_ELOG("Error inserting bounds table: %s", error);
sqlite3_free(error);
}
}
-void CreateBuiltinTables(sqlite3* db) {
- char* error = nullptr;
- sqlite3_exec(db, "CREATE TABLE perfetto_tables(name STRING)", nullptr,
- nullptr, &error);
- if (error) {
- PERFETTO_ELOG("Error initializing: %s", error);
- sqlite3_free(error);
- }
- sqlite3_exec(db, "CREATE TABLE trace_bounds(start_ts BIGINT, end_ts BIGINT)",
- nullptr, nullptr, &error);
- if (error) {
- PERFETTO_ELOG("Error initializing: %s", error);
- sqlite3_free(error);
- }
- // Ensure that the entries in power_profile are unique to prevent duplicates
- // when the power_profile is augmented with additional profiles.
- sqlite3_exec(db,
- "CREATE TABLE power_profile("
- "device STRING, cpu INT, cluster INT, freq INT, power DOUBLE,"
- "UNIQUE(device, cpu, cluster, freq));",
- nullptr, nullptr, &error);
- if (error) {
- PERFETTO_ELOG("Error initializing: %s", error);
- sqlite3_free(error);
- }
- sqlite3_exec(db, "CREATE TABLE trace_metrics(name STRING)", nullptr, nullptr,
- &error);
- if (error) {
- PERFETTO_ELOG("Error initializing: %s", error);
- sqlite3_free(error);
- }
- // This is a table intended to be used for metric debugging/developing. Data
- // in the table is shown specially in the UI, and users can insert rows into
- // this table to draw more things.
- sqlite3_exec(db,
- "CREATE TABLE debug_slices (id BIGINT, name STRING, ts BIGINT,"
- "dur BIGINT, depth BIGINT)",
- nullptr, nullptr, &error);
- if (error) {
- PERFETTO_ELOG("Error initializing: %s", error);
- sqlite3_free(error);
- }
-
- // Initialize the bounds table with some data so even before parsing any data,
- // we still have a valid table.
- BuildBoundsTable(db, std::make_pair(0, 0));
-}
-
-void MaybeRegisterError(char* error) {
- if (error) {
- PERFETTO_ELOG("Error initializing: %s", error);
- sqlite3_free(error);
- }
-}
-
-void CreateBuiltinViews(sqlite3* db) {
- char* error = nullptr;
- sqlite3_exec(db,
- "CREATE VIEW counters AS "
- "SELECT * "
- "FROM counter v "
- "JOIN counter_track t "
- "ON v.track_id = t.id "
- "ORDER BY ts;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- sqlite3_exec(db,
- "CREATE VIEW slice AS "
- "SELECT "
- " *, "
- " category AS cat, "
- " id AS slice_id "
- "FROM internal_slice;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- sqlite3_exec(db,
- "CREATE VIEW instant AS "
- "SELECT "
- "ts, track_id, name, arg_set_id "
- "FROM slice "
- "WHERE dur = 0;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- sqlite3_exec(db,
- "CREATE VIEW sched AS "
- "SELECT "
- "*, "
- "ts + dur as ts_end "
- "FROM sched_slice;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- sqlite3_exec(db,
- "CREATE VIEW slices AS "
- "SELECT * FROM slice;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- sqlite3_exec(db,
- "CREATE VIEW thread AS "
- "SELECT "
- "id as utid, "
- "* "
- "FROM internal_thread;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- sqlite3_exec(db,
- "CREATE VIEW process AS "
- "SELECT "
- "id as upid, "
- "* "
- "FROM internal_process;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- // This should be kept in sync with GlobalArgsTracker::AddArgSet.
- sqlite3_exec(db,
- "CREATE VIEW args AS "
- "SELECT "
- "*, "
- "CASE value_type "
- " WHEN 'int' THEN CAST(int_value AS text) "
- " WHEN 'uint' THEN CAST(int_value AS text) "
- " WHEN 'string' THEN string_value "
- " WHEN 'real' THEN CAST(real_value AS text) "
- " WHEN 'pointer' THEN printf('0x%x', int_value) "
- " WHEN 'bool' THEN ( "
- " CASE WHEN int_value <> 0 THEN 'true' "
- " ELSE 'false' END) "
- " WHEN 'json' THEN string_value "
- "ELSE NULL END AS display_value "
- "FROM internal_args;",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-
- sqlite3_exec(db,
- "CREATE VIEW ftrace_event AS "
- "SELECT * FROM raw "
- "WHERE "
- " name NOT LIKE 'chrome_event.%' AND"
- " name NOT LIKE 'track_event.%'",
- nullptr, nullptr, &error);
- MaybeRegisterError(error);
-}
-
struct ValueAtMaxTsContext {
bool initialized;
int value_type;
@@ -415,7 +238,7 @@ std::vector<std::string> SanitizeMetricMountPaths(
}
void SetupMetrics(TraceProcessor* tp,
- sqlite3* db,
+ SqliteEngine* engine,
std::vector<metrics::SqlMetricFile>* sql_metrics,
const std::vector<std::string>& extension_paths) {
const std::vector<std::string> sanitized_extension_paths =
@@ -445,10 +268,11 @@ void SetupMetrics(TraceProcessor* tp,
}
}
- RegisterFunction<metrics::NullIfEmpty>(db, "NULL_IF_EMPTY", 1);
- RegisterFunction<metrics::UnwrapMetricProto>(db, "UNWRAP_METRIC_PROTO", 2);
+ RegisterFunction<metrics::NullIfEmpty>(engine, "NULL_IF_EMPTY", 1);
+ RegisterFunction<metrics::UnwrapMetricProto>(engine, "UNWRAP_METRIC_PROTO",
+ 2);
RegisterFunction<metrics::RunMetric>(
- db, "RUN_METRIC", -1,
+ engine, "RUN_METRIC", -1,
std::unique_ptr<metrics::RunMetric::Context>(
new metrics::RunMetric::Context{tp, sql_metrics}));
@@ -456,21 +280,13 @@ void SetupMetrics(TraceProcessor* tp,
// functions are supported.
{
auto ret = sqlite3_create_function_v2(
- db, "RepeatedField", 1, SQLITE_UTF8, nullptr, nullptr,
+ engine->db(), "RepeatedField", 1, SQLITE_UTF8, nullptr, nullptr,
metrics::RepeatedFieldStep, metrics::RepeatedFieldFinal, nullptr);
if (ret)
PERFETTO_FATAL("Error initializing RepeatedField");
}
}
-void EnsureSqliteInitialized() {
- // sqlite3_initialize isn't actually thread-safe despite being documented
- // as such; we need to make sure multiple TraceProcessorImpl instances don't
- // call it concurrently and only gets called once per process, instead.
- static bool init_once = [] { return sqlite3_initialize() == SQLITE_OK; }();
- PERFETTO_CHECK(init_once);
-}
-
void InsertIntoTraceMetricsTable(sqlite3* db, const std::string& metric_name) {
char* insert_sql = sqlite3_mprintf(
"INSERT INTO trace_metrics(name) VALUES('%q')", metric_name.c_str());
@@ -639,8 +455,8 @@ const char* TraceTypeToString(TraceType trace_type) {
}
// Register SQL functions only used in local development instances.
-void RegisterDevFunctions(sqlite3* db) {
- RegisterFunction<WriteFile>(db, "WRITE_FILE", 2);
+void RegisterDevFunctions(SqliteEngine* engine) {
+ RegisterFunction<WriteFile>(engine, "WRITE_FILE", 2);
}
sql_modules::NameToModule GetStdlibModules() {
@@ -653,6 +469,17 @@ sql_modules::NameToModule GetStdlibModules() {
return modules;
}
+void InitializePreludeTablesViews(sqlite3* db) {
+ for (const auto& file_to_sql : prelude::tables_views::kFileToSql) {
+ char* errmsg_raw = nullptr;
+ int err = sqlite3_exec(db, file_to_sql.sql, nullptr, nullptr, &errmsg_raw);
+ ScopedSqliteString errmsg(errmsg_raw);
+ if (err != SQLITE_OK) {
+ PERFETTO_FATAL("Failed to initialize prelude %s", errmsg_raw);
+ }
+ }
+}
+
} // namespace
template <typename View>
@@ -685,65 +512,78 @@ TraceProcessorImpl::TraceProcessorImpl(const Config& cfg)
context_.content_analyzer.reset(new ProtoContentAnalyzer(&context_));
}
+ sqlite3_str_split_init(engine_.db());
RegisterAdditionalModules(&context_);
- sqlite3* db = nullptr;
- EnsureSqliteInitialized();
- PERFETTO_CHECK(sqlite3_open(":memory:", &db) == SQLITE_OK);
- InitializeSqlite(db);
- CreateBuiltinTables(db);
- CreateBuiltinViews(db);
- db_.reset(std::move(db));
-
// New style function registration.
if (cfg.enable_dev_features) {
- RegisterDevFunctions(db);
+ RegisterDevFunctions(&engine_);
}
- RegisterFunction<Glob>(db, "glob", 2);
- RegisterFunction<Hash>(db, "HASH", -1);
- RegisterFunction<Base64Encode>(db, "BASE64_ENCODE", 1);
- RegisterFunction<Demangle>(db, "DEMANGLE", 1);
- RegisterFunction<SourceGeq>(db, "SOURCE_GEQ", -1);
- RegisterFunction<ExportJson>(db, "EXPORT_JSON", 1, context_.storage.get(),
- false);
- RegisterFunction<ExtractArg>(db, "EXTRACT_ARG", 2, context_.storage.get());
- RegisterFunction<AbsTimeStr>(db, "ABS_TIME_STR", 1,
+ RegisterFunction<Glob>(&engine_, "glob", 2);
+ RegisterFunction<Hash>(&engine_, "HASH", -1);
+ RegisterFunction<Base64Encode>(&engine_, "BASE64_ENCODE", 1);
+ RegisterFunction<Demangle>(&engine_, "DEMANGLE", 1);
+ RegisterFunction<SourceGeq>(&engine_, "SOURCE_GEQ", -1);
+ RegisterFunction<ExportJson>(&engine_, "EXPORT_JSON", 1,
+ context_.storage.get(), false);
+ RegisterFunction<ExtractArg>(&engine_, "EXTRACT_ARG", 2,
+ context_.storage.get());
+ RegisterFunction<AbsTimeStr>(&engine_, "ABS_TIME_STR", 1,
context_.clock_converter.get());
- RegisterFunction<ToMonotonic>(db, "TO_MONOTONIC", 1,
+ RegisterFunction<ToMonotonic>(&engine_, "TO_MONOTONIC", 1,
context_.clock_converter.get());
- RegisterFunction<CreateFunction>(
- db, "CREATE_FUNCTION", 3,
- std::unique_ptr<CreateFunction::Context>(
- new CreateFunction::Context{db_.get(), &create_function_state_}));
+ RegisterFunction<CreateFunction>(&engine_, "CREATE_FUNCTION", 3, &engine_);
RegisterFunction<CreateViewFunction>(
- db, "CREATE_VIEW_FUNCTION", 3,
+ &engine_, "CREATE_VIEW_FUNCTION", 3,
std::unique_ptr<CreateViewFunction::Context>(
- new CreateViewFunction::Context{db_.get()}));
- RegisterFunction<Import>(db, "IMPORT", 1,
+ new CreateViewFunction::Context{engine_.db()}));
+ RegisterFunction<Import>(&engine_, "IMPORT", 1,
std::unique_ptr<Import::Context>(new Import::Context{
- db_.get(), this, &sql_modules_}));
+ engine_.db(), this, &sql_modules_}));
+ RegisterFunction<ToFtrace>(
+ &engine_, "TO_FTRACE", 1,
+ std::unique_ptr<ToFtrace::Context>(new ToFtrace::Context{
+ context_.storage.get(), SystraceSerializer(&context_)}));
// Old style function registration.
// TODO(lalitm): migrate this over to using RegisterFunction once aggregate
// functions are supported.
- RegisterLastNonNullFunction(db);
- RegisterValueAtMaxTsFunction(db);
+ RegisterLastNonNullFunction(engine_.db());
+ RegisterValueAtMaxTsFunction(engine_.db());
{
- base::Status status = RegisterStackFunctions(db, &context_);
+ base::Status status = RegisterStackFunctions(&engine_, &context_);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
}
{
- base::Status status = PprofFunctions::Register(db, &context_);
+ base::Status status = PprofFunctions::Register(engine_.db(), &context_);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
}
{
- base::Status status = LayoutFunctions::Register(db, &context_);
+ base::Status status = LayoutFunctions::Register(engine_.db(), &context_);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
}
+ const TraceStorage* storage = context_.storage.get();
+
+ // Operator tables.
+ engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
+ "span_join", storage, SqliteTable::TableType::kExplicitCreate, false);
+ engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
+ "span_left_join", storage, SqliteTable::TableType::kExplicitCreate,
+ false);
+ engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
+ "span_outer_join", storage, SqliteTable::TableType::kExplicitCreate,
+ false);
+ engine_.RegisterVirtualTableModule<WindowOperatorTable>(
+ "window", storage, SqliteTable::TableType::kExplicitCreate, true);
+ RegisterCreateViewFunctionModule(&engine_);
+
+ // Initalize the tables and views in the prelude.
+ InitializePreludeTablesViews(engine_.db());
+
auto stdlib_modules = GetStdlibModules();
for (auto module_it = stdlib_modules.GetIterator(); module_it; ++module_it) {
base::Status status =
@@ -752,23 +592,13 @@ TraceProcessorImpl::TraceProcessorImpl(const Config& cfg)
PERFETTO_ELOG("%s", status.c_message());
}
- SetupMetrics(this, *db_, &sql_metrics_, cfg.skip_builtin_metric_paths);
-
- // Setup the query cache.
- query_cache_.reset(new QueryCache());
-
- const TraceStorage* storage = context_.storage.get();
-
- SqlStatsTable::RegisterTable(*db_, storage);
- StatsTable::RegisterTable(*db_, storage);
-
- // Operator tables.
- SpanJoinOperatorTable::RegisterTable(*db_, storage);
- WindowOperatorTable::RegisterTable(*db_, storage);
- CreateViewFunction::RegisterTable(*db_);
+ SetupMetrics(this, &engine_, &sql_metrics_, cfg.skip_builtin_metric_paths);
- // New style tables but with some custom logic.
- SqliteRawTable::RegisterTable(*db_, query_cache_.get(), &context_);
+ // Legacy tables.
+ engine_.RegisterVirtualTableModule<SqlStatsTable>(
+ "sqlstats", storage, SqliteTable::TableType::kEponymousOnly, false);
+ engine_.RegisterVirtualTableModule<StatsTable>(
+ "stats", storage, SqliteTable::TableType::kEponymousOnly, false);
// Tables dynamically generated at query time.
RegisterTableFunction(std::unique_ptr<ExperimentalFlamegraph>(
@@ -810,6 +640,8 @@ TraceProcessorImpl::TraceProcessorImpl(const Config& cfg)
// (O(rows in sched/slice/counter)), then consider calling ShrinkToFit on
// that table in TraceStorage::ShrinkToFitTables.
RegisterDbTable(storage->arg_table());
+ RegisterDbTable(storage->raw_table());
+ RegisterDbTable(storage->ftrace_event_table());
RegisterDbTable(storage->thread_table());
RegisterDbTable(storage->process_table());
RegisterDbTable(storage->filedescriptor_table());
@@ -911,7 +743,7 @@ void TraceProcessorImpl::Flush() {
context_.storage->InternString(TraceTypeToString(context_.trace_type));
context_.metadata_tracker->SetMetadata(metadata::trace_type,
Variadic::String(trace_type_id));
- BuildBoundsTable(*db_, context_.storage->GetTraceTimestampBoundsNs());
+ BuildBoundsTable(engine_.db(), context_.storage->GetTraceTimestampBoundsNs());
}
void TraceProcessorImpl::NotifyEndOfFile() {
@@ -949,7 +781,7 @@ void TraceProcessorImpl::NotifyEndOfFile() {
// TraceProcessorStorageImpl::NotifyEndOfFile, this will be counted in
// trace bounds: this is important for parsers like ninja which wait until
// the end to flush all their data.
- BuildBoundsTable(*db_, context_.storage->GetTraceTimestampBoundsNs());
+ BuildBoundsTable(engine_.db(), context_.storage->GetTraceTimestampBoundsNs());
TraceProcessorStorageImpl::DestroyContext();
}
@@ -996,19 +828,20 @@ Iterator TraceProcessorImpl::ExecuteQuery(const std::string& sql) {
ScopedStmt stmt;
IteratorImpl::StmtMetadata metadata;
base::Status status =
- PrepareAndStepUntilLastValidStmt(*db_, sql, &stmt, &metadata);
+ PrepareAndStepUntilLastValidStmt(engine_.db(), sql, &stmt, &metadata);
PERFETTO_DCHECK((status.ok() && stmt) || (!status.ok() && !stmt));
- std::unique_ptr<IteratorImpl> impl(new IteratorImpl(
- this, *db_, status, std::move(stmt), std::move(metadata), sql_stats_row));
+ std::unique_ptr<IteratorImpl> impl(
+ new IteratorImpl(this, engine_.db(), status, std::move(stmt),
+ std::move(metadata), sql_stats_row));
return Iterator(std::move(impl));
}
void TraceProcessorImpl::InterruptQuery() {
- if (!db_)
+ if (!engine_.db())
return;
query_interrupted_.store(true);
- sqlite3_interrupt(db_.get());
+ sqlite3_interrupt(engine_.db());
}
bool TraceProcessorImpl::IsRootMetricField(const std::string& metric_name) {
@@ -1100,7 +933,7 @@ base::Status TraceProcessorImpl::RegisterMetric(const std::string& path,
prev_path.c_str(), path.c_str(), metric.proto_field_name->c_str());
}
- InsertIntoTraceMetricsTable(*db_, no_ext_name);
+ InsertIntoTraceMetricsTable(engine_.db(), no_ext_name);
}
sql_metrics_.emplace_back(metric);
@@ -1128,7 +961,7 @@ base::Status TraceProcessorImpl::ExtendMetricsProto(
auto fn_name = desc.full_name().substr(desc.package_name().size() + 1);
std::replace(fn_name.begin(), fn_name.end(), '.', '_');
RegisterFunction<metrics::BuildProto>(
- db_.get(), fn_name.c_str(), -1,
+ &engine_, fn_name.c_str(), -1,
std::unique_ptr<metrics::BuildProto::Context>(
new metrics::BuildProto::Context{this, &pool_, i}));
}
diff --git a/src/trace_processor/trace_processor_impl.h b/src/trace_processor/trace_processor_impl.h
index 37e7a2cf4..21cbd9289 100644
--- a/src/trace_processor/trace_processor_impl.h
+++ b/src/trace_processor/trace_processor_impl.h
@@ -36,6 +36,7 @@
#include "src/trace_processor/sqlite/db_sqlite_table.h"
#include "src/trace_processor/sqlite/query_cache.h"
#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "src/trace_processor/trace_processor_storage_impl.h"
#include "src/trace_processor/util/sql_modules.h"
@@ -107,13 +108,11 @@ class TraceProcessorImpl : public TraceProcessor,
template <typename Table>
void RegisterDbTable(const Table& table) {
- DbSqliteTable::RegisterTable(*db_, query_cache_.get(), &table,
- Table::Name());
+ engine_.RegisterTable(table, Table::Name());
}
- void RegisterTableFunction(std::unique_ptr<TableFunction> generator) {
- DbSqliteTable::RegisterTable(*db_, query_cache_.get(),
- std::move(generator));
+ void RegisterTableFunction(std::unique_ptr<TableFunction> fn) {
+ engine_.RegisterTableFunction(std::move(fn));
}
template <typename View>
@@ -121,15 +120,7 @@ class TraceProcessorImpl : public TraceProcessor,
bool IsRootMetricField(const std::string& metric_name);
- // Keep this first: we need this to be destroyed after we clean up
- // everything else.
- ScopedDb db_;
-
- // State necessary for CREATE_FUNCTION invocations. We store this here as we
- // need to finalize any prepared statements *before* we destroy the database.
- CreateFunction::State create_function_state_;
-
- std::unique_ptr<QueryCache> query_cache_;
+ SqliteEngine engine_;
DescriptorPool pool_;
diff --git a/src/trace_processor/types/BUILD.gn b/src/trace_processor/types/BUILD.gn
index ba26e2424..0605ea1bc 100644
--- a/src/trace_processor/types/BUILD.gn
+++ b/src/trace_processor/types/BUILD.gn
@@ -23,7 +23,6 @@ source_set("types") {
"task_state.h",
"tcp_state.h",
"trace_processor_context.h",
- "variadic.cc",
"variadic.h",
"version_number.h",
]
diff --git a/src/trace_processor/util/status_macros.h b/src/trace_processor/util/status_macros.h
index 50e2bb4d0..2acb79947 100644
--- a/src/trace_processor/util/status_macros.h
+++ b/src/trace_processor/util/status_macros.h
@@ -23,7 +23,7 @@
// error status, returns the status from the current function.
#define RETURN_IF_ERROR(expr) \
do { \
- util::Status status_macro_internal_status = (expr); \
+ base::Status status_macro_internal_status = (expr); \
if (!status_macro_internal_status.ok()) \
return status_macro_internal_status; \
} while (0)
diff --git a/src/trace_processor/views/BUILD.gn b/src/trace_processor/views/BUILD.gn
index 7cd540887..604a4bb24 100644
--- a/src/trace_processor/views/BUILD.gn
+++ b/src/trace_processor/views/BUILD.gn
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import("../../../gn/perfetto_tp_tables.gni")
import("../../../gn/test.gni")
source_set("views") {
@@ -28,10 +29,15 @@ source_set("views") {
]
}
+perfetto_tp_tables("macros_unittest") {
+ sources = [ "macros_unittest.py" ]
+}
+
source_set("unittests") {
testonly = true
sources = [ "macros_unittest.cc" ]
deps = [
+ ":macros_unittest",
":views",
"../../../gn:default_deps",
"../../../gn:gtest_and_gmock",
diff --git a/src/trace_processor/views/macros_internal.h b/src/trace_processor/views/macros_internal.h
index 69f4f9058..ca161372f 100644
--- a/src/trace_processor/views/macros_internal.h
+++ b/src/trace_processor/views/macros_internal.h
@@ -16,8 +16,6 @@
#include "src/trace_processor/db/view.h"
-#include "src/trace_processor/tables/macros_internal.h"
-
#ifndef SRC_TRACE_PROCESSOR_VIEWS_MACROS_INTERNAL_H_
#define SRC_TRACE_PROCESSOR_VIEWS_MACROS_INTERNAL_H_
@@ -73,6 +71,15 @@ class ViewColumnBlueprint {
#pragma GCC system_header
#endif
+// Basic helper macros.
+#define PERFETTO_TP_NOOP(...)
+
+// Invokes FN on each column in the definition of the table. We define a
+// recursive macro as we need to walk up the hierarchy until we hit the root.
+// Currently, we hardcode 5 levels but this can be increased as necessary.
+#define PERFETTO_TP_ALL_COLUMNS(DEF, arg) \
+ DEF(PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, arg)
+
// Invokes a View column function using data from a table column definition.
#define PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE(FN, col_name) \
FN(col_name, from_table, col_name)
diff --git a/src/trace_processor/views/macros_unittest.cc b/src/trace_processor/views/macros_unittest.cc
index 89c77343f..dc4d697ff 100644
--- a/src/trace_processor/views/macros_unittest.cc
+++ b/src/trace_processor/views/macros_unittest.cc
@@ -16,38 +16,30 @@
#include "src/trace_processor/views/macros.h"
+#include "src/trace_processor/views/macros_unittest_py.h"
#include "test/gtest_and_gmock.h"
-#include "src/trace_processor/tables/macros.h"
-
namespace perfetto {
namespace trace_processor {
-namespace {
-
-#define PERFETTO_TP_TEST_THREAD_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestThreadTable, "thread") \
- PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
- C(StringPool::Id, name) \
- C(int64_t, start_ts, Column::Flag::kSorted)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_THREAD_TABLE_DEF);
+namespace tables {
#define PERFETTO_TP_TEST_EVENT_TABLE_DEF(NAME, PARENT, C) \
- NAME(TestEventTable, "event") \
- PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
+ NAME(MacrosEventTable, "event") \
C(int64_t, ts, Column::Flag::kSorted) \
- C(TestThreadTable::Id, thread_id)
-PERFETTO_TP_TABLE(PERFETTO_TP_TEST_EVENT_TABLE_DEF);
+ C(MacrosThreadTable::Id, thread_id)
-TestEventTable::~TestEventTable() = default;
-TestThreadTable::~TestThreadTable() = default;
+MacrosEventTable::~MacrosEventTable() = default;
+MacrosThreadTable::~MacrosThreadTable() = default;
+
+namespace {
#define PERFETTO_TP_EVENT_VIEW_DEF(NAME, FROM, JOIN, COL, FCOL) \
NAME(TestEventView, "event_view") \
PERFETTO_TP_VIEW_EXPORT_FROM_COLS(PERFETTO_TP_TEST_EVENT_TABLE_DEF, FCOL) \
COL(thread_name, thread, name) \
COL(thread_start_ts, thread, start_ts) \
- FROM(TestEventTable, event) \
- JOIN(TestThreadTable, thread, id, event, thread_id, View::kIdAlwaysPresent)
+ FROM(MacrosEventTable, event) \
+ JOIN(MacrosThreadTable, thread, id, event, thread_id, View::kIdAlwaysPresent)
PERFETTO_TP_DECLARE_VIEW(PERFETTO_TP_EVENT_VIEW_DEF);
PERFETTO_TP_DEFINE_VIEW(TestEventView);
@@ -72,8 +64,8 @@ TEST(ViewMacrosUnittest, ColIdx) {
}
TEST(ViewMacrosUnittest, Schema) {
- TestThreadTable thread{nullptr, nullptr};
- TestEventTable event{nullptr, nullptr};
+ MacrosThreadTable thread{nullptr};
+ MacrosEventTable event{nullptr};
TestEventView view{&event, &thread};
auto schema = view.schema();
@@ -98,5 +90,6 @@ TEST(ViewMacrosUnittest, Schema) {
}
} // namespace
+} // namespace tables
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/views/macros_unittest.py b/src/trace_processor/views/macros_unittest.py
new file mode 100644
index 000000000..96606e0e9
--- /dev/null
+++ b/src/trace_processor/views/macros_unittest.py
@@ -0,0 +1,45 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Contains tables for unittesting."""
+
+from python.generators.trace_processor_table.public import Column as C
+from python.generators.trace_processor_table.public import ColumnFlag
+from python.generators.trace_processor_table.public import CppInt64
+from python.generators.trace_processor_table.public import Table
+from python.generators.trace_processor_table.public import CppString
+from python.generators.trace_processor_table.public import CppTableId
+
+MACROS_THREAD_TABLE = Table(
+ python_module=__file__,
+ class_name="MacrosThreadTable",
+ sql_name="thread",
+ columns=[
+ C("name", CppString()),
+ C("start_ts", CppInt64(), flags=ColumnFlag.SORTED),
+ ])
+
+MACROS_EVENT_TABLE = Table(
+ python_module=__file__,
+ class_name="MacrosEventTable",
+ sql_name="event",
+ columns=[
+ C("ts", CppInt64(), flags=ColumnFlag.SORTED),
+ C("thread_id", CppTableId(MACROS_THREAD_TABLE)),
+ ])
+
+# Keep this list sorted.
+ALL_TABLES = [
+ MACROS_THREAD_TABLE,
+ MACROS_EVENT_TABLE,
+]
diff --git a/src/trace_processor/views/slice_views.h b/src/trace_processor/views/slice_views.h
index 287fd02b2..53dd896ff 100644
--- a/src/trace_processor/views/slice_views.h
+++ b/src/trace_processor/views/slice_views.h
@@ -19,7 +19,6 @@
#include "src/trace_processor/db/view.h"
#include "src/trace_processor/tables/metadata_tables_py.h"
-#include "src/trace_processor/tables/slice_tables.h"
#include "src/trace_processor/tables/slice_tables_py.h"
#include "src/trace_processor/tables/track_tables_py.h"
#include "src/trace_processor/views/macros.h"
@@ -28,6 +27,23 @@ namespace perfetto {
namespace trace_processor {
namespace views {
+#define PERFETTO_TP_SLICE_TABLE_DEF(NAME, PARENT, C) \
+ NAME(SliceTable, "internal_slice") \
+ C(int64_t, ts, Column::Flag::kSorted) \
+ C(int64_t, dur) \
+ C(TrackTable::Id, track_id) \
+ C(std::optional<StringPool::Id>, category) \
+ C(std::optional<StringPool::Id>, name) \
+ C(uint32_t, depth) \
+ C(int64_t, stack_id) \
+ C(int64_t, parent_stack_id) \
+ C(std::optional<SliceTable::Id>, parent_id) \
+ C(uint32_t, arg_set_id) \
+ C(std::optional<int64_t>, thread_ts) \
+ C(std::optional<int64_t>, thread_dur) \
+ C(std::optional<int64_t>, thread_instruction_count) \
+ C(std::optional<int64_t>, thread_instruction_delta)
+
// TODO(lalitm): add support in document generator for views.
#define PERFETTO_TP_THREAD_SLICE_VIEW_DEF(NAME, FROM, JOIN, COL, FCOL) \
NAME(ThreadSliceView, "exp_thread_slice") \
diff --git a/src/traceconv/trace_to_systrace.cc b/src/traceconv/trace_to_systrace.cc
index 6b2f3802e..e3494e837 100644
--- a/src/traceconv/trace_to_systrace.cc
+++ b/src/traceconv/trace_to_systrace.cc
@@ -33,9 +33,6 @@
#include "perfetto/trace_processor/trace_processor.h"
#include "src/traceconv/utils.h"
-#define FILTER_RAW_EVENTS \
- " where not (name like \"chrome_event.%\" or name like \"track_event.%\")"
-
namespace perfetto {
namespace trace_to_text {
@@ -168,8 +165,7 @@ int ExtractRawEvents(TraceWriter* trace_writer,
Keep truncate_keep) {
using trace_processor::Iterator;
- static const char kRawEventsCountSql[] =
- "select count(1) from raw" FILTER_RAW_EVENTS;
+ static const char kRawEventsCountSql[] = "select count(1) from ftrace_event";
uint32_t raw_events = 0;
auto e_callback = [&raw_events](Iterator* it, base::StringWriter*) {
raw_events = static_cast<uint32_t>(it->Get(0).long_value);
@@ -235,7 +231,7 @@ int ExtractRawEvents(TraceWriter* trace_writer,
const uint32_t max_ftrace_events = (140 * 1024 * 1024) / 130;
static const char kRawEventsQuery[] =
- "select to_ftrace(id) from raw" FILTER_RAW_EVENTS;
+ "select to_ftrace(id) from ftrace_event";
// 1. Write the appropriate header for the file type.
if (wrapped_in_json) {
diff --git a/src/traced/probes/ftrace/cpu_reader_unittest.cc b/src/traced/probes/ftrace/cpu_reader_unittest.cc
index 459b64081..859cc8bf1 100644
--- a/src/traced/probes/ftrace/cpu_reader_unittest.cc
+++ b/src/traced/probes/ftrace/cpu_reader_unittest.cc
@@ -34,6 +34,7 @@
#include "test/gtest_and_gmock.h"
#include "protos/perfetto/trace/ftrace/dpu.gen.h"
+#include "protos/perfetto/trace/ftrace/f2fs.gen.h"
#include "protos/perfetto/trace/ftrace/ftrace.gen.h"
#include "protos/perfetto/trace/ftrace/ftrace_event.gen.h"
#include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
@@ -62,6 +63,7 @@ using testing::Not;
using testing::Pair;
using testing::Property;
using testing::Return;
+using testing::SizeIs;
using testing::StartsWith;
namespace perfetto {
@@ -3303,5 +3305,113 @@ TEST_F(CpuReaderParsePagePayloadTest, ZeroPaddedPageWorkaround) {
EXPECT_THAT(AllTracePackets(), IsEmpty());
}
+// Kernel code:
+// trace_f2fs_truncate_partial_nodes(... nid = {1,2,3}, depth = 4, err = 0)
+//
+// After kernel commit 0b04d4c0542e("f2fs: Fix
+// f2fs_truncate_partial_nodes ftrace event")
+static ExamplePage g_f2fs_truncate_partial_nodes_new{
+ "b281660544_new",
+ R"(
+00000000: 1555 c3e4 cb07 0000 3c00 0000 0000 0000 .U......<.......
+00000010: 3e33 0b87 2700 0000 0c00 0000 7d02 0000 >3..'.......}...
+00000020: c638 0000 3900 e00f 0000 0000 b165 0000 .8..9........e..
+00000030: 0000 0000 0100 0000 0200 0000 0300 0000 ................
+00000040: 0400 0000 0000 0000 0000 0000 0000 0000 ................
+ )",
+};
+
+TEST_F(CpuReaderParsePagePayloadTest, F2fsTruncatePartialNodesNew) {
+ const ExamplePage* test_case = &g_f2fs_truncate_partial_nodes_new;
+
+ ProtoTranslationTable* table = GetTable(test_case->name);
+ auto page = PageFromXxd(test_case->data);
+
+ FtraceDataSourceConfig ds_config = EmptyConfig();
+ ds_config.event_filter.AddEnabledEvent(table->EventToFtraceId(
+ GroupAndName("f2fs", "f2fs_truncate_partial_nodes")));
+
+ const uint8_t* parse_pos = page.get();
+ std::optional<CpuReader::PageHeader> page_header =
+ CpuReader::ParsePageHeader(&parse_pos, table->page_header_size_len());
+
+ const uint8_t* page_end = page.get() + base::kPageSize;
+ ASSERT_TRUE(page_header.has_value());
+ EXPECT_FALSE(page_header->lost_events);
+ EXPECT_LE(parse_pos + page_header->size, page_end);
+
+ size_t evt_bytes = CpuReader::ParsePagePayload(
+ parse_pos, &page_header.value(), table, &ds_config,
+ CreateBundler(ds_config), &metadata_);
+
+ EXPECT_LT(0u, evt_bytes);
+
+ auto bundle = GetBundle();
+ ASSERT_THAT(bundle.event(), SizeIs(1));
+ auto& event = bundle.event()[0];
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().dev(), 65081u);
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().ino(), 26033u);
+ // This field is disabled in ftrace_proto_gen.cc
+ EXPECT_FALSE(event.f2fs_truncate_partial_nodes().has_nid());
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().depth(), 4);
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().err(), 0);
+}
+
+// Kernel code:
+// trace_f2fs_truncate_partial_nodes(... nid = {1,2,3}, depth = 4, err = 0)
+//
+// Before kernel commit 0b04d4c0542e("f2fs: Fix
+// f2fs_truncate_partial_nodes ftrace event")
+static ExamplePage g_f2fs_truncate_partial_nodes_old{
+ "b281660544_old",
+ R"(
+00000000: 8f90 aa0d 9e00 0000 3c00 0000 0000 0000 ........<.......
+00000010: 3e97 0295 0e01 0000 0c00 0000 7d02 0000 >...........}...
+00000020: 8021 0000 3900 e00f 0000 0000 0d66 0000 .!..9........f..
+00000030: 0000 0000 0100 0000 0200 0000 0300 0000 ................
+00000040: 0400 0000 0000 0000 0000 0000 0000 0000 ................
+ )",
+};
+
+TEST_F(CpuReaderParsePagePayloadTest, F2fsTruncatePartialNodesOld) {
+ const ExamplePage* test_case = &g_f2fs_truncate_partial_nodes_old;
+
+ ProtoTranslationTable* table = GetTable(test_case->name);
+ auto page = PageFromXxd(test_case->data);
+
+ FtraceDataSourceConfig ds_config = EmptyConfig();
+ auto id = table->EventToFtraceId(
+ GroupAndName("f2fs", "f2fs_truncate_partial_nodes"));
+ PERFETTO_LOG("Enabling: %zu", id);
+ ds_config.event_filter.AddEnabledEvent(id);
+
+ const uint8_t* parse_pos = page.get();
+ std::optional<CpuReader::PageHeader> page_header =
+ CpuReader::ParsePageHeader(&parse_pos, table->page_header_size_len());
+
+ const uint8_t* page_end = page.get() + base::kPageSize;
+ ASSERT_TRUE(page_header.has_value());
+ EXPECT_FALSE(page_header->lost_events);
+ EXPECT_LE(parse_pos + page_header->size, page_end);
+
+ size_t evt_bytes = CpuReader::ParsePagePayload(
+ parse_pos, &page_header.value(), table, &ds_config,
+ CreateBundler(ds_config), &metadata_);
+
+ EXPECT_LT(0u, evt_bytes);
+
+ auto bundle = GetBundle();
+ ASSERT_THAT(bundle.event(), SizeIs(1));
+ auto& event = bundle.event()[0];
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().dev(), 65081u);
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().ino(), 26125u);
+ // This field is disabled in ftrace_proto_gen.cc
+ EXPECT_FALSE(event.f2fs_truncate_partial_nodes().has_nid());
+ // Due to a kernel bug, nid[1] is parsed as depth.
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().depth(), 2);
+ // Due to a kernel bug, nid[2] is parsed as err.
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().err(), 3);
+}
+
} // namespace
} // namespace perfetto
diff --git a/src/traced/probes/ftrace/event_info.cc b/src/traced/probes/ftrace/event_info.cc
index 3551e9f7b..6a8cca30b 100644
--- a/src/traced/probes/ftrace/event_info.cc
+++ b/src/traced/probes/ftrace/event_info.cc
@@ -4266,9 +4266,6 @@ std::vector<Event> GetStaticEventInfo() {
"ino", 2, ProtoSchemaType::kUint64,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "nid", 3, ProtoSchemaType::kUint32,
- TranslationStrategy::kInvalidTranslationStrategy},
- {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
"depth", 4, ProtoSchemaType::kInt32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
@@ -6653,6 +6650,38 @@ std::vector<Event> GetStaticEventInfo() {
kUnsetFtraceId,
475,
kUnsetSize},
+ {"mali_CSF_INTERRUPT_START",
+ "mali",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "kctx_tgid", 1, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "kctx_id", 2, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "info_val", 3, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 482,
+ kUnsetSize},
+ {"mali_CSF_INTERRUPT_END",
+ "mali",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "kctx_tgid", 1, ProtoSchemaType::kInt32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "kctx_id", 2, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "info_val", 3, ProtoSchemaType::kUint64,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 483,
+ kUnsetSize},
{"mdp_cmd_kickoff",
"mdss",
{
diff --git a/src/traced/probes/ftrace/test/data/b281660544_new/available_events b/src/traced/probes/ftrace/test/data/b281660544_new/available_events
new file mode 100644
index 000000000..5588a9606
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_new/available_events
@@ -0,0 +1 @@
+f2fs:f2fs_truncate_partial_nodes
diff --git a/src/traced/probes/ftrace/test/data/b281660544_new/events/f2fs/f2fs_truncate_partial_nodes/format b/src/traced/probes/ftrace/test/data/b281660544_new/events/f2fs/f2fs_truncate_partial_nodes/format
new file mode 100644
index 000000000..2f5a8ab38
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_new/events/f2fs/f2fs_truncate_partial_nodes/format
@@ -0,0 +1,15 @@
+name: f2fs_truncate_partial_nodes
+ID: 637
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:dev_t dev; offset:8; size:4; signed:0;
+ field:ino_t ino; offset:16; size:8; signed:0;
+ field:nid_t nid[3]; offset:24; size:12; signed:0;
+ field:int depth; offset:36; size:4; signed:1;
+ field:int err; offset:40; size:4; signed:1;
+
+print fmt: "dev = (%d,%d), ino = %lu, nid[0] = %u, nid[1] = %u, nid[2] = %u, depth = %d, err = %d", ((unsigned int) ((REC->dev) >> 20)), ((unsigned int) ((REC->dev) & ((1U << 20) - 1))), (unsigned long)REC->ino, (unsigned int)REC->nid[0], (unsigned int)REC->nid[1], (unsigned int)REC->nid[2], REC->depth, REC->err
diff --git a/src/traced/probes/ftrace/test/data/b281660544_new/events/header_page b/src/traced/probes/ftrace/test/data/b281660544_new/events/header_page
new file mode 100644
index 000000000..276dce9d5
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_new/events/header_page
@@ -0,0 +1,4 @@
+ field: u64 timestamp; offset:0; size:8; signed:0;
+ field: local_t commit; offset:8; size:8; signed:1;
+ field: int overwrite; offset:8; size:1; signed:1;
+ field: char data; offset:16; size:4080; signed:1;
diff --git a/src/traced/probes/ftrace/test/data/b281660544_old/available_events b/src/traced/probes/ftrace/test/data/b281660544_old/available_events
new file mode 100644
index 000000000..5588a9606
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_old/available_events
@@ -0,0 +1 @@
+f2fs:f2fs_truncate_partial_nodes
diff --git a/src/traced/probes/ftrace/test/data/b281660544_old/events/f2fs/f2fs_truncate_partial_nodes/format b/src/traced/probes/ftrace/test/data/b281660544_old/events/f2fs/f2fs_truncate_partial_nodes/format
new file mode 100644
index 000000000..15f6a646b
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_old/events/f2fs/f2fs_truncate_partial_nodes/format
@@ -0,0 +1,15 @@
+name: f2fs_truncate_partial_nodes
+ID: 637
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:dev_t dev; offset:8; size:4; signed:0;
+ field:ino_t ino; offset:16; size:8; signed:0;
+ field:nid_t nid[3]; offset:24; size:4; signed:0;
+ field:int depth; offset:28; size:4; signed:1;
+ field:int err; offset:32; size:4; signed:1;
+
+print fmt: "dev = (%d,%d), ino = %lu, nid[0] = %u, nid[1] = %u, nid[2] = %u, depth = %d, err = %d", ((unsigned int) ((REC->dev) >> 20)), ((unsigned int) ((REC->dev) & ((1U << 20) - 1))), (unsigned long)REC->ino, (unsigned int)REC->nid[0], (unsigned int)REC->nid[1], (unsigned int)REC->nid[2], REC->depth, REC->err
diff --git a/src/traced/probes/ftrace/test/data/b281660544_old/events/header_page b/src/traced/probes/ftrace/test/data/b281660544_old/events/header_page
new file mode 100644
index 000000000..276dce9d5
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_old/events/header_page
@@ -0,0 +1,4 @@
+ field: u64 timestamp; offset:0; size:8; signed:0;
+ field: local_t commit; offset:8; size:8; signed:1;
+ field: int overwrite; offset:8; size:1; signed:1;
+ field: char data; offset:16; size:4080; signed:1;
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_END/format b/src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_END/format
new file mode 100644
index 000000000..277128baa
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_END/format
@@ -0,0 +1,13 @@
+name: mali_CSF_INTERRUPT_END
+ID: 1679
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:pid_t kctx_tgid; offset:8; size:4; signed:1;
+ field:u32 kctx_id; offset:12; size:4; signed:0;
+ field:u64 info_val; offset:16; size:8; signed:0;
+
+print fmt: "kctx=%d_%u info=0x%llx", REC->kctx_tgid, REC->kctx_id, REC->info_val
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_START/format b/src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_START/format
new file mode 100644
index 000000000..0c9e0db55
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/mali/mali_CSF_INTERRUPT_START/format
@@ -0,0 +1,13 @@
+name: mali_CSF_INTERRUPT_START
+ID: 1678
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:pid_t kctx_tgid; offset:8; size:4; signed:1;
+ field:u32 kctx_id; offset:12; size:4; signed:0;
+ field:u64 info_val; offset:16; size:8; signed:0;
+
+print fmt: "kctx=%d_%u info=0x%llx", REC->kctx_tgid, REC->kctx_id, REC->info_val
diff --git a/src/traced/probes/ps/process_stats_data_source.cc b/src/traced/probes/ps/process_stats_data_source.cc
index 8100e4264..9ce614cfc 100644
--- a/src/traced/probes/ps/process_stats_data_source.cc
+++ b/src/traced/probes/ps/process_stats_data_source.cc
@@ -96,6 +96,7 @@ ProcessStatsDataSource::ProcessStatsDataSource(
record_thread_names_ = cfg.record_thread_names();
dump_all_procs_on_start_ = cfg.scan_all_processes_on_start();
resolve_process_fds_ = cfg.resolve_process_fds();
+ scan_smaps_rollup_ = cfg.scan_smaps_rollup();
enable_on_demand_dumps_ = true;
for (auto quirk = cfg.quirks(); quirk; ++quirk) {
@@ -495,6 +496,11 @@ void ProcessStatsDataSource::WriteAllProcessStats() {
if (proc_status.empty())
continue;
+ if (scan_smaps_rollup_) {
+ std::string proc_smaps_rollup = ReadProcPidFile(pid, "smaps_rollup");
+ proc_status.append(proc_smaps_rollup);
+ }
+
if (!WriteMemCounters(pid, proc_status)) {
// If WriteMemCounters() fails the pid is very likely a kernel thread
// that has a valid /proc/[pid]/status but no memory values. In this
@@ -606,6 +612,38 @@ bool ProcessStatsDataSource::WriteMemCounters(int32_t pid,
GetOrCreateStatsProcess(pid)->set_vm_swap_kb(counter);
cached.vm_swap_kb = counter;
}
+ // The entries below come from smaps_rollup, WriteAllProcessStats merges
+ // everything into the same buffer for convenience.
+ } else if (strcmp(key.data(), "Rss") == 0) {
+ auto counter = ToU32(value.data());
+ if (counter != cached.smr_rss_kb) {
+ GetOrCreateStatsProcess(pid)->set_smr_rss_kb(counter);
+ cached.smr_rss_kb = counter;
+ }
+ } else if (strcmp(key.data(), "Pss") == 0) {
+ auto counter = ToU32(value.data());
+ if (counter != cached.smr_pss_kb) {
+ GetOrCreateStatsProcess(pid)->set_smr_pss_kb(counter);
+ cached.smr_pss_kb = counter;
+ }
+ } else if (strcmp(key.data(), "Pss_Anon") == 0) {
+ auto counter = ToU32(value.data());
+ if (counter != cached.smr_pss_anon_kb) {
+ GetOrCreateStatsProcess(pid)->set_smr_pss_anon_kb(counter);
+ cached.smr_pss_anon_kb = counter;
+ }
+ } else if (strcmp(key.data(), "Pss_File") == 0) {
+ auto counter = ToU32(value.data());
+ if (counter != cached.smr_pss_file_kb) {
+ GetOrCreateStatsProcess(pid)->set_smr_pss_file_kb(counter);
+ cached.smr_pss_file_kb = counter;
+ }
+ } else if (strcmp(key.data(), "Pss_Shmem") == 0) {
+ auto counter = ToU32(value.data());
+ if (counter != cached.smr_pss_shmem_kb) {
+ GetOrCreateStatsProcess(pid)->set_smr_pss_shmem_kb(counter);
+ cached.smr_pss_shmem_kb = counter;
+ }
}
key.clear();
diff --git a/src/traced/probes/ps/process_stats_data_source.h b/src/traced/probes/ps/process_stats_data_source.h
index 706ee2a19..4989b3cb7 100644
--- a/src/traced/probes/ps/process_stats_data_source.h
+++ b/src/traced/probes/ps/process_stats_data_source.h
@@ -87,6 +87,11 @@ class ProcessStatsDataSource : public ProbesDataSource {
uint32_t vm_locked_kb = std::numeric_limits<uint32_t>::max();
uint32_t vm_hvm_kb = std::numeric_limits<uint32_t>::max();
int oom_score_adj = std::numeric_limits<int>::max();
+ uint32_t smr_rss_kb = std::numeric_limits<uint32_t>::max();
+ uint32_t smr_pss_kb = std::numeric_limits<uint32_t>::max();
+ uint32_t smr_pss_anon_kb = std::numeric_limits<uint32_t>::max();
+ uint32_t smr_pss_file_kb = std::numeric_limits<uint32_t>::max();
+ uint32_t smr_pss_shmem_kb = std::numeric_limits<uint32_t>::max();
// ctime + stime from /proc/pid/stat
uint64_t cpu_time = std::numeric_limits<uint64_t>::max();
@@ -160,6 +165,7 @@ class ProcessStatsDataSource : public ProbesDataSource {
bool enable_on_demand_dumps_ = true;
bool dump_all_procs_on_start_ = false;
bool resolve_process_fds_ = false;
+ bool scan_smaps_rollup_ = false;
// This set contains PIDs as per the Linux kernel notion of a PID (which is
// really a TID). In practice this set will contain all TIDs for all processes
diff --git a/src/traced/probes/ps/process_stats_data_source_unittest.cc b/src/traced/probes/ps/process_stats_data_source_unittest.cc
index c87f0bdfe..5a09ebefd 100644
--- a/src/traced/probes/ps/process_stats_data_source_unittest.cc
+++ b/src/traced/probes/ps/process_stats_data_source_unittest.cc
@@ -381,6 +381,10 @@ TEST_F(ProcessStatsDataSourceTest, ProcessStats) {
return ret.ToStdString();
}));
+ // By default scan_smaps_rollup is off and /proc/<pid>/smaps_rollup
+ // shouldn't be read.
+ EXPECT_CALL(*data_source, ReadProcPidFile(pid, "smaps_rollup")).Times(0);
+
EXPECT_CALL(*data_source, ReadProcPidFile(pid, "oom_score_adj"))
.WillRepeatedly(Invoke(
[checkpoint, kPids, &iter](int32_t inner_pid, const std::string&) {
@@ -535,5 +539,95 @@ TEST_F(ProcessStatsDataSourceTest, NamespacedProcess) {
EXPECT_THAT(nstid, ElementsAre(3));
}
+TEST_F(ProcessStatsDataSourceTest, ScanSmapsRollupIsOn) {
+ DataSourceConfig ds_config;
+ ProcessStatsConfig cfg;
+ cfg.set_proc_stats_poll_ms(1);
+ cfg.set_resolve_process_fds(true);
+ cfg.set_scan_smaps_rollup(true);
+ cfg.add_quirks(ProcessStatsConfig::DISABLE_ON_DEMAND);
+ ds_config.set_process_stats_config_raw(cfg.SerializeAsString());
+ auto data_source = GetProcessStatsDataSource(ds_config);
+
+ // Populate a fake /proc/ directory.
+ auto fake_proc = base::TempDir::Create();
+ const int kPids[] = {1, 2};
+ std::vector<std::string> dirs_to_delete;
+ for (int pid : kPids) {
+ base::StackString<256> path("%s/%d", fake_proc.path().c_str(), pid);
+ dirs_to_delete.push_back(path.ToStdString());
+ EXPECT_EQ(mkdir(path.c_str(), 0755), 0)
+ << "mkdir('" << path.c_str() << "') failed";
+ }
+
+ auto checkpoint = task_runner_.CreateCheckpoint("all_done");
+ const auto fake_proc_path = fake_proc.path();
+ EXPECT_CALL(*data_source, OpenProcDir())
+ .WillRepeatedly(Invoke([&fake_proc_path] {
+ return base::ScopedDir(opendir(fake_proc_path.c_str()));
+ }));
+ EXPECT_CALL(*data_source, GetProcMountpoint())
+ .WillRepeatedly(
+ Invoke([&fake_proc_path] { return fake_proc_path.c_str(); }));
+
+ const int kNumIters = 4;
+ int iter = 0;
+ for (int pid : kPids) {
+ EXPECT_CALL(*data_source, ReadProcPidFile(pid, "status"))
+ .WillRepeatedly(
+ Invoke([checkpoint, &iter](int32_t p, const std::string&) {
+ base::StackString<1024> ret(
+ "Name: pid_10\nVmSize: %d kB\nVmRSS:\t%d kB\n",
+ p * 100 + iter * 10 + 1, p * 100 + iter * 10 + 2);
+ return ret.ToStdString();
+ }));
+ EXPECT_CALL(*data_source, ReadProcPidFile(pid, "smaps_rollup"))
+ .WillRepeatedly(
+ Invoke([checkpoint, &iter](int32_t p, const std::string&) {
+ base::StackString<1024> ret(
+ "Name: pid_10\nRss: %d kB\nPss:\t%d kB\n",
+ p * 100 + iter * 10 + 4, p * 100 + iter * 10 + 5);
+ return ret.ToStdString();
+ }));
+
+ EXPECT_CALL(*data_source, ReadProcPidFile(pid, "oom_score_adj"))
+ .WillRepeatedly(Invoke(
+ [checkpoint, kPids, &iter](int32_t inner_pid, const std::string&) {
+ auto oom_score = inner_pid * 100 + iter * 10 + 3;
+ if (inner_pid == kPids[base::ArraySize(kPids) - 1]) {
+ if (++iter == kNumIters)
+ checkpoint();
+ }
+ return std::to_string(oom_score);
+ }));
+ }
+
+ data_source->Start();
+ task_runner_.RunUntilCheckpoint("all_done");
+ data_source->Flush(1 /* FlushRequestId */, []() {});
+
+ std::vector<protos::gen::ProcessStats::Process> processes;
+ auto trace = writer_raw_->GetAllTracePackets();
+ for (const auto& packet : trace) {
+ for (const auto& process : packet.process_stats().processes()) {
+ processes.push_back(process);
+ }
+ }
+ ASSERT_EQ(processes.size(), kNumIters * base::ArraySize(kPids));
+ iter = 0;
+ for (const auto& proc_counters : processes) {
+ int32_t pid = proc_counters.pid();
+ ASSERT_EQ(static_cast<int>(proc_counters.smr_rss_kb()),
+ pid * 100 + iter * 10 + 4);
+ ASSERT_EQ(static_cast<int>(proc_counters.smr_pss_kb()),
+ pid * 100 + iter * 10 + 5);
+ if (pid == kPids[base::ArraySize(kPids) - 1])
+ iter++;
+ }
+ for (auto path = dirs_to_delete.rbegin(); path != dirs_to_delete.rend();
+ path++)
+ base::Rmdir(*path);
+}
+
} // namespace
} // namespace perfetto
diff --git a/src/traced/probes/statsd_client/statsd_binder_data_source.cc b/src/traced/probes/statsd_client/statsd_binder_data_source.cc
index 627d4bc97..9d3d7f74b 100644
--- a/src/traced/probes/statsd_client/statsd_binder_data_source.cc
+++ b/src/traced/probes/statsd_client/statsd_binder_data_source.cc
@@ -242,30 +242,20 @@ void StatsdBinderDataSource::OnData(uint32_t reason,
const uint8_t* data,
size_t sz) {
ShellDataDecoder message(data, sz);
-
- bool parse_error = false;
- auto timestamps_it = message.timestamp_nanos(&parse_error);
- std::vector<int64_t> timestamps;
- if (!parse_error) {
- for (; timestamps_it; ++timestamps_it) {
- timestamps.push_back(*timestamps_it);
- }
-
- TraceWriter::TracePacketHandle packet;
- size_t i = 0;
- for (auto it = message.atom(); it; ++it) {
- packet = writer_->NewTracePacket();
- if (i < timestamps.size()) {
- packet->set_timestamp(static_cast<uint64_t>(timestamps[i++]));
- } else {
- packet->set_timestamp(
- static_cast<uint64_t>(base::GetBootTimeNs().count()));
- }
- auto* statsd_atom = packet->set_statsd_atom();
- auto* atom = statsd_atom->add_atom();
- atom->AppendRawProtoBytes(it->data(), it->size());
- packet->Finalize();
- }
+ if (message.has_atom()) {
+ TraceWriter::TracePacketHandle packet = writer_->NewTracePacket();
+
+ // The root packet gets the timestamp of *now* to aid in
+ // a) Packet sorting in trace_processor
+ // b) So we have some useful record of timestamp in case the statsd
+ // one gets broken in some exciting way.
+ packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
+
+ // Now put all the data. We rely on ShellData and StatsdAtom
+ // matching format exactly.
+ packet->AppendBytes(protos::pbzero::TracePacket::kStatsdAtomFieldNumber,
+ message.begin(),
+ static_cast<size_t>(message.end() - message.begin()));
}
// If we have the pending flush in progress resolve that:
diff --git a/src/traced/service/BUILD.gn b/src/traced/service/BUILD.gn
index e0770dbff..cb142e51a 100644
--- a/src/traced/service/BUILD.gn
+++ b/src/traced/service/BUILD.gn
@@ -43,6 +43,10 @@ source_set("service") {
"../../tracing/core:service",
"../../tracing/ipc/service",
]
+ if (enable_perfetto_zlib) {
+ deps += [ "../../tracing/core:zlib_compressor" ]
+ }
+
sources = [
"builtin_producer.cc",
"builtin_producer.h",
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index 72f19ac62..c9d633590 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -43,6 +43,10 @@
#include <sys/system_properties.h>
#endif
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include "src/tracing/core/zlib_compressor.h"
+#endif
+
namespace perfetto {
namespace {
#if defined(PERFETTO_SET_SOCKET_PERMISSIONS)
@@ -158,7 +162,11 @@ int PERFETTO_EXPORT_ENTRYPOINT ServiceMain(int argc, char** argv) {
base::UnixTaskRunner task_runner;
std::unique_ptr<ServiceIPCHost> svc;
- svc = ServiceIPCHost::CreateInstance(&task_runner);
+ TracingService::InitOpts init_opts = {};
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+ init_opts.compressor_fn = &ZlibCompressFn;
+#endif
+ svc = ServiceIPCHost::CreateInstance(&task_runner, init_opts);
// When built as part of the Android tree, the two socket are created and
// bound by init and their fd number is passed in two env variables.
diff --git a/src/tracing/core/BUILD.gn b/src/tracing/core/BUILD.gn
index ea1cb903f..3fe90eae1 100644
--- a/src/tracing/core/BUILD.gn
+++ b/src/tracing/core/BUILD.gn
@@ -83,6 +83,21 @@ source_set("service") {
}
}
+if (enable_perfetto_zlib) {
+ source_set("zlib_compressor") {
+ deps = [
+ ":core",
+ "../../../gn:default_deps",
+ "../../../gn:zlib",
+ "../../../include/perfetto/tracing",
+ ]
+ sources = [
+ "zlib_compressor.cc",
+ "zlib_compressor.h",
+ ]
+ }
+}
+
perfetto_unittest_source_set("unittests") {
testonly = true
deps = [
@@ -99,6 +114,14 @@ perfetto_unittest_source_set("unittests") {
"../../base:test_support",
"../test:test_support",
]
+
+ if (enable_perfetto_zlib) {
+ deps += [
+ ":zlib_compressor",
+ "../../../gn:zlib",
+ ]
+ }
+
sources = [
"histogram_unittest.cc",
"id_allocator_unittest.cc",
@@ -110,6 +133,10 @@ perfetto_unittest_source_set("unittests") {
"trace_packet_unittest.cc",
]
+ if (enable_perfetto_zlib) {
+ sources += [ "zlib_compressor_unittest.cc" ]
+ }
+
# These tests rely on test_task_runner.h which
# has no Windows implementation.
if (!is_win) {
diff --git a/src/tracing/core/metatrace_writer.cc b/src/tracing/core/metatrace_writer.cc
index c2706329b..8d121a6b7 100644
--- a/src/tracing/core/metatrace_writer.cc
+++ b/src/tracing/core/metatrace_writer.cc
@@ -26,11 +26,6 @@
namespace perfetto {
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// static
-constexpr char MetatraceWriter::kDataSourceName[];
-#endif
-
MetatraceWriter::MetatraceWriter() : weak_ptr_factory_(this) {}
MetatraceWriter::~MetatraceWriter() {
diff --git a/src/tracing/core/shared_memory_abi.cc b/src/tracing/core/shared_memory_abi.cc
index 0c4694b02..a9098dc24 100644
--- a/src/tracing/core/shared_memory_abi.cc
+++ b/src/tracing/core/shared_memory_abi.cc
@@ -69,16 +69,6 @@ inline void ClearChunkHeader(SharedMemoryABI::ChunkHeader* header) {
} // namespace
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// static
-constexpr uint32_t SharedMemoryABI::kNumChunksForLayout[];
-constexpr const char* SharedMemoryABI::kChunkStateStr[];
-constexpr const size_t SharedMemoryABI::kInvalidPageIdx;
-constexpr const size_t SharedMemoryABI::kMinPageSize;
-constexpr const size_t SharedMemoryABI::kMaxPageSize;
-constexpr const size_t SharedMemoryABI::kPacketSizeDropPacket;
-#endif
-
SharedMemoryABI::SharedMemoryABI() = default;
SharedMemoryABI::SharedMemoryABI(uint8_t* start,
diff --git a/src/tracing/core/shared_memory_arbiter_impl.cc b/src/tracing/core/shared_memory_arbiter_impl.cc
index f1b830abf..61b3974c0 100644
--- a/src/tracing/core/shared_memory_arbiter_impl.cc
+++ b/src/tracing/core/shared_memory_arbiter_impl.cc
@@ -52,11 +52,6 @@ bool IsReservationTargetBufferId(MaybeUnboundBufferID buffer_id) {
SharedMemoryABI::PageLayout SharedMemoryArbiterImpl::default_page_layout =
SharedMemoryABI::PageLayout::kPageDiv1;
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// static
-constexpr BufferID SharedMemoryArbiterImpl::kInvalidBufferId;
-#endif
-
// static
std::unique_ptr<SharedMemoryArbiter> SharedMemoryArbiter::CreateInstance(
SharedMemory* shared_memory,
diff --git a/src/tracing/core/trace_buffer.cc b/src/tracing/core/trace_buffer.cc
index 4f0f69f49..baa6a3486 100644
--- a/src/tracing/core/trace_buffer.cc
+++ b/src/tracing/core/trace_buffer.cc
@@ -42,9 +42,6 @@ constexpr uint8_t kChunkNeedsPatching =
SharedMemoryABI::ChunkHeader::kChunkNeedsPatching;
} // namespace.
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-constexpr size_t TraceBuffer::ChunkRecord::kMaxSize;
-#endif
const size_t TraceBuffer::InlineChunkHeaderSize = sizeof(ChunkRecord);
// static
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index b4ab055e7..b32a65854 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -16,9 +16,6 @@
#include "src/tracing/core/tracing_service_impl.h"
-#include "perfetto/base/build_config.h"
-#include "perfetto/tracing/core/forward_decls.h"
-
#include <errno.h>
#include <limits.h>
#include <string.h>
@@ -301,25 +298,21 @@ void AppendOwnedSlicesToPacket(std::unique_ptr<uint8_t[]> data,
} // namespace
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// These constants instead are defined in the header because are used by tests.
-constexpr size_t TracingServiceImpl::kMaxShmSize;
-constexpr uint32_t TracingServiceImpl::kDataSourceStopTimeoutMs;
-constexpr uint8_t TracingServiceImpl::kSyncMarker[];
-#endif
-
// static
std::unique_ptr<TracingService> TracingService::CreateInstance(
std::unique_ptr<SharedMemory::Factory> shm_factory,
- base::TaskRunner* task_runner) {
+ base::TaskRunner* task_runner,
+ InitOpts init_opts) {
return std::unique_ptr<TracingService>(
- new TracingServiceImpl(std::move(shm_factory), task_runner));
+ new TracingServiceImpl(std::move(shm_factory), task_runner, init_opts));
}
TracingServiceImpl::TracingServiceImpl(
std::unique_ptr<SharedMemory::Factory> shm_factory,
- base::TaskRunner* task_runner)
+ base::TaskRunner* task_runner,
+ InitOpts init_opts)
: task_runner_(task_runner),
+ init_opts_(init_opts),
shm_factory_(std::move(shm_factory)),
uid_(base::GetCurrentUserId()),
buffer_ids_(kMaxTraceBufferID),
@@ -587,8 +580,8 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
cfg.duration_ms(), max_duration_ms);
}
- const bool has_trigger_config = cfg.trigger_config().trigger_mode() !=
- TraceConfig::TriggerConfig::UNSPECIFIED;
+ const bool has_trigger_config =
+ GetTriggerMode(cfg) != TraceConfig::TriggerConfig::UNSPECIFIED;
if (has_trigger_config &&
(cfg.trigger_config().trigger_timeout_ms() == 0 ||
cfg.trigger_config().trigger_timeout_ms() > max_duration_ms)) {
@@ -610,6 +603,16 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
"The trace config specified an invalid trigger_mode");
}
+ if (cfg.trigger_config().use_clone_snapshot_if_available() &&
+ cfg.trigger_config().trigger_mode() !=
+ TraceConfig::TriggerConfig::STOP_TRACING) {
+ MaybeLogUploadEvent(
+ cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidTriggerMode);
+ return PERFETTO_SVC_ERR(
+ "trigger_mode must be STOP_TRACING when "
+ "use_clone_snapshot_if_available=true");
+ }
+
if (has_trigger_config && cfg.duration_ms() != 0) {
MaybeLogUploadEvent(
cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingDurationWithTrigger);
@@ -617,8 +620,8 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
"duration_ms was set, this must not be set for traces with triggers.");
}
- if (cfg.trigger_config().trigger_mode() ==
- TraceConfig::TriggerConfig::STOP_TRACING &&
+ if ((GetTriggerMode(cfg) == TraceConfig::TriggerConfig::STOP_TRACING ||
+ GetTriggerMode(cfg) == TraceConfig::TriggerConfig::CLONE_SNAPSHOT) &&
cfg.write_into_file()) {
// We don't support this usecase because there are subtle assumptions which
// break around TracingServiceEvents and windowed sorting (i.e. if we don't
@@ -630,8 +633,8 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
cfg, uuid,
PerfettoStatsdAtom::kTracedEnableTracingStopTracingWriteIntoFile);
return PERFETTO_SVC_ERR(
- "Specifying trigger mode STOP_TRACING and write_into_file together is "
- "unsupported");
+ "Specifying trigger mode STOP_TRACING/CLONE_SNAPSHOT and "
+ "write_into_file together is unsupported");
}
std::unordered_set<std::string> triggers;
@@ -853,6 +856,17 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
tracing_session->bytes_written_into_file = 0;
}
+ if (!cfg.compress_from_cli() &&
+ cfg.compression_type() == TraceConfig::COMPRESSION_TYPE_DEFLATE) {
+ if (init_opts_.compressor_fn) {
+ tracing_session->compress_deflate = true;
+ } else {
+ PERFETTO_LOG(
+ "COMPRESSION_TYPE_DEFLATE is not supported in the current build "
+ "configuration. Skipping compression");
+ }
+ }
+
// Initialize the log buffers.
bool did_allocate_all_buffers = true;
bool invalid_buffer_config = false;
@@ -943,7 +957,7 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
bool has_start_trigger = false;
auto weak_this = weak_ptr_factory_.GetWeakPtr();
- switch (cfg.trigger_config().trigger_mode()) {
+ switch (GetTriggerMode(cfg)) {
case TraceConfig::TriggerConfig::UNSPECIFIED:
// no triggers are specified so this isn't a trace that is using triggers.
PERFETTO_DCHECK(!has_trigger_config);
@@ -960,6 +974,7 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
cfg.trigger_config().trigger_timeout_ms());
break;
case TraceConfig::TriggerConfig::STOP_TRACING:
+ case TraceConfig::TriggerConfig::CLONE_SNAPSHOT:
// Update the tracing_session's duration_ms to ensure that if no trigger
// is received the session will end and be cleaned up equal to the
// timeout.
@@ -1245,7 +1260,7 @@ void TracingServiceImpl::StopOnDurationMsExpiry(
// If this trace was using STOP_TRACING triggers and we've seen
// one, then the trigger overrides the normal timeout. In this
// case we just return and let the other task clean up this trace.
- if (tracing_session_ptr->config.trigger_config().trigger_mode() ==
+ if (GetTriggerMode(tracing_session_ptr->config) ==
TraceConfig::TriggerConfig::STOP_TRACING &&
!tracing_session_ptr->received_triggers.empty())
return;
@@ -1485,7 +1500,7 @@ void TracingServiceImpl::ActivateTriggers(
std::string triggered_session_name;
base::Uuid triggered_session_uuid;
TracingSessionID triggered_session_id = 0;
- int trigger_mode = 0;
+ auto trigger_mode = TraceConfig::TriggerConfig::UNSPECIFIED;
uint64_t trigger_name_hash = hash.digest();
size_t count_in_window =
@@ -1544,8 +1559,7 @@ void TracingServiceImpl::ActivateTriggers(
triggered_session_name = tracing_session.config.unique_session_name();
triggered_session_uuid.set_lsb_msb(tracing_session.trace_uuid.lsb(),
tracing_session.trace_uuid.msb());
- trigger_mode = static_cast<int>(
- tracing_session.config.trigger_config().trigger_mode());
+ trigger_mode = GetTriggerMode(tracing_session.config);
const bool triggers_already_received =
!tracing_session.received_triggers.empty();
@@ -1553,7 +1567,7 @@ void TracingServiceImpl::ActivateTriggers(
{static_cast<uint64_t>(now_ns), iter->name(), producer->name_,
producer->uid_});
auto weak_this = weak_ptr_factory_.GetWeakPtr();
- switch (tracing_session.config.trigger_config().trigger_mode()) {
+ switch (trigger_mode) {
case TraceConfig::TriggerConfig::START_TRACING:
// If the session has already been triggered and moved past
// CONFIGURED then we don't need to repeat StartTracing. This would
@@ -1600,6 +1614,24 @@ void TracingServiceImpl::ActivateTriggers(
// will happen shortly.
iter->stop_delay_ms());
break;
+
+ case TraceConfig::TriggerConfig::CLONE_SNAPSHOT:
+ trigger_activated = true;
+ MaybeLogUploadEvent(
+ tracing_session.config, tracing_session.trace_uuid,
+ PerfettoStatsdAtom::kTracedTriggerCloneSnapshot, iter->name());
+ task_runner_->PostDelayedTask(
+ [weak_this, tsid] {
+ if (!weak_this)
+ return;
+ auto* tsess = weak_this->GetTracingSession(tsid);
+ if (!tsess || !tsess->consumer_maybe_null)
+ return;
+ tsess->consumer_maybe_null->NotifyCloneSnapshotTrigger();
+ },
+ iter->stop_delay_ms());
+ break;
+
case TraceConfig::TriggerConfig::UNSPECIFIED:
PERFETTO_ELOG("Trigger activated but trigger mode unspecified.");
break;
@@ -2306,6 +2338,8 @@ std::vector<TracePacket> TracingServiceImpl::ReadBuffers(
MaybeFilterPackets(tracing_session, &packets);
+ MaybeCompressPackets(tracing_session, &packets);
+
if (!*has_more) {
// We've observed some extremely high memory usage by scudo after
// MaybeFilterPackets in the past. The original bug (b/195145848) is fixed
@@ -2358,6 +2392,16 @@ void TracingServiceImpl::MaybeFilterPackets(TracingSession* tracing_session,
}
}
+void TracingServiceImpl::MaybeCompressPackets(
+ TracingSession* tracing_session,
+ std::vector<TracePacket>* packets) {
+ if (!tracing_session->compress_deflate) {
+ return;
+ }
+
+ init_opts_.compressor_fn(packets);
+}
+
bool TracingServiceImpl::WriteIntoFile(TracingSession* tracing_session,
std::vector<TracePacket> packets) {
if (!tracing_session->write_into_file) {
@@ -3497,7 +3541,7 @@ void TracingServiceImpl::FlushAndCloneSession(ConsumerEndpointImpl* consumer,
TracingSession* session = FindTracingSessionWithMaxBugreportScore();
if (!session) {
consumer->consumer_->OnSessionCloned(
- false, "No tracing sessions eligible for bugreport found");
+ {false, "No tracing sessions eligible for bugreport found", {}});
return;
}
tsid = session->id;
@@ -3510,15 +3554,18 @@ void TracingServiceImpl::FlushAndCloneSession(ConsumerEndpointImpl* consumer,
final_flush_outcome);
if (!weak_this || !weak_consumer)
return;
- base::Status result =
- weak_this->DoCloneSession(&*weak_consumer, tsid, final_flush_outcome);
- weak_consumer->consumer_->OnSessionCloned(result.ok(), result.message());
+ base::Uuid uuid;
+ base::Status result = weak_this->DoCloneSession(&*weak_consumer, tsid,
+ final_flush_outcome, &uuid);
+ weak_consumer->consumer_->OnSessionCloned(
+ {result.ok(), result.message(), uuid});
});
}
base::Status TracingServiceImpl::DoCloneSession(ConsumerEndpointImpl* consumer,
TracingSessionID src_tsid,
- bool final_flush_outcome) {
+ bool final_flush_outcome,
+ base::Uuid* new_uuid) {
PERFETTO_DLOG("CloneSession(%" PRIu64 ") started, consumer uid: %d", src_tsid,
static_cast<int>(consumer->uid_));
@@ -3569,6 +3616,7 @@ base::Status TracingServiceImpl::DoCloneSession(ConsumerEndpointImpl* consumer,
cloned_session->state = TracingSession::CLONED_READ_ONLY;
cloned_session->trace_uuid = base::Uuidv4(); // Generate a new UUID.
+ *new_uuid = cloned_session->trace_uuid;
for (auto& kv : buf_snaps) {
BufferID buf_global_id = kv.first;
@@ -3589,6 +3637,7 @@ base::Status TracingServiceImpl::DoCloneSession(ConsumerEndpointImpl* consumer,
cloned_session->flushes_requested = src->flushes_requested;
cloned_session->flushes_succeeded = src->flushes_succeeded;
cloned_session->flushes_failed = src->flushes_failed;
+ cloned_session->compress_deflate = src->compress_deflate;
if (src->trace_filter) {
// Copy the trace filter.
cloned_session->trace_filter.reset(
@@ -3814,6 +3863,15 @@ void TracingServiceImpl::ConsumerEndpointImpl::OnAllDataSourcesStarted() {
observable_events->set_all_data_sources_started(true);
}
+void TracingServiceImpl::ConsumerEndpointImpl::NotifyCloneSnapshotTrigger() {
+ if (!(observable_events_mask_ & ObservableEvents::TYPE_CLONE_TRIGGER_HIT)) {
+ return;
+ }
+ auto* observable_events = AddObservableEvents();
+ auto* clone_trig = observable_events->mutable_clone_trigger_hit();
+ clone_trig->set_tracing_session_id(static_cast<int64_t>(tracing_session_id_));
+}
+
ObservableEvents*
TracingServiceImpl::ConsumerEndpointImpl::AddObservableEvents() {
PERFETTO_DCHECK_THREAD(thread_checker_);
@@ -3910,11 +3968,13 @@ void TracingServiceImpl::ConsumerEndpointImpl::QueryCapabilities(
TracingServiceCapabilities caps;
caps.set_has_query_capabilities(true);
caps.set_has_trace_config_output_path(true);
+ caps.set_has_clone_session(true);
caps.add_observable_events(ObservableEvents::TYPE_DATA_SOURCES_INSTANCES);
caps.add_observable_events(ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED);
- static_assert(ObservableEvents::Type_MAX ==
- ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED,
- "");
+ caps.add_observable_events(ObservableEvents::TYPE_CLONE_TRIGGER_HIT);
+ static_assert(
+ ObservableEvents::Type_MAX == ObservableEvents::TYPE_CLONE_TRIGGER_HIT,
+ "");
callback(caps);
}
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index 7cefb9b6b..8d067fd78 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -87,8 +87,9 @@ class TracingServiceImpl : public TracingService {
// tracing_integration_test.cc and b/195065199
// This is a rough threshold to determine how many bytes to read from the
- // buffers on each iteration when writing into a file. Since filtering
- // allocates memory, this limits the amount of memory allocated.
+ // buffers on each iteration when writing into a file. Since filtering and
+ // compression allocate memory, this effectively limits the amount of memory
+ // allocated.
static constexpr size_t kWriteIntoFileChunkSize = 1024 * 1024ul;
// The implementation behind the service endpoint exposed to each producer.
@@ -209,6 +210,7 @@ class TracingServiceImpl : public TracingService {
~ConsumerEndpointImpl() override;
void NotifyOnTracingDisabled(const std::string& error);
+ void NotifyCloneSnapshotTrigger();
// TracingService::ConsumerEndpoint implementation.
void EnableTracing(const TraceConfig&, base::ScopedFile) override;
@@ -264,7 +266,8 @@ class TracingServiceImpl : public TracingService {
};
explicit TracingServiceImpl(std::unique_ptr<SharedMemory::Factory>,
- base::TaskRunner*);
+ base::TaskRunner*,
+ InitOpts = {});
~TracingServiceImpl() override;
// Called by ProducerEndpointImpl.
@@ -565,6 +568,9 @@ class TracingServiceImpl : public TracingService {
// Whether we put the system info into the trace output yet.
bool did_emit_system_info = false;
+ // Whether we should compress TracePackets after reading them.
+ bool compress_deflate = false;
+
// The number of received triggers we've emitted into the trace output.
size_t num_triggers_emitted_into_trace = 0;
@@ -723,7 +729,8 @@ class TracingServiceImpl : public TracingService {
TraceBuffer* GetBufferByID(BufferID);
base::Status DoCloneSession(ConsumerEndpointImpl*,
TracingSessionID,
- bool final_flush_outcome);
+ bool final_flush_outcome,
+ base::Uuid*);
// Returns true if `*tracing_session` is waiting for a trigger that hasn't
// happened.
@@ -744,6 +751,10 @@ class TracingServiceImpl : public TracingService {
void MaybeFilterPackets(TracingSession* tracing_session,
std::vector<TracePacket>* packets);
+ // If `*tracing_session` has compression enabled, compress `*packets`.
+ void MaybeCompressPackets(TracingSession* tracing_session,
+ std::vector<TracePacket>* packets);
+
// If `*tracing_session` is configured to write into a file, writes `packets`
// into the file.
//
@@ -765,6 +776,7 @@ class TracingServiceImpl : public TracingService {
TracingSessionID);
base::TaskRunner* const task_runner_;
+ const InitOpts init_opts_;
std::unique_ptr<SharedMemory::Factory> shm_factory_;
ProducerID last_producer_id_ = 0;
DataSourceInstanceID last_data_source_instance_id_ = 0;
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index 654272394..fb175e990 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -49,6 +49,11 @@
#include "protos/perfetto/trace/trace_uuid.gen.h"
#include "protos/perfetto/trace/trigger.gen.h"
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <zlib.h>
+#include "src/tracing/core/zlib_compressor.h"
+#endif
+
using ::testing::_;
using ::testing::AssertionFailure;
using ::testing::AssertionResult;
@@ -103,6 +108,53 @@ MATCHER_P(HasTriggerMode, mode, "") {
return HasTriggerModeInternal(arg, mode);
}
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+std::string Decompress(const std::string& data) {
+ uint8_t out[1024];
+
+ z_stream stream{};
+ stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data.data()));
+ stream.avail_in = static_cast<unsigned int>(data.size());
+
+ EXPECT_EQ(inflateInit(&stream), Z_OK);
+ std::string s;
+
+ int ret;
+ do {
+ stream.next_out = out;
+ stream.avail_out = sizeof(out);
+ ret = inflate(&stream, Z_NO_FLUSH);
+ EXPECT_NE(ret, Z_STREAM_ERROR);
+ EXPECT_NE(ret, Z_NEED_DICT);
+ EXPECT_NE(ret, Z_DATA_ERROR);
+ EXPECT_NE(ret, Z_MEM_ERROR);
+ s.append(reinterpret_cast<char*>(out), sizeof(out) - stream.avail_out);
+ } while (ret != Z_STREAM_END);
+
+ inflateEnd(&stream);
+ return s;
+}
+
+std::vector<protos::gen::TracePacket> DecompressTrace(
+ const std::vector<protos::gen::TracePacket> compressed) {
+ std::vector<protos::gen::TracePacket> decompressed;
+
+ for (const protos::gen::TracePacket& c : compressed) {
+ if (c.compressed_packets().empty()) {
+ decompressed.push_back(c);
+ continue;
+ }
+
+ std::string s = Decompress(c.compressed_packets());
+ protos::gen::Trace t;
+ EXPECT_TRUE(t.ParseFromString(s));
+ decompressed.insert(decompressed.end(), t.packet().begin(),
+ t.packet().end());
+ }
+ return decompressed;
+}
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
} // namespace
class TracingServiceImplTest : public testing::Test {
@@ -110,11 +162,14 @@ class TracingServiceImplTest : public testing::Test {
using DataSourceInstanceState =
TracingServiceImpl::DataSourceInstance::DataSourceInstanceState;
- TracingServiceImplTest() {
+ TracingServiceImplTest() { InitializeSvcWithOpts({}); }
+
+ void InitializeSvcWithOpts(TracingService::InitOpts init_opts) {
auto shm_factory =
std::unique_ptr<SharedMemory::Factory>(new TestSharedMemory::Factory());
svc.reset(static_cast<TracingServiceImpl*>(
- TracingService::CreateInstance(std::move(shm_factory), &task_runner)
+ TracingService::CreateInstance(std::move(shm_factory), &task_runner,
+ init_opts)
.release()));
svc->min_write_period_ms_ = 1;
}
@@ -1631,6 +1686,312 @@ TEST_F(TracingServiceImplTest, ProducerIDWrapping) {
ASSERT_EQ(6u, connect_producer_and_get_id("6"));
}
+TEST_F(TracingServiceImplTest, CompressionConfiguredButUnsupported) {
+ // Initialize the service without support for compression.
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = nullptr;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ // Ask for compression in the config.
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ consumer->EnableTracing(trace_config);
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ // The packets should NOT be compressed.
+ std::vector<protos::gen::TracePacket> packets = consumer->ReadBuffers();
+ EXPECT_THAT(packets, Not(IsEmpty()));
+ EXPECT_THAT(
+ packets,
+ Each(Property(&protos::gen::TracePacket::has_compressed_packets, false)));
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-1")))));
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-2")))));
+}
+
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+TEST_F(TracingServiceImplTest, CompressionFromCli) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ // When compress_from_cli is enabled, the service shouldn't do compression
+ trace_config.set_compress_from_cli(true);
+ consumer->EnableTracing(trace_config);
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ std::vector<protos::gen::TracePacket> packets = consumer->ReadBuffers();
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-1")))));
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-2")))));
+}
+
+TEST_F(TracingServiceImplTest, CompressionReadIpc) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ consumer->EnableTracing(trace_config);
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ std::vector<protos::gen::TracePacket> compressed_packets =
+ consumer->ReadBuffers();
+ EXPECT_THAT(compressed_packets, Not(IsEmpty()));
+ EXPECT_THAT(compressed_packets,
+ Each(Property(&protos::gen::TracePacket::compressed_packets,
+ Not(IsEmpty()))));
+ std::vector<protos::gen::TracePacket> decompressed_packets =
+ DecompressTrace(compressed_packets);
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-1")))));
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-2")))));
+}
+
+TEST_F(TracingServiceImplTest, CompressionWriteIntoFile) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ trace_config.set_write_into_file(true);
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ base::TempFile tmp_file = base::TempFile::Create();
+ consumer->EnableTracing(trace_config, base::ScopedFile(dup(tmp_file.fd())));
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ // Verify the contents of the file.
+ std::string trace_raw;
+ ASSERT_TRUE(base::ReadFile(tmp_file.path().c_str(), &trace_raw));
+ protos::gen::Trace trace;
+ ASSERT_TRUE(trace.ParseFromString(trace_raw));
+ EXPECT_THAT(trace.packet(), Not(IsEmpty()));
+ EXPECT_THAT(trace.packet(),
+ Each(Property(&protos::gen::TracePacket::compressed_packets,
+ Not(IsEmpty()))));
+ std::vector<protos::gen::TracePacket> decompressed_packets =
+ DecompressTrace(trace.packet());
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-1")))));
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-2")))));
+}
+
+TEST_F(TracingServiceImplTest, CloneSessionWithCompression) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ // The consumer the creates the initial tracing session.
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ // The consumer that clones it and reads back the data.
+ std::unique_ptr<MockConsumer> consumer2 = CreateMockConsumer();
+ consumer2->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+
+ producer->RegisterDataSource("ds_1");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(32);
+ auto* ds_cfg = trace_config.add_data_sources()->mutable_config();
+ ds_cfg->set_name("ds_1");
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+
+ consumer->EnableTracing(trace_config);
+ producer->WaitForTracingSetup();
+
+ producer->WaitForDataSourceSetup("ds_1");
+
+ producer->WaitForDataSourceStart("ds_1");
+
+ std::unique_ptr<TraceWriter> writer = producer->CreateTraceWriter("ds_1");
+
+ // Add some data.
+ static constexpr size_t kNumTestPackets = 20;
+ for (size_t i = 0; i < kNumTestPackets; i++) {
+ auto tp = writer->NewTracePacket();
+ std::string payload("payload" + std::to_string(i));
+ tp->set_for_testing()->set_str(payload.c_str(), payload.size());
+ tp->set_timestamp(static_cast<uint64_t>(i));
+ }
+
+ auto clone_done = task_runner.CreateCheckpoint("clone_done");
+ EXPECT_CALL(*consumer2, OnSessionCloned(_))
+ .WillOnce(Invoke([clone_done](const Consumer::OnSessionClonedArgs&) {
+ clone_done();
+ }));
+ consumer2->CloneSession(1);
+ // CloneSession() will implicitly issue a flush. Linearize with that.
+ producer->WaitForFlush(std::vector<TraceWriter*>{writer.get()});
+ task_runner.RunUntilCheckpoint("clone_done");
+
+ // Delete the initial tracing session.
+ consumer->DisableTracing();
+ consumer->FreeBuffers();
+ producer->WaitForDataSourceStop("ds_1");
+ consumer->WaitForTracingDisabled();
+
+ // Read back the cloned trace and check that it's compressed
+ std::vector<protos::gen::TracePacket> compressed_packets =
+ consumer2->ReadBuffers();
+ EXPECT_THAT(compressed_packets, Not(IsEmpty()));
+ EXPECT_THAT(compressed_packets,
+ Each(Property(&protos::gen::TracePacket::compressed_packets,
+ Not(IsEmpty()))));
+}
+
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
// Note: file_write_period_ms is set to a large enough to have exactly one flush
// of the tracing buffers (and therefore at most one synchronization section),
// unless the test runs unrealistically slowly, or the implementation of the
@@ -4071,7 +4432,9 @@ TEST_F(TracingServiceImplTest, CloneSession) {
// Message 0: root Trace proto.
filt.AddNestedField(1 /* root trace.packet*/, 1);
filt.EndMessage();
- // Message 1: TracePacket proto. Allow only the `for_testing` sub-field.
+ // Message 1: TracePacket proto. Allow only the `for_testing` and `trace_uuid`
+ // sub-fields.
+ filt.AddSimpleField(protos::pbzero::TracePacket::kTraceUuidFieldNumber);
filt.AddSimpleField(protos::pbzero::TracePacket::kForTestingFieldNumber);
filt.EndMessage();
trace_config.mutable_trace_filter()->set_bytecode(filt.Serialize());
@@ -4100,8 +4463,17 @@ TEST_F(TracingServiceImplTest, CloneSession) {
}
auto clone_done = task_runner.CreateCheckpoint("clone_done");
- EXPECT_CALL(*consumer2, OnSessionCloned(true, ""))
- .WillOnce(InvokeWithoutArgs(clone_done));
+ base::Uuid clone_uuid;
+ EXPECT_CALL(*consumer2, OnSessionCloned(_))
+ .WillOnce(Invoke(
+ [clone_done, &clone_uuid](const Consumer::OnSessionClonedArgs& args) {
+ ASSERT_TRUE(args.success);
+ ASSERT_TRUE(args.error.empty());
+ ASSERT_NE(args.uuid.msb(), 0);
+ ASSERT_NE(args.uuid.lsb(), 0);
+ clone_uuid = args.uuid;
+ clone_done();
+ }));
consumer2->CloneSession(1);
// CloneSession() will implicitly issue a flush. Linearize with that.
producer->WaitForFlush({writers[0].get(), writers[1].get()});
@@ -4145,6 +4517,16 @@ TEST_F(TracingServiceImplTest, CloneSession) {
// Check that the `timestamp` field is filtered out.
EXPECT_THAT(packets,
Each(Property(&protos::gen::TracePacket::has_timestamp, false)));
+
+ // Check that the UUID in the trace matches the UUID passed to to the
+ // OnCloneSession consumer API.
+ EXPECT_THAT(
+ packets,
+ Contains(Property(
+ &protos::gen::TracePacket::trace_uuid,
+ AllOf(
+ Property(&protos::gen::TraceUuid::msb, Eq(clone_uuid.msb())),
+ Property(&protos::gen::TraceUuid::lsb, Eq(clone_uuid.lsb()))))));
}
TEST_F(TracingServiceImplTest, InvalidBufferSizes) {
diff --git a/src/tracing/core/virtual_destructors.cc b/src/tracing/core/virtual_destructors.cc
index 5b7534f88..d38a77613 100644
--- a/src/tracing/core/virtual_destructors.cc
+++ b/src/tracing/core/virtual_destructors.cc
@@ -38,11 +38,6 @@ SharedMemoryArbiter::~SharedMemoryArbiter() = default;
// TODO(primiano): make pure virtual after various 3way patches.
void ConsumerEndpoint::CloneSession(TracingSessionID) {}
-void Consumer::OnSessionCloned(bool, const std::string&) {}
-
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-constexpr size_t TracingService::kDefaultShmSize;
-constexpr size_t TracingService::kDefaultShmPageSize;
-#endif
+void Consumer::OnSessionCloned(const OnSessionClonedArgs&) {}
} // namespace perfetto
diff --git a/src/tracing/core/zlib_compressor.cc b/src/tracing/core/zlib_compressor.cc
new file mode 100644
index 000000000..1a9689ec2
--- /dev/null
+++ b/src/tracing/core/zlib_compressor.cc
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/tracing/core/zlib_compressor.h"
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#error "Zlib must be enabled to compile this file."
+#endif
+
+#include <zlib.h>
+
+#include "protos/perfetto/trace/trace.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+
+namespace {
+
+struct Preamble {
+ uint32_t size;
+ std::array<uint8_t, 16> buf;
+};
+
+template <uint32_t id>
+Preamble GetPreamble(size_t sz) {
+ Preamble preamble;
+ uint8_t* ptr = preamble.buf.data();
+ constexpr uint32_t tag = protozero::proto_utils::MakeTagLengthDelimited(id);
+ ptr = protozero::proto_utils::WriteVarInt(tag, ptr);
+ ptr = protozero::proto_utils::WriteVarInt(sz, ptr);
+ preamble.size =
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr) -
+ reinterpret_cast<uintptr_t>(preamble.buf.data()));
+ PERFETTO_DCHECK(preamble.size < preamble.buf.size());
+ return preamble;
+}
+
+Slice PreambleToSlice(const Preamble& preamble) {
+ Slice slice = Slice::Allocate(preamble.size);
+ memcpy(slice.own_data(), preamble.buf.data(), preamble.size);
+ return slice;
+}
+
+// A compressor for `TracePacket`s that uses zlib. The class is exposed for
+// testing.
+class ZlibPacketCompressor {
+ public:
+ ZlibPacketCompressor();
+ ~ZlibPacketCompressor();
+
+ // Can be called multiple times, before Finish() is called.
+ void PushPacket(const TracePacket& packet);
+
+ // Returned the compressed data. Can be called at most once. After this call,
+ // the object is unusable (PushPacket should not be called) and must be
+ // destroyed.
+ TracePacket Finish();
+
+ private:
+ void PushData(const void* data, uint32_t size);
+ void NewOutputSlice();
+ void PushCurSlice();
+
+ z_stream stream_;
+ size_t total_new_slices_size_ = 0;
+ std::vector<Slice> new_slices_;
+ std::unique_ptr<uint8_t[]> cur_slice_;
+};
+
+ZlibPacketCompressor::ZlibPacketCompressor() {
+ memset(&stream_, 0, sizeof(stream_));
+ int status = deflateInit(&stream_, 6);
+ PERFETTO_CHECK(status == Z_OK);
+}
+
+ZlibPacketCompressor::~ZlibPacketCompressor() {
+ int status = deflateEnd(&stream_);
+ PERFETTO_CHECK(status == Z_OK);
+}
+
+void ZlibPacketCompressor::PushPacket(const TracePacket& packet) {
+ // We need to be able to tokenize packets in the compressed stream, so we
+ // prefix a proto preamble to each packet. The compressed stream looks like a
+ // valid Trace proto.
+ Preamble preamble =
+ GetPreamble<protos::pbzero::Trace::kPacketFieldNumber>(packet.size());
+ PushData(preamble.buf.data(), preamble.size);
+ for (const Slice& slice : packet.slices()) {
+ PushData(slice.start, static_cast<uint32_t>(slice.size));
+ }
+}
+
+void ZlibPacketCompressor::PushData(const void* data, uint32_t size) {
+ stream_.next_in = const_cast<Bytef*>(static_cast<const Bytef*>(data));
+ stream_.avail_in = static_cast<uInt>(size);
+ while (stream_.avail_in != 0) {
+ if (stream_.avail_out == 0) {
+ NewOutputSlice();
+ }
+ int status = deflate(&stream_, Z_NO_FLUSH);
+ PERFETTO_CHECK(status == Z_OK);
+ }
+}
+
+TracePacket ZlibPacketCompressor::Finish() {
+ for (;;) {
+ int status = deflate(&stream_, Z_FINISH);
+ if (status == Z_STREAM_END)
+ break;
+ PERFETTO_CHECK(status == Z_OK || status == Z_BUF_ERROR);
+ NewOutputSlice();
+ }
+
+ PushCurSlice();
+
+ TracePacket packet;
+ packet.AddSlice(PreambleToSlice(
+ GetPreamble<protos::pbzero::TracePacket::kCompressedPacketsFieldNumber>(
+ total_new_slices_size_)));
+ for (auto& slice : new_slices_) {
+ packet.AddSlice(std::move(slice));
+ }
+ return packet;
+}
+
+void ZlibPacketCompressor::NewOutputSlice() {
+ PushCurSlice();
+ cur_slice_ = std::make_unique<uint8_t[]>(kZlibCompressSliceSize);
+ stream_.next_out = reinterpret_cast<Bytef*>(cur_slice_.get());
+ stream_.avail_out = kZlibCompressSliceSize;
+}
+
+void ZlibPacketCompressor::PushCurSlice() {
+ if (cur_slice_) {
+ total_new_slices_size_ += kZlibCompressSliceSize - stream_.avail_out;
+ new_slices_.push_back(Slice::TakeOwnership(
+ std::move(cur_slice_), kZlibCompressSliceSize - stream_.avail_out));
+ }
+}
+
+} // namespace
+
+void ZlibCompressFn(std::vector<TracePacket>* packets) {
+ if (packets->empty()) {
+ return;
+ }
+
+ ZlibPacketCompressor stream;
+
+ for (const TracePacket& packet : *packets) {
+ stream.PushPacket(packet);
+ }
+
+ TracePacket packet = stream.Finish();
+
+ packets->clear();
+ packets->push_back(std::move(packet));
+}
+
+} // namespace perfetto
diff --git a/src/tracing/core/zlib_compressor.h b/src/tracing/core/zlib_compressor.h
new file mode 100644
index 000000000..1962c4831
--- /dev/null
+++ b/src/tracing/core/zlib_compressor.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACING_CORE_ZLIB_COMPRESSOR_H_
+#define SRC_TRACING_CORE_ZLIB_COMPRESSOR_H_
+
+#include <vector>
+
+#include "perfetto/ext/tracing/core/trace_packet.h"
+
+namespace perfetto {
+
+// Matches TracingServiceImpl::kMaxTracePacketSliceSize. Exposed for testing.
+static constexpr size_t kZlibCompressSliceSize = 128 * 1024 - 512;
+
+void ZlibCompressFn(std::vector<TracePacket>*);
+
+} // namespace perfetto
+
+#endif // SRC_TRACING_CORE_ZLIB_COMPRESSOR_H_
diff --git a/src/tracing/core/zlib_compressor_unittest.cc b/src/tracing/core/zlib_compressor_unittest.cc
new file mode 100644
index 000000000..2471c1b63
--- /dev/null
+++ b/src/tracing/core/zlib_compressor_unittest.cc
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/tracing/core/zlib_compressor.h"
+
+#include <random>
+
+#include <zlib.h>
+
+#include "protos/perfetto/trace/test_event.gen.h"
+#include "protos/perfetto/trace/trace.gen.h"
+#include "protos/perfetto/trace/trace_packet.gen.h"
+#include "src/tracing/core/tracing_service_impl.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace {
+
+using ::testing::Each;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::Le;
+using ::testing::Not;
+using ::testing::Property;
+using ::testing::SizeIs;
+
+template <typename F>
+TracePacket CreateTracePacket(F fill_function) {
+ protos::gen::TracePacket msg;
+ fill_function(&msg);
+ std::vector<uint8_t> buf = msg.SerializeAsArray();
+ Slice slice = Slice::Allocate(buf.size());
+ memcpy(slice.own_data(), buf.data(), buf.size());
+ perfetto::TracePacket packet;
+ packet.AddSlice(std::move(slice));
+ return packet;
+}
+
+// Return a copy of the `old` trace packets that owns its own slices data.
+TracePacket CopyTracePacket(const TracePacket& old) {
+ TracePacket ret;
+ for (const Slice& slice : old.slices()) {
+ auto new_slice = Slice::Allocate(slice.size);
+ memcpy(new_slice.own_data(), slice.start, slice.size);
+ ret.AddSlice(std::move(new_slice));
+ }
+ return ret;
+}
+
+std::vector<TracePacket> CopyTracePackets(const std::vector<TracePacket>& old) {
+ std::vector<TracePacket> ret;
+ ret.reserve(old.size());
+ for (const TracePacket& trace_packet : old) {
+ ret.push_back(CopyTracePacket(trace_packet));
+ }
+ return ret;
+}
+std::string RandomString(size_t size) {
+ std::default_random_engine rnd(0);
+ std::uniform_int_distribution<> dist(0, 255);
+ std::string s;
+ s.resize(size);
+ for (size_t i = 0; i < s.size(); i++)
+ s[i] = static_cast<char>(dist(rnd));
+ return s;
+}
+
+std::string Decompress(const std::string& data) {
+ uint8_t out[1024];
+
+ z_stream stream{};
+ stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data.data()));
+ stream.avail_in = static_cast<unsigned int>(data.size());
+
+ EXPECT_EQ(inflateInit(&stream), Z_OK);
+ std::string s;
+
+ int ret;
+ do {
+ stream.next_out = out;
+ stream.avail_out = sizeof(out);
+ ret = inflate(&stream, Z_NO_FLUSH);
+ EXPECT_NE(ret, Z_STREAM_ERROR);
+ EXPECT_NE(ret, Z_NEED_DICT);
+ EXPECT_NE(ret, Z_DATA_ERROR);
+ EXPECT_NE(ret, Z_MEM_ERROR);
+ s.append(reinterpret_cast<char*>(out), sizeof(out) - stream.avail_out);
+ } while (ret != Z_STREAM_END);
+
+ inflateEnd(&stream);
+ return s;
+}
+
+static_assert(kZlibCompressSliceSize ==
+ TracingServiceImpl::kMaxTracePacketSliceSize);
+
+TEST(ZlibCompressFnTest, Empty) {
+ std::vector<TracePacket> packets;
+
+ ZlibCompressFn(&packets);
+
+ EXPECT_THAT(packets, IsEmpty());
+}
+
+TEST(ZlibCompressFnTest, End2EndCompressAndDecompress) {
+ std::vector<TracePacket> packets;
+
+ packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
+ auto* for_testing = msg->mutable_for_testing();
+ for_testing->set_str("abc");
+ }));
+ packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
+ auto* for_testing = msg->mutable_for_testing();
+ for_testing->set_str("def");
+ }));
+
+ ZlibCompressFn(&packets);
+
+ ASSERT_THAT(packets, SizeIs(1));
+ protos::gen::TracePacket compressed_packet_proto;
+ ASSERT_TRUE(compressed_packet_proto.ParseFromString(
+ packets[0].GetRawBytesForTesting()));
+ const std::string& data = compressed_packet_proto.compressed_packets();
+ EXPECT_THAT(data, Not(IsEmpty()));
+ protos::gen::Trace subtrace;
+ ASSERT_TRUE(subtrace.ParseFromString(Decompress(data)));
+ EXPECT_THAT(
+ subtrace.packet(),
+ ElementsAre(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, "abc")),
+ Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, "def"))));
+}
+
+TEST(ZlibCompressFnTest, MaxSliceSize) {
+ std::vector<TracePacket> packets;
+
+ constexpr size_t kStopOutputSize =
+ TracingServiceImpl::kMaxTracePacketSliceSize + 2000;
+
+ TracePacket compressed_packet;
+ while (compressed_packet.size() < kStopOutputSize) {
+ packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
+ auto* for_testing = msg->mutable_for_testing();
+ for_testing->set_str(RandomString(65536));
+ }));
+ {
+ std::vector<TracePacket> packets_copy = CopyTracePackets(packets);
+ ZlibCompressFn(&packets_copy);
+ ASSERT_THAT(packets_copy, SizeIs(1));
+ compressed_packet = std::move(packets_copy[0]);
+ }
+ }
+
+ EXPECT_GE(compressed_packet.slices().size(), 2u);
+ ASSERT_GT(compressed_packet.size(),
+ TracingServiceImpl::kMaxTracePacketSliceSize);
+ EXPECT_THAT(compressed_packet.slices(),
+ Each(Field(&Slice::size,
+ Le(TracingServiceImpl::kMaxTracePacketSliceSize))));
+}
+
+} // namespace
+} // namespace perfetto
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index 181237fc2..5169a2bee 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -644,8 +644,7 @@ void TracingMuxerImpl::ConsumerImpl::OnObservableEvents(
}
void TracingMuxerImpl::ConsumerImpl::OnSessionCloned(
- bool /*success*/,
- const std::string& /*error*/) {
+ const OnSessionClonedArgs&) {
// CloneSession is not exposed in the SDK. This should never happen.
PERFETTO_DCHECK(false);
}
@@ -1165,7 +1164,8 @@ void TracingMuxerImpl::RegisterInterceptor(
}
// Only allow certain interceptors for now.
if (descriptor.name() != "test_interceptor" &&
- descriptor.name() != "console") {
+ descriptor.name() != "console" &&
+ descriptor.name() != "etwexport") {
PERFETTO_ELOG(
"Interceptors are experimental. If you want to use them, please "
"get in touch with the project maintainers "
diff --git a/src/tracing/internal/tracing_muxer_impl.h b/src/tracing/internal/tracing_muxer_impl.h
index 4c87bb9c1..54d2fc375 100644
--- a/src/tracing/internal/tracing_muxer_impl.h
+++ b/src/tracing/internal/tracing_muxer_impl.h
@@ -300,7 +300,7 @@ class TracingMuxerImpl : public TracingMuxer {
void OnAttach(bool success, const TraceConfig&) override;
void OnTraceStats(bool success, const TraceStats&) override;
void OnObservableEvents(const ObservableEvents&) override;
- void OnSessionCloned(bool, const std::string&) override;
+ void OnSessionCloned(const OnSessionClonedArgs&) override;
void NotifyStartComplete();
void NotifyError(const TracingError&);
diff --git a/src/tracing/internal/tracing_muxer_impl_integrationtest.cc b/src/tracing/internal/tracing_muxer_impl_integrationtest.cc
index 5711d73c3..bc28cdef6 100644
--- a/src/tracing/internal/tracing_muxer_impl_integrationtest.cc
+++ b/src/tracing/internal/tracing_muxer_impl_integrationtest.cc
@@ -25,6 +25,12 @@ using ::testing::Property;
class TracingMuxerImplIntegrationTest : public testing::Test {
protected:
+ void SetUp() override {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ GTEST_SKIP() << "Unix sockets not supported on windows";
+#endif
+ }
+
// Sets the environment variable `name` to `value`. Restores it to the
// previous value when the test finishes.
void SetEnvVar(const char* name, const char* value) {
@@ -38,7 +44,7 @@ class TracingMuxerImplIntegrationTest : public testing::Test {
base::SetEnv(name, value);
}
- ~TracingMuxerImplIntegrationTest() {
+ ~TracingMuxerImplIntegrationTest() override {
perfetto::Tracing::ResetForTesting();
while (!prev_state_.empty()) {
const EnvVar& var = prev_state_.top();
diff --git a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
index 7eecd09ed..cf34361be 100644
--- a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
+++ b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
@@ -479,10 +479,11 @@ void ConsumerIPCClientImpl::CloneSession(TracingSessionID tsid) {
// If the IPC fails, we are talking to an older version of the service
// that didn't support CloneSession at all.
weak_this->consumer_->OnSessionCloned(
- false, "CloneSession IPC not supported");
+ {false, "CloneSession IPC not supported", {}});
} else {
- weak_this->consumer_->OnSessionCloned(response->success(),
- response->error());
+ base::Uuid uuid(response->uuid_lsb(), response->uuid_msb());
+ weak_this->consumer_->OnSessionCloned(
+ {response->success(), response->error(), uuid});
}
});
consumer_port_.CloneSession(req, std::move(async_response));
diff --git a/src/tracing/ipc/service/consumer_ipc_service.cc b/src/tracing/ipc/service/consumer_ipc_service.cc
index 2f457136e..ac52864ae 100644
--- a/src/tracing/ipc/service/consumer_ipc_service.cc
+++ b/src/tracing/ipc/service/consumer_ipc_service.cc
@@ -480,14 +480,15 @@ void ConsumerIPCService::RemoteConsumer::CloseObserveEventsResponseStream() {
}
void ConsumerIPCService::RemoteConsumer::OnSessionCloned(
- bool success,
- const std::string& error) {
+ const OnSessionClonedArgs& args) {
if (!clone_session_response.IsBound())
return;
auto resp = ipc::AsyncResult<protos::gen::CloneSessionResponse>::Create();
- resp->set_success(success);
- resp->set_error(error);
+ resp->set_success(args.success);
+ resp->set_error(args.error);
+ resp->set_uuid_msb(args.uuid.msb());
+ resp->set_uuid_lsb(args.uuid.lsb());
std::move(clone_session_response).Resolve(std::move(resp));
}
diff --git a/src/tracing/ipc/service/consumer_ipc_service.h b/src/tracing/ipc/service/consumer_ipc_service.h
index d570c519a..f1424d9e4 100644
--- a/src/tracing/ipc/service/consumer_ipc_service.h
+++ b/src/tracing/ipc/service/consumer_ipc_service.h
@@ -94,7 +94,7 @@ class ConsumerIPCService : public protos::gen::ConsumerPort {
void OnAttach(bool, const TraceConfig&) override;
void OnTraceStats(bool, const TraceStats&) override;
void OnObservableEvents(const ObservableEvents&) override;
- void OnSessionCloned(bool, const std::string&) override;
+ void OnSessionCloned(const OnSessionClonedArgs&) override;
void CloseObserveEventsResponseStream();
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.cc b/src/tracing/ipc/service/service_ipc_host_impl.cc
index 85029a296..1df674ef7 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.cc
+++ b/src/tracing/ipc/service/service_ipc_host_impl.cc
@@ -40,12 +40,15 @@ constexpr uint32_t kProducerSocketTxTimeoutMs = 10;
// Implements the publicly exposed factory method declared in
// include/tracing/posix_ipc/posix_service_host.h.
std::unique_ptr<ServiceIPCHost> ServiceIPCHost::CreateInstance(
- base::TaskRunner* task_runner) {
- return std::unique_ptr<ServiceIPCHost>(new ServiceIPCHostImpl(task_runner));
+ base::TaskRunner* task_runner,
+ TracingService::InitOpts init_opts) {
+ return std::unique_ptr<ServiceIPCHost>(
+ new ServiceIPCHostImpl(task_runner, init_opts));
}
-ServiceIPCHostImpl::ServiceIPCHostImpl(base::TaskRunner* task_runner)
- : task_runner_(task_runner) {}
+ServiceIPCHostImpl::ServiceIPCHostImpl(base::TaskRunner* task_runner,
+ TracingService::InitOpts init_opts)
+ : task_runner_(task_runner), init_opts_(init_opts) {}
ServiceIPCHostImpl::~ServiceIPCHostImpl() {}
@@ -95,7 +98,8 @@ bool ServiceIPCHostImpl::DoStart() {
std::unique_ptr<SharedMemory::Factory> shm_factory(
new PosixSharedMemory::Factory());
#endif
- svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_);
+ svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_,
+ init_opts_);
if (!producer_ipc_port_ || !consumer_ipc_port_) {
Shutdown();
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.h b/src/tracing/ipc/service/service_ipc_host_impl.h
index dda7e5bfa..4ccfa65f2 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.h
+++ b/src/tracing/ipc/service/service_ipc_host_impl.h
@@ -33,7 +33,8 @@ class Host;
// producer_ipc_service.cc and consumer_ipc_service.cc.
class ServiceIPCHostImpl : public ServiceIPCHost {
public:
- ServiceIPCHostImpl(base::TaskRunner*);
+ explicit ServiceIPCHostImpl(base::TaskRunner*,
+ TracingService::InitOpts init_opts = {});
~ServiceIPCHostImpl() override;
// ServiceIPCHost implementation.
@@ -51,6 +52,7 @@ class ServiceIPCHostImpl : public ServiceIPCHost {
void Shutdown();
base::TaskRunner* const task_runner_;
+ const TracingService::InitOpts init_opts_;
std::unique_ptr<TracingService> svc_; // The service business logic.
// The IPC host that listens on the Producer socket. It owns the
diff --git a/src/tracing/test/aligned_buffer_test.cc b/src/tracing/test/aligned_buffer_test.cc
index 082e13051..fc9b8bc47 100644
--- a/src/tracing/test/aligned_buffer_test.cc
+++ b/src/tracing/test/aligned_buffer_test.cc
@@ -20,11 +20,6 @@
namespace perfetto {
-#if !PERFETTO_IS_AT_LEAST_CPP17()
-// static
-constexpr size_t AlignedBufferTest::kNumPages;
-#endif
-
void AlignedBufferTest::SetUp() {
page_size_ = GetParam();
buf_.reset(new TestSharedMemory(page_size_ * kNumPages));
diff --git a/src/tracing/test/mock_consumer.h b/src/tracing/test/mock_consumer.h
index 3b6ad2b73..2253d93f5 100644
--- a/src/tracing/test/mock_consumer.h
+++ b/src/tracing/test/mock_consumer.h
@@ -83,7 +83,7 @@ class MockConsumer : public Consumer {
MOCK_METHOD(void, OnAttach, (bool, const TraceConfig&), (override));
MOCK_METHOD(void, OnTraceStats, (bool, const TraceStats&), (override));
MOCK_METHOD(void, OnObservableEvents, (const ObservableEvents&), (override));
- MOCK_METHOD(void, OnSessionCloned, (bool, const std::string&), (override));
+ MOCK_METHOD(void, OnSessionCloned, (const OnSessionClonedArgs&), (override));
// gtest doesn't support move-only types. This wrapper is here jut to pass
// a pointer to the vector (rather than the vector itself) to the mock method.
diff --git a/src/tracing/test/tracing_integration_test.cc b/src/tracing/test/tracing_integration_test.cc
index 05fa12607..29949a853 100644
--- a/src/tracing/test/tracing_integration_test.cc
+++ b/src/tracing/test/tracing_integration_test.cc
@@ -97,7 +97,7 @@ class MockConsumer : public Consumer {
MOCK_METHOD(void, OnAttach, (bool, const TraceConfig&), (override));
MOCK_METHOD(void, OnTraceStats, (bool, const TraceStats&), (override));
MOCK_METHOD(void, OnObservableEvents, (const ObservableEvents&), (override));
- MOCK_METHOD(void, OnSessionCloned, (bool, const std::string&), (override));
+ MOCK_METHOD(void, OnSessionCloned, (const OnSessionClonedArgs&), (override));
// Workaround, gmock doesn't support yet move-only types, passing a pointer.
void OnTraceData(std::vector<TracePacket> packets, bool has_more) {
diff --git a/test/cmdline_integrationtest.cc b/test/cmdline_integrationtest.cc
index cbc355560..f8c7a43e6 100644
--- a/test/cmdline_integrationtest.cc
+++ b/test/cmdline_integrationtest.cc
@@ -46,6 +46,7 @@ namespace {
using ::testing::ContainsRegex;
using ::testing::Each;
using ::testing::ElementsAreArray;
+using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::Property;
using ::testing::SizeIs;
@@ -80,6 +81,13 @@ TraceConfig CreateTraceConfigForBugreportTest() {
return trace_config;
}
+class ScopedFileRemove {
+ public:
+ explicit ScopedFileRemove(const std::string& path) : path_(path) {}
+ ~ScopedFileRemove() { remove(path_.c_str()); }
+ std::string path_;
+};
+
class PerfettoCmdlineTest : public ::testing::Test {
public:
void SetUp() override {
@@ -137,8 +145,10 @@ class PerfettoCmdlineTest : public ::testing::Test {
// This is in common to the 3 TEST_F SaveForBugreport* fixtures, which differ
// only in the config, passed here as input.
void RunBugreportTest(protos::gen::TraceConfig trace_config,
- bool check_original_trace = true) {
+ bool check_original_trace = true,
+ bool use_explicit_clone = false) {
const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
auto perfetto_proc = ExecPerfetto(
{
@@ -149,9 +159,10 @@ class PerfettoCmdlineTest : public ::testing::Test {
},
trace_config.SerializeAsString());
- auto perfetto_br_proc = ExecPerfetto({
- "--save-for-bugreport",
- });
+ Exec perfetto_br_proc =
+ use_explicit_clone
+ ? ExecPerfetto({"--out", GetBugreportTracePath(), "--clone", "-1"})
+ : ExecPerfetto({"--save-for-bugreport"});
// Start the service and connect a simple fake producer.
StartServiceIfRequiredNoNewExecsAfterThis();
@@ -364,6 +375,7 @@ TEST_F(PerfettoCmdlineTest, StartTracingTrigger) {
// (could deadlock) to fork after we've spawned some threads which might
// printf (and thus hold locks).
const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
auto perfetto_proc = ExecPerfetto(
{
"-o",
@@ -458,6 +470,7 @@ TEST_F(PerfettoCmdlineTest, StopTracingTrigger) {
// (could deadlock) to fork after we've spawned some threads which might
// printf (and thus hold locks).
const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
auto perfetto_proc = ExecPerfetto(
{
"-o",
@@ -562,6 +575,7 @@ TEST_F(PerfettoCmdlineTest, AndroidOnly(NoDataNoFileWithoutTrigger)) {
// (could deadlock) to fork after we've spawned some threads which might
// printf (and thus hold locks).
const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
auto perfetto_proc = ExecPerfetto(
{
"--dropbox",
@@ -616,6 +630,7 @@ TEST_F(PerfettoCmdlineTest, StopTracingTriggerFromConfig) {
// (could deadlock) to fork after we've spawned some threads which might
// printf (and thus hold locks).
const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
auto perfetto_proc = ExecPerfetto(
{
"-o",
@@ -719,6 +734,7 @@ TEST_F(PerfettoCmdlineTest, TriggerFromConfigStopsFileOpening) {
// (could deadlock) to fork after we've spawned some threads which might
// printf (and thus hold locks).
const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
std::string triggers = R"(
activate_triggers: "trigger_name_2"
activate_triggers: "trigger_name"
@@ -782,6 +798,7 @@ TEST_F(PerfettoCmdlineTest, AndroidOnly(CmdTriggerWithUploadFlag)) {
// (could deadlock) to fork after we've spawned some threads which might
// printf (and thus hold locks).
const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
auto perfetto_proc = ExecPerfetto(
{
"-o",
@@ -829,11 +846,100 @@ TEST_F(PerfettoCmdlineTest, AndroidOnly(CmdTriggerWithUploadFlag)) {
protos::gen::Trace trace;
ASSERT_TRUE(trace.ParseFromString(trace_str));
EXPECT_LT(static_cast<int>(kMessageCount), trace.packet_size());
- for (const auto& packet : trace.packet()) {
- if (packet.has_trigger()) {
- EXPECT_EQ("trigger_name", packet.trigger().trigger_name());
- }
+ EXPECT_THAT(trace.packet(),
+ Contains(Property(&protos::gen::TracePacket::trigger,
+ Property(&protos::gen::Trigger::trigger_name,
+ Eq("trigger_name")))));
+}
+
+TEST_F(PerfettoCmdlineTest, TriggerCloneSnapshot) {
+ constexpr size_t kMessageCount = 2;
+ constexpr size_t kMessageSize = 2;
+ protos::gen::TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(1024);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("android.perfetto.FakeProducer");
+ ds_config->mutable_for_testing()->set_message_count(kMessageCount);
+ ds_config->mutable_for_testing()->set_message_size(kMessageSize);
+ auto* trigger_cfg = trace_config.mutable_trigger_config();
+ trigger_cfg->set_trigger_mode(
+ protos::gen::TraceConfig::TriggerConfig::CLONE_SNAPSHOT);
+ trigger_cfg->set_trigger_timeout_ms(600000);
+ auto* trigger = trigger_cfg->add_triggers();
+ trigger->set_name("trigger_name");
+ // |stop_delay_ms| must be long enough that we can write the packets in
+ // before the trace finishes. This has to be long enough for the slowest
+ // emulator. But as short as possible to prevent the test running a long
+ // time.
+ trigger->set_stop_delay_ms(500);
+
+ // We have to construct all the processes we want to fork before we start the
+ // service with |StartServiceIfRequired()|. this is because it is unsafe
+ // (could deadlock) to fork after we've spawned some threads which might
+ // printf (and thus hold locks).
+ const std::string path = RandomTraceFileName();
+ ScopedFileRemove remove_on_test_exit(path);
+ auto perfetto_proc = ExecPerfetto(
+ {
+ "-o",
+ path,
+ "-c",
+ "-",
+ },
+ trace_config.SerializeAsString());
+
+ std::string triggers = R"(
+ activate_triggers: "trigger_name"
+ )";
+ auto trigger_proc = ExecPerfetto(
+ {
+ "-c",
+ "-",
+ "--txt",
+ },
+ triggers);
+
+ // Start the service and connect a simple fake producer.
+ StartServiceIfRequiredNoNewExecsAfterThis();
+ auto* fake_producer = ConnectFakeProducer();
+ EXPECT_TRUE(fake_producer);
+
+ std::thread background_trace([&perfetto_proc]() {
+ std::string stderr_str;
+ EXPECT_EQ(0, perfetto_proc.Run(&stderr_str)) << stderr_str;
+ });
+
+ WaitForProducerEnabled();
+ // Wait for the producer to start, and then write out 11 packets, before the
+ // trace actually starts (the trigger is seen).
+ auto on_data_written = task_runner_.CreateCheckpoint("data_written_1");
+ fake_producer->ProduceEventBatch(WrapTask(on_data_written));
+ task_runner_.RunUntilCheckpoint("data_written_1");
+
+ EXPECT_EQ(0, trigger_proc.Run(&stderr_)) << "stderr: " << stderr_;
+
+ // Now we need to wait that the `perfetto_proc` creates the snapshot trace
+ // file in the trace/path.0 file (appending .0). Once that is done we can
+ // kill the perfetto cmd (otherwise it will keep running for the whole
+ // trigger_timeout_ms, unlike the case of STOP_TRACING.
+ std::string snapshot_path = path + ".0";
+ for (int i = 0; i < 100 && !base::FileExists(snapshot_path); i++) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
+ ASSERT_TRUE(base::FileExists(snapshot_path));
+
+ perfetto_proc.SendSigterm();
+ background_trace.join();
+
+ std::string trace_str;
+ base::ReadFile(snapshot_path, &trace_str);
+ protos::gen::Trace trace;
+ ASSERT_TRUE(trace.ParseFromString(trace_str));
+ EXPECT_LT(static_cast<int>(kMessageCount), trace.packet_size());
+ EXPECT_THAT(trace.packet(),
+ Contains(Property(&protos::gen::TracePacket::trigger,
+ Property(&protos::gen::Trigger::trigger_name,
+ Eq("trigger_name")))));
}
TEST_F(PerfettoCmdlineTest, SaveForBugreport) {
@@ -848,6 +954,21 @@ TEST_F(PerfettoCmdlineTest, SaveForBugreport_WriteIntoFile) {
RunBugreportTest(std::move(trace_config));
}
+TEST_F(PerfettoCmdlineTest, Clone) {
+ TraceConfig trace_config = CreateTraceConfigForBugreportTest();
+ RunBugreportTest(std::move(trace_config), /*check_original_trace=*/true,
+ /*use_explicit_clone=*/true);
+}
+
+// Regression test for b/279753347 .
+TEST_F(PerfettoCmdlineTest, UnavailableBugreportLeavesNoEmptyFiles) {
+ ScopedFileRemove remove_on_test_exit(GetBugreportTracePath());
+ Exec perfetto_br_proc = ExecPerfetto({"--save-for-bugreport"});
+ StartServiceIfRequiredNoNewExecsAfterThis();
+ perfetto_br_proc.Run(&stderr_);
+ ASSERT_FALSE(base::FileExists(GetBugreportTracePath()));
+}
+
// Tests that SaveTraceForBugreport() works also if the trace has triggers
// defined and those triggers have not been hit. This is a regression test for
// b/188008375 .
diff --git a/test/configs/BUILD.gn b/test/configs/BUILD.gn
index 230fe0147..b56822bb6 100644
--- a/test/configs/BUILD.gn
+++ b/test/configs/BUILD.gn
@@ -40,6 +40,7 @@ action_foreach("configs") {
"long_trace.cfg",
"mm_events.cfg",
"scheduling.cfg",
+ "snapshot.cfg",
"summary.cfg",
"sys_stats.cfg",
"thermal.cfg",
diff --git a/test/configs/snapshot.cfg b/test/configs/snapshot.cfg
new file mode 100644
index 000000000..eb2c19786
--- /dev/null
+++ b/test/configs/snapshot.cfg
@@ -0,0 +1,49 @@
+unique_session_name: "test_snap"
+
+buffers {
+ size_kb: 32768
+ fill_policy: RING_BUFFER
+}
+
+# Enable various data sources as usual.
+data_sources {
+ config {
+ name: "linux.ftrace"
+ target_buffer: 0
+ ftrace_config {
+ ftrace_events: "cpu_frequency"
+ ftrace_events: "cpu_idle"
+ ftrace_events: "sched_process_exec"
+ ftrace_events: "sched_process_exit"
+ ftrace_events: "sched_process_fork"
+ ftrace_events: "sched_process_free"
+ ftrace_events: "sched_process_hang"
+ ftrace_events: "sched_process_wait"
+ ftrace_events: "sched_switch"
+ ftrace_events: "sched_wakeup_new"
+ ftrace_events: "sched_wakeup"
+ ftrace_events: "sched_waking"
+ ftrace_events: "task_newtask"
+ ftrace_events: "task_rename"
+ ftrace_events: "tracing_mark_write"
+ }
+ }
+}
+
+data_sources {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 0
+ }
+}
+
+
+trigger_config {
+ trigger_mode: STOP_TRACING
+ use_clone_snapshot_if_available: true
+ trigger_timeout_ms: 300000
+ triggers {
+ name: "xxx"
+ stop_delay_ms: 0
+ }
+}
diff --git a/test/configs/statsd.cfg b/test/configs/statsd.cfg
index a384b5728..10d5b0d07 100644
--- a/test/configs/statsd.cfg
+++ b/test/configs/statsd.cfg
@@ -5,7 +5,7 @@ buffers {
data_sources {
config {
- name: "android.statsd"
+ name: "android.statsd_binder"
target_buffer: 0
statsd_tracing_config {
push_atom_id: ATOM_FLASHLIGHT_STATE_CHANGED
diff --git a/test/cts/reporter/reporter_test_cts.cc b/test/cts/reporter/reporter_test_cts.cc
index f9294f4e5..f27d3daba 100644
--- a/test/cts/reporter/reporter_test_cts.cc
+++ b/test/cts/reporter/reporter_test_cts.cc
@@ -42,6 +42,7 @@ TEST(PerfettoReporterTest, TestEndToEndReport) {
trace_config.add_buffers()->set_size_kb(1024);
trace_config.set_duration_ms(200);
trace_config.set_allow_user_build_tracing(true);
+ trace_config.set_unique_session_name("TestEndToEndReport");
auto* ds_config = trace_config.add_data_sources()->mutable_config();
ds_config->set_name("android.perfetto.FakeProducer");
@@ -72,6 +73,7 @@ TEST(PerfettoReporterTest, TestEndToEndReport) {
auto perfetto_proc = Exec("perfetto",
{
"--upload",
+ "--no-guardrails",
"-c",
"-",
},
diff --git a/test/data/fuchsia_events_and_args.fxt.sha256 b/test/data/fuchsia_events_and_args.fxt.sha256
new file mode 100644
index 000000000..cf71b6769
--- /dev/null
+++ b/test/data/fuchsia_events_and_args.fxt.sha256
@@ -0,0 +1 @@
+1597b8fd935caedb1e319e423cff4dbfba68327cad6ec21f985c0378c2c76b20 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
index 62feb86a5..adfa483e2 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
@@ -1 +1 @@
-826cb6e532e4d342e02b6022917423bb481a3b8764bb697706ca890d0ad847c3 \ No newline at end of file
+37ce86e92a72fe05c24acfcadf1393f3407a99e3dcdda6b3c883f380ffd00b41 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
index de95b69cf..ba42f3444 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
@@ -1 +1 @@
-a56f7bcdebf30ae7da87417e1951867446ae7bd337e450d52ffa45d5d4c2ab65 \ No newline at end of file
+0c7f3705f1d29c0b16756b66cb748635352fef3928a173b34d995356e6d3d58e \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
index d34a6fde8..4c65000da 100644
--- a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
@@ -1 +1 @@
-e97284d62ddefdbd091e5e820881e81d5ad95a22edcf50d83cacc06b7b9bedde \ No newline at end of file
+c8277a777519e7c1bf762d4e0e299a79a66da88ce54ed26e6d27939dca6128c9 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
index 5780168a2..f504fafc3 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
@@ -1 +1 @@
-eb2d68c1fab251b50184431abb3a10b420f95e5eca2dc341028feb4a3ea03d40 \ No newline at end of file
+dc246b0bf68834a63464c0c98e35a060cb3698947084cdb9d976207a37bf8156 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
index 73891dc2e..0ee6b178d 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
@@ -1 +1 @@
-fd17d4de0cae0cfbaaed535519b333d7ee13cac65ad14144e68335c8ca521216 \ No newline at end of file
+e79c53f02bed0a629c76fd3d044492dc8e619fe9f58c597db5f4417cbe91f805 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
index d65717981..0e50d9b87 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
@@ -1 +1 @@
-92aa98e5edad0293244bc0a94672a2e9b63e9b6aaa86ab0a58db8b106e912693 \ No newline at end of file
+cc543d6db95f56863f5d6c90dbbb8b07e8dff539534c53d595b1faee807903da \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
index 69e55e119..bf8f89b19 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_1.png.sha256
@@ -1 +1 @@
-e7dc92a76eec326637bebaa176482197c621f48bc066fc761d0b1d19513c8c21 \ No newline at end of file
+db689629c3ba9a51e74d48edd3e801bf062dd985ed5210e5a9b4f1bce50f29a7 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
index 48395a155..6c3077884 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_dismiss_2.png.sha256
@@ -1 +1 @@
-36628de5b3af4cb6de10e6b4f1860ea8534b8b0db37ee994fddc94947947cb6e \ No newline at end of file
+eae8d6c700a16b5062736c54e4fe0ffab569ffd839715138e74cd257fdb014fa \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
index 623260e39..5117a65d5 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_1.png.sha256
@@ -1 +1 @@
-b51e0a5035eab217bc4339800e8a6c4025bfc7d5240844c152fbc867b28f75ba \ No newline at end of file
+5767e81834101bf14dcd1917544f1605b8dbb8aa747a7eefd1c52f4db891575f \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
index 679bd3983..ff3aafa1a 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_show_dialog_2.png.sha256
@@ -1 +1 @@
-99d3e463fe3812942825829a388bb2d5b11d73010c3213b11d09884dfc1663b5 \ No newline at end of file
+ab1a1b7c948e008fa5d44a4471dc24977f3ab2d592c1ceeaa0ab4afac5bb2336 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256 b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
index e84c777d3..f4e56d2eb 100644
--- a/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
+++ b/test/data/ui-screenshots/ui-modal_dialog_switch_page_no_dialog.png.sha256
@@ -1 +1 @@
-c5c11d6515e27365eeaf50602243d918cc688ee18d1390649c786b28225e1d81 \ No newline at end of file
+d7c89c766d8db408de06f79654e2f81d8c761c08c4451991447807468df0f3d5 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
index 849be2d4c..46f012943 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_navigate_back_and_forward.png.sha256
@@ -1 +1 @@
-4b07a28b92a72568615003beb4eb086adc9be581a27baa2ea593c5e88802647b \ No newline at end of file
+e596f8037a578f1e58a33bbe08f5d5621b1d37e55456409e5f8799a6897eedb9 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
index eb2608789..23be44dae 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
@@ -1 +1 @@
-9bac90702af629b8ecec00b99d86704f188b332695dea2eaf49d79aba3fc8670 \ No newline at end of file
+b938d4dfcc109165feaedb9421276a355d03a383a0d21ab91ff72409b18a3ab5 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
index b3581ce86..b3b161970 100644
--- a/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_invalid_trace_from_blank_page.png.sha256
@@ -1 +1 @@
-f64d01ccda59ec74395e00267d7adbf179f5dd962affeeef639ae583756bc65b \ No newline at end of file
+ae78e1f372a6a052a650974464f2e706ab8cb665c639ca4b0b15b48dce95d185 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256 b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
index 2afc1a3ab..0abbaa782 100644
--- a/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_trace_and_go_back_to_landing_page.png.sha256
@@ -1 +1 @@
-04e0762424dae233fb13d5cfff51a2d3075ad62220538010d0ab376fc79022a9 \ No newline at end of file
+d62fb2e2f4067552d4f9d4170b4ffa45c74171b4de750292ded957cb6b12b669 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
index 4cfdf9f7e..9287876a7 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
@@ -1 +1 @@
-3539c6d2a8ac9d9e15455be491aa171f75f00fdb39e36971b50a060d70732e81 \ No newline at end of file
+30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
index eb2608789..23be44dae 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
@@ -1 +1 @@
-9bac90702af629b8ecec00b99d86704f188b332695dea2eaf49d79aba3fc8670 \ No newline at end of file
+b938d4dfcc109165feaedb9421276a355d03a383a0d21ab91ff72409b18a3ab5 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
index 4cfdf9f7e..9287876a7 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
@@ -1 +1 @@
-3539c6d2a8ac9d9e15455be491aa171f75f00fdb39e36971b50a060d70732e81 \ No newline at end of file
+30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
index d8da34611..9287876a7 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
@@ -1 +1 @@
-150bfec1eb606a548dc39bbdf081efb82a529b7cc39500605c4e56a5d742fea6 \ No newline at end of file
+30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
index a494f13b2..4324721a4 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_to_page_with_no_trace.png.sha256
@@ -1 +1 @@
-8de36401497e509ab127d202b83a056c40c2f5f461254f1ea79fe7a4861b059e \ No newline at end of file
+9d502e8458f85884c7bf1a6411aa3425c63ccf102e6f537318733704e7a416fb \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
index 6d882f60e..535b9b126 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_invalid_trace.png.sha256
@@ -1 +1 @@
-3898ba5cd5fdb63fdef0abced3a1174f5ee864c9b01c7e033e7e2f5e1f0280f2 \ No newline at end of file
+b0d5928fbcf0b7adfc06386ea1961d301ee19f66c61b190f9d00fd5acef824c0 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
index eb2608789..23be44dae 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
@@ -1 +1 @@
-9bac90702af629b8ecec00b99d86704f188b332695dea2eaf49d79aba3fc8670 \ No newline at end of file
+b938d4dfcc109165feaedb9421276a355d03a383a0d21ab91ff72409b18a3ab5 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
index 4cfdf9f7e..9287876a7 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
@@ -1 +1 @@
-3539c6d2a8ac9d9e15455be491aa171f75f00fdb39e36971b50a060d70732e81 \ No newline at end of file
+30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6 \ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
index 4cfdf9f7e..9287876a7 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
@@ -1 +1 @@
-3539c6d2a8ac9d9e15455be491aa171f75f00fdb39e36971b50a060d70732e81 \ No newline at end of file
+30faf223bfc57acbbcca2308c716064d3447dee2673db6329ad9188bf08a59e6 \ No newline at end of file
diff --git a/test/end_to_end_benchmark.cc b/test/end_to_end_benchmark.cc
index ac7f8faa2..ce63780bc 100644
--- a/test/end_to_end_benchmark.cc
+++ b/test/end_to_end_benchmark.cc
@@ -232,7 +232,7 @@ void SaturateCpuProducerArgs(benchmark::internal::Benchmark* b) {
void ConstantRateProducerArgs(benchmark::internal::Benchmark* b) {
int message_count = IsBenchmarkFunctionalOnly() ? 2 * 1024 : 128 * 1024;
- int min_speed = IsBenchmarkFunctionalOnly() ? 64 : 8;
+ int min_speed = IsBenchmarkFunctionalOnly() ? 128 : 8;
int max_speed = 128;
for (int speed = min_speed; speed <= max_speed; speed *= 2) {
b->Args({message_count, 128, speed});
@@ -242,7 +242,7 @@ void ConstantRateProducerArgs(benchmark::internal::Benchmark* b) {
void SaturateCpuConsumerArgs(benchmark::internal::Benchmark* b) {
int min_payload = 8;
- int max_payload = IsBenchmarkFunctionalOnly() ? 16 : 64 * 1024;
+ int max_payload = IsBenchmarkFunctionalOnly() ? 8 : 64 * 1024;
for (int bytes = min_payload; bytes <= max_payload; bytes *= 2) {
b->Args({bytes, 0 /* speed */});
}
diff --git a/test/ftrace_integrationtest.cc b/test/ftrace_integrationtest.cc
index 318b308a9..ae1b1046e 100644
--- a/test/ftrace_integrationtest.cc
+++ b/test/ftrace_integrationtest.cc
@@ -244,7 +244,7 @@ TEST_F(PerfettoFtraceIntegrationTest, MAYBE_KernelAddressSymbolization) {
helper.WaitForConsumerConnect();
TraceConfig trace_config;
- trace_config.add_buffers()->set_size_kb(1024);
+ trace_config.add_buffers()->set_size_kb(64);
auto* ds_config = trace_config.add_data_sources()->mutable_config();
ds_config->set_name("linux.ftrace");
diff --git a/test/test_helper.cc b/test/test_helper.cc
index cbc3aca27..49a996188 100644
--- a/test/test_helper.cc
+++ b/test/test_helper.cc
@@ -290,7 +290,7 @@ void TestHelper::OnTraceStats(bool, const TraceStats&) {}
void TestHelper::OnObservableEvents(const ObservableEvents&) {}
-void TestHelper::OnSessionCloned(bool, const std::string&) {}
+void TestHelper::OnSessionCloned(const OnSessionClonedArgs&) {}
// static
const char* TestHelper::GetDefaultModeConsumerSocketName() {
diff --git a/test/test_helper.h b/test/test_helper.h
index dd18b4c31..2cabd98d3 100644
--- a/test/test_helper.h
+++ b/test/test_helper.h
@@ -290,7 +290,7 @@ class TestHelper : public Consumer {
void OnAttach(bool, const TraceConfig&) override;
void OnTraceStats(bool, const TraceStats&) override;
void OnObservableEvents(const ObservableEvents&) override;
- void OnSessionCloned(bool, const std::string&) override;
+ void OnSessionCloned(const OnSessionClonedArgs&) override;
// Starts the tracing service if in kStartDaemons mode.
void StartServiceIfRequired();
diff --git a/test/trace_processor/diff_tests/android/android_battery_stats_event_slices.out b/test/trace_processor/diff_tests/android/android_battery_stats_event_slices.out
new file mode 100644
index 000000000..82cd36c91
--- /dev/null
+++ b/test/trace_processor/diff_tests/android/android_battery_stats_event_slices.out
@@ -0,0 +1,4 @@
+"ts","dur","track_name","str_value","int_value"
+1000,8000,"battery_stats.top","mail",123
+3000,-1,"battery_stats.job","mail_job",456
+1000,3000,"battery_stats.job","video_job",789
diff --git a/test/trace_processor/diff_tests/android/android_battery_stats_state.out b/test/trace_processor/diff_tests/android/android_battery_stats_state.out
new file mode 100644
index 000000000..04ea9533d
--- /dev/null
+++ b/test/trace_processor/diff_tests/android/android_battery_stats_state.out
@@ -0,0 +1,4 @@
+"ts","track_name","value","value_name","dur"
+1000,"battery_stats.audio",1,"active",-1
+1000,"battery_stats.data_conn",13,"lte",3000
+4000,"battery_stats.data_conn",20,"nr",-1
diff --git a/test/trace_processor/diff_tests/android/android_binder_metric.out b/test/trace_processor/diff_tests/android/android_binder_metric.out
index 8191521c9..09dc24888 100644
--- a/test/trace_processor/diff_tests/android/android_binder_metric.out
+++ b/test/trace_processor/diff_tests/android/android_binder_metric.out
@@ -234,11 +234,13 @@ android_binder {
client_ts: 25827352153
client_dur: 86322
client_tid: 422
+ client_pid: 415
server_process: "system_server"
server_thread: "binder:641_5"
server_ts: 25827417672
server_dur: 11316
server_tid: 1600
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -271,11 +273,13 @@ android_binder {
client_ts: 25827531554
client_dur: 41057
client_tid: 422
+ client_pid: 415
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25827545050
server_dur: 18590
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -308,11 +312,13 @@ android_binder {
client_ts: 25927698833
client_dur: 43619
client_tid: 422
+ client_pid: 415
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25927713489
server_dur: 18478
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -345,11 +351,13 @@ android_binder {
client_ts: 26027844321
client_dur: 76502
client_tid: 422
+ client_pid: 415
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 26027869620
server_dur: 38328
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -382,11 +390,13 @@ android_binder {
client_ts: 26128022950
client_dur: 93620
client_tid: 422
+ client_pid: 415
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 26128060441
server_dur: 42549
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -419,11 +429,13 @@ android_binder {
client_ts: 26228226807
client_dur: 92197
client_tid: 422
+ client_pid: 415
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 26228257962
server_dur: 47691
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -456,11 +468,13 @@ android_binder {
client_ts: 26328427074
client_dur: 88516
client_tid: 422
+ client_pid: 415
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 26328457296
server_dur: 45253
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -493,11 +507,13 @@ android_binder {
client_ts: 21625430256
client_dur: 106084
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21625451288
server_dur: 25329
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -530,11 +546,13 @@ android_binder {
client_ts: 21651104412
client_dur: 1553854
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21651127883
server_dur: 24255
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -567,11 +585,13 @@ android_binder {
client_ts: 21681078075
client_dur: 6957581
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21681097331
server_dur: 20398
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -604,11 +624,13 @@ android_binder {
client_ts: 21713184564
client_dur: 1238385
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21713209886
server_dur: 8733
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -641,11 +663,13 @@ android_binder {
client_ts: 21745330426
client_dur: 2415345
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21745354167
server_dur: 24535
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -678,11 +702,13 @@ android_binder {
client_ts: 21772841582
client_dur: 60073
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21772864934
server_dur: 21372
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -715,11 +741,13 @@ android_binder {
client_ts: 21797991492
client_dur: 58946
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21798015547
server_dur: 20885
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -752,11 +780,13 @@ android_binder {
client_ts: 21823141587
client_dur: 61370
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21823167028
server_dur: 21656
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -789,11 +819,13 @@ android_binder {
client_ts: 21848290804
client_dur: 60709
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21848316259
server_dur: 20391
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -826,11 +858,13 @@ android_binder {
client_ts: 21873440775
client_dur: 55934
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21873461764
server_dur: 21136
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -863,11 +897,13 @@ android_binder {
client_ts: 21898589558
client_dur: 58875
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21898611789
server_dur: 20494
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -900,11 +936,13 @@ android_binder {
client_ts: 21923738957
client_dur: 64169
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21923761253
server_dur: 25784
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -937,11 +975,13 @@ android_binder {
client_ts: 21948891420
client_dur: 64699
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21948920277
server_dur: 20540
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -974,11 +1014,13 @@ android_binder {
client_ts: 21974296208
client_dur: 104989
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21974341636
server_dur: 25187
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1011,11 +1053,13 @@ android_binder {
client_ts: 21999539011
client_dur: 71202
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21999568501
server_dur: 20357
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1048,11 +1092,13 @@ android_binder {
client_ts: 22024711257
client_dur: 328183
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22024736108
server_dur: 25338
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1085,11 +1131,13 @@ android_binder {
client_ts: 22050132357
client_dur: 59459
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22050156562
server_dur: 20679
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1122,11 +1170,13 @@ android_binder {
client_ts: 22075288214
client_dur: 58461
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22075311405
server_dur: 20809
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1159,11 +1209,13 @@ android_binder {
client_ts: 22100443015
client_dur: 66715
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22100466870
server_dur: 19761
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1196,11 +1248,13 @@ android_binder {
client_ts: 22125600618
client_dur: 65545
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22125623322
server_dur: 20702
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1233,11 +1287,13 @@ android_binder {
client_ts: 22150759363
client_dur: 56369
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22150779993
server_dur: 22255
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1270,11 +1326,13 @@ android_binder {
client_ts: 22175906178
client_dur: 63847
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22175929226
server_dur: 25370
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1307,11 +1365,13 @@ android_binder {
client_ts: 22201561660
client_dur: 209987
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22201735902
server_dur: 20781
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1344,11 +1404,13 @@ android_binder {
client_ts: 22227603566
client_dur: 61556
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22227627247
server_dur: 19354
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1381,11 +1443,13 @@ android_binder {
client_ts: 22252767831
client_dur: 65418
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22252793033
server_dur: 24322
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1418,11 +1482,13 @@ android_binder {
client_ts: 22277925922
client_dur: 297059
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22278187629
server_dur: 20875
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1455,11 +1521,13 @@ android_binder {
client_ts: 22303375651
client_dur: 55580
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22303396802
server_dur: 20656
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1492,11 +1560,13 @@ android_binder {
client_ts: 22328804156
client_dur: 83145
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22328852158
server_dur: 21212
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1529,11 +1599,13 @@ android_binder {
client_ts: 22354003523
client_dur: 56819
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22354025291
server_dur: 20568
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1566,11 +1638,13 @@ android_binder {
client_ts: 22379156345
client_dur: 66779
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22379180900
server_dur: 25632
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1603,11 +1677,13 @@ android_binder {
client_ts: 22404448968
client_dur: 67438
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22404473541
server_dur: 24816
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1640,11 +1716,13 @@ android_binder {
client_ts: 22429616334
client_dur: 74108
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22429639907
server_dur: 32292
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1677,11 +1755,13 @@ android_binder {
client_ts: 22455238568
client_dur: 55788
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22455259634
server_dur: 20555
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1714,11 +1794,13 @@ android_binder {
client_ts: 22480383875
client_dur: 56554
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22480404678
server_dur: 20572
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1751,11 +1833,13 @@ android_binder {
client_ts: 22505531489
client_dur: 59218
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22505553139
server_dur: 22859
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1788,11 +1872,13 @@ android_binder {
client_ts: 22531090402
client_dur: 56749
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22531111630
server_dur: 20210
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1825,11 +1911,13 @@ android_binder {
client_ts: 22556242635
client_dur: 57252
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22556262293
server_dur: 20917
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1862,11 +1950,13 @@ android_binder {
client_ts: 22581426858
client_dur: 266380
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22581641694
server_dur: 31182
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1905,11 +1995,13 @@ android_binder {
client_ts: 22606961662
client_dur: 557886
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22606985795
server_dur: 21756
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1942,11 +2034,13 @@ android_binder {
client_ts: 22632616662
client_dur: 57814
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22632638644
server_dur: 20728
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -1979,11 +2073,13 @@ android_binder {
client_ts: 22657890096
client_dur: 63825
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22657912861
server_dur: 22058
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2016,11 +2112,13 @@ android_binder {
client_ts: 22683093531
client_dur: 80792
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22683116244
server_dur: 21278
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2059,11 +2157,13 @@ android_binder {
client_ts: 22708307977
client_dur: 67445
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22708332522
server_dur: 26370
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2096,11 +2196,13 @@ android_binder {
client_ts: 22733506276
client_dur: 119221
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22733593661
server_dur: 19257
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2133,11 +2235,13 @@ android_binder {
client_ts: 22758727072
client_dur: 446508
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22759138073
server_dur: 20676
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2170,11 +2274,13 @@ android_binder {
client_ts: 22784311059
client_dur: 161051
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22784409798
server_dur: 20874
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2207,11 +2313,13 @@ android_binder {
client_ts: 22809748047
client_dur: 57852
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22809770020
server_dur: 20538
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2244,11 +2352,13 @@ android_binder {
client_ts: 22834902012
client_dur: 93361
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22834959559
server_dur: 21369
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2281,11 +2391,13 @@ android_binder {
client_ts: 22860898758
client_dur: 82717
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22860942436
server_dur: 21910
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2318,11 +2430,13 @@ android_binder {
client_ts: 22886110503
client_dur: 99316
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22886176653
server_dur: 20849
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2355,11 +2469,13 @@ android_binder {
client_ts: 22911318220
client_dur: 66992
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22911345648
server_dur: 22362
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2392,11 +2508,13 @@ android_binder {
client_ts: 22936549304
client_dur: 58969
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22936570719
server_dur: 21297
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2429,11 +2547,13 @@ android_binder {
client_ts: 22961701152
client_dur: 676548
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22962339912
server_dur: 22166
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2466,11 +2586,13 @@ android_binder {
client_ts: 22987512708
client_dur: 79649
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22987551432
server_dur: 24288
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2509,11 +2631,13 @@ android_binder {
client_ts: 23013143578
client_dur: 61635
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23013168634
server_dur: 20531
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2546,11 +2670,13 @@ android_binder {
client_ts: 23038642421
client_dur: 137175
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23038736570
server_dur: 20651
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2583,11 +2709,13 @@ android_binder {
client_ts: 23063886880
client_dur: 55663
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23063908358
server_dur: 16544
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2620,11 +2748,13 @@ android_binder {
client_ts: 23089198686
client_dur: 68926
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23089221371
server_dur: 23561
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2663,11 +2793,13 @@ android_binder {
client_ts: 23114443451
client_dur: 64468
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23114469373
server_dur: 23341
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2700,11 +2832,13 @@ android_binder {
client_ts: 23139601722
client_dur: 78228
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23139640251
server_dur: 21320
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2737,11 +2871,13 @@ android_binder {
client_ts: 23164771069
client_dur: 91260
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23164821900
server_dur: 21423
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2774,11 +2910,13 @@ android_binder {
client_ts: 23189996807
client_dur: 214050
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23190162200
server_dur: 20825
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2817,11 +2955,13 @@ android_binder {
client_ts: 23215317200
client_dur: 57982
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23215338281
server_dur: 21069
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2854,11 +2994,13 @@ android_binder {
client_ts: 23240472994
client_dur: 61104
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23240494382
server_dur: 22737
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2891,11 +3033,13 @@ android_binder {
client_ts: 23265633084
client_dur: 257686
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23265855074
server_dur: 21119
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2928,11 +3072,13 @@ android_binder {
client_ts: 23294001031
client_dur: 68360
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23294024310
server_dur: 25000
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -2965,11 +3111,13 @@ android_binder {
client_ts: 23319166709
client_dur: 255922
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23319381423
server_dur: 24946
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3002,11 +3150,13 @@ android_binder {
client_ts: 23344525034
client_dur: 66275
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23344548135
server_dur: 25737
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3039,11 +3189,13 @@ android_binder {
client_ts: 23369688943
client_dur: 61329
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23369711803
server_dur: 22061
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3076,11 +3228,13 @@ android_binder {
client_ts: 23394850079
client_dur: 540888
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23395351729
server_dur: 22192
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3113,11 +3267,13 @@ android_binder {
client_ts: 23420492464
client_dur: 65743
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23420518127
server_dur: 22480
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3150,11 +3306,13 @@ android_binder {
client_ts: 23451713078
client_dur: 68421
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23451738606
server_dur: 24478
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3187,11 +3345,13 @@ android_binder {
client_ts: 23476881893
client_dur: 64782
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23476905553
server_dur: 24602
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3224,11 +3384,13 @@ android_binder {
client_ts: 23502042821
client_dur: 820095
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23502825079
server_dur: 23414
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3261,11 +3423,13 @@ android_binder {
client_ts: 23527974198
client_dur: 845116
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23528782089
server_dur: 23126
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3298,11 +3462,13 @@ android_binder {
client_ts: 23553917567
client_dur: 59738
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23553940355
server_dur: 21362
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3335,11 +3501,13 @@ android_binder {
client_ts: 23579071838
client_dur: 411519
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23579443790
server_dur: 25365
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3372,11 +3540,13 @@ android_binder {
client_ts: 23604582593
client_dur: 210023
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23604751577
server_dur: 24165
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3409,11 +3579,13 @@ android_binder {
client_ts: 23629892322
client_dur: 194538
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23630049856
server_dur: 21631
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3446,11 +3618,13 @@ android_binder {
client_ts: 23655179880
client_dur: 142025
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23655273690
server_dur: 30591
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3483,11 +3657,13 @@ android_binder {
client_ts: 23680421874
client_dur: 72852
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23680450743
server_dur: 26736
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3520,11 +3696,13 @@ android_binder {
client_ts: 23705597440
client_dur: 470856
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23706033599
server_dur: 21348
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3557,11 +3735,13 @@ android_binder {
client_ts: 23731172177
client_dur: 184006
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23731318438
server_dur: 21088
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3594,11 +3774,13 @@ android_binder {
client_ts: 23757576836
client_dur: 69175
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23757598859
server_dur: 22748
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3631,11 +3813,13 @@ android_binder {
client_ts: 23782737996
client_dur: 59451
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23782758417
server_dur: 25123
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3668,11 +3852,13 @@ android_binder {
client_ts: 23807891211
client_dur: 62509
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23807914516
server_dur: 23582
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3705,11 +3891,13 @@ android_binder {
client_ts: 23833055418
client_dur: 163286
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23833182220
server_dur: 22315
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3742,11 +3930,13 @@ android_binder {
client_ts: 23858313038
client_dur: 57714
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23858335729
server_dur: 20454
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3779,11 +3969,13 @@ android_binder {
client_ts: 23883462809
client_dur: 59212
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23883487934
server_dur: 19666
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3816,11 +4008,13 @@ android_binder {
client_ts: 23908617410
client_dur: 67454
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23908643220
server_dur: 25095
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3853,11 +4047,13 @@ android_binder {
client_ts: 23933826058
client_dur: 54993
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23933846583
server_dur: 19834
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3890,11 +4086,13 @@ android_binder {
client_ts: 23958974344
client_dur: 56757
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23958997349
server_dur: 19668
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3927,11 +4125,13 @@ android_binder {
client_ts: 23984212731
client_dur: 65425
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23984244337
server_dur: 18760
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -3964,11 +4164,13 @@ android_binder {
client_ts: 24009326493
client_dur: 55937
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24009348026
server_dur: 20878
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4001,11 +4203,13 @@ android_binder {
client_ts: 24034474905
client_dur: 323973
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24034762131
server_dur: 21724
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4038,11 +4242,13 @@ android_binder {
client_ts: 24059888481
client_dur: 269355
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24060121507
server_dur: 21099
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4075,11 +4281,13 @@ android_binder {
client_ts: 24085507070
client_dur: 65864
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24085532155
server_dur: 24607
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4112,11 +4320,13 @@ android_binder {
client_ts: 24110668836
client_dur: 62135
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24110692176
server_dur: 23546
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4149,11 +4359,13 @@ android_binder {
client_ts: 24135822325
client_dur: 55790
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24135843301
server_dur: 20745
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4186,11 +4398,13 @@ android_binder {
client_ts: 24160973601
client_dur: 64296
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24160998105
server_dur: 24373
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4223,11 +4437,13 @@ android_binder {
client_ts: 24186129350
client_dur: 61214
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24186153807
server_dur: 21100
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4260,11 +4476,13 @@ android_binder {
client_ts: 24211335205
client_dur: 99239
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24211379278
server_dur: 25032
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4297,11 +4515,13 @@ android_binder {
client_ts: 24236559912
client_dur: 85757
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24236597491
server_dur: 27319
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4334,11 +4554,13 @@ android_binder {
client_ts: 24261743662
client_dur: 72120
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24261771646
server_dur: 25209
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4371,11 +4593,13 @@ android_binder {
client_ts: 24286913419
client_dur: 330217
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24287198196
server_dur: 22848
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4408,11 +4632,13 @@ android_binder {
client_ts: 24312358034
client_dur: 69020
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24312388724
server_dur: 21476
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4451,11 +4677,13 @@ android_binder {
client_ts: 24337574519
client_dur: 104255
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24337613079
server_dur: 33967
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4488,11 +4716,13 @@ android_binder {
client_ts: 24362804629
client_dur: 58822
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24362826557
server_dur: 20783
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4525,11 +4755,13 @@ android_binder {
client_ts: 24387968494
client_dur: 63171
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24387991414
server_dur: 24460
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4562,11 +4794,13 @@ android_binder {
client_ts: 24414399633
client_dur: 3357310
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24414422286
server_dur: 20459
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4599,11 +4833,13 @@ android_binder {
client_ts: 24443111092
client_dur: 63218
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24443132289
server_dur: 23717
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4636,11 +4872,13 @@ android_binder {
client_ts: 24468268772
client_dur: 63940
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24468295057
server_dur: 21634
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4673,11 +4911,13 @@ android_binder {
client_ts: 24493507908
client_dur: 75072
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24493536500
server_dur: 22590
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4710,11 +4950,13 @@ android_binder {
client_ts: 24518715570
client_dur: 83147
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24518746589
server_dur: 20133
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4747,11 +4989,13 @@ android_binder {
client_ts: 24544028919
client_dur: 105487
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24544069334
server_dur: 24026
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4784,11 +5028,13 @@ android_binder {
client_ts: 24569328112
client_dur: 106610
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24569369501
server_dur: 41826
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4821,11 +5067,13 @@ android_binder {
client_ts: 24594543032
client_dur: 45871
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24594558488
server_dur: 20382
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4852,11 +5100,13 @@ android_binder {
client_ts: 24619690623
client_dur: 58336
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24619710131
server_dur: 25779
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4883,11 +5133,13 @@ android_binder {
client_ts: 24644930551
client_dur: 105892
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24644975052
server_dur: 34388
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4920,11 +5172,13 @@ android_binder {
client_ts: 24670207638
client_dur: 54225
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24670224041
server_dur: 26208
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4951,11 +5205,13 @@ android_binder {
client_ts: 24695363832
client_dur: 47347
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24695380382
server_dur: 19885
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -4982,11 +5238,13 @@ android_binder {
client_ts: 24720504163
client_dur: 41635
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24720517121
server_dur: 18951
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5013,11 +5271,13 @@ android_binder {
client_ts: 24745651155
client_dur: 50201
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24745667169
server_dur: 21953
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5044,11 +5304,13 @@ android_binder {
client_ts: 24770795510
client_dur: 45248
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24770810644
server_dur: 19730
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5075,11 +5337,13 @@ android_binder {
client_ts: 24795949562
client_dur: 44458
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24795964339
server_dur: 19474
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5106,11 +5370,13 @@ android_binder {
client_ts: 24821098319
client_dur: 45736
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24821113887
server_dur: 19916
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5137,11 +5403,13 @@ android_binder {
client_ts: 24846533416
client_dur: 52565
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24846550147
server_dur: 20978
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5168,11 +5436,13 @@ android_binder {
client_ts: 24871959612
client_dur: 33762
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24871969021
server_dur: 15109
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5199,11 +5469,13 @@ android_binder {
client_ts: 24897089502
client_dur: 36235
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24897101194
server_dur: 15306
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5230,11 +5502,13 @@ android_binder {
client_ts: 24922327702
client_dur: 47487
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24922343062
server_dur: 20895
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5261,11 +5535,13 @@ android_binder {
client_ts: 24947478390
client_dur: 50011
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24947495490
server_dur: 21244
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5292,11 +5568,13 @@ android_binder {
client_ts: 24972625739
client_dur: 46864
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24972642054
server_dur: 20460
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5323,11 +5601,13 @@ android_binder {
client_ts: 24997766928
client_dur: 105830
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24997800832
server_dur: 45031
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5360,11 +5640,13 @@ android_binder {
client_ts: 25023405381
client_dur: 86423
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25023438732
server_dur: 29757
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5397,11 +5679,13 @@ android_binder {
client_ts: 25048609139
client_dur: 56222
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25048631235
server_dur: 16655
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5434,11 +5718,13 @@ android_binder {
client_ts: 25073875780
client_dur: 84120
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25073898205
server_dur: 15854
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5471,11 +5757,13 @@ android_binder {
client_ts: 25099064916
client_dur: 204188
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25099198462
server_dur: 49025
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5508,11 +5796,13 @@ android_binder {
client_ts: 25124642124
client_dur: 68889
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25124666670
server_dur: 29243
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5539,11 +5829,13 @@ android_binder {
client_ts: 25149891522
client_dur: 60500
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25149912505
server_dur: 27000
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5570,11 +5862,13 @@ android_binder {
client_ts: 25175121734
client_dur: 65293
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25175141892
server_dur: 23570
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5607,11 +5901,13 @@ android_binder {
client_ts: 25200283959
client_dur: 44045
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25200298152
server_dur: 19339
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5638,11 +5934,13 @@ android_binder {
client_ts: 25225419452
client_dur: 43144
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25225434070
server_dur: 18615
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5669,11 +5967,13 @@ android_binder {
client_ts: 25250561510
client_dur: 82814
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25250589325
server_dur: 36944
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5706,11 +6006,13 @@ android_binder {
client_ts: 25275837002
client_dur: 111602
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25275893327
server_dur: 33040
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5743,11 +6045,13 @@ android_binder {
client_ts: 25301779154
client_dur: 81058
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25301805031
server_dur: 24119
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5780,11 +6084,13 @@ android_binder {
client_ts: 25327028096
client_dur: 144639
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25327077936
server_dur: 53753
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5817,11 +6123,13 @@ android_binder {
client_ts: 25352301178
client_dur: 837973
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25353047151
server_dur: 48734
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5854,11 +6162,13 @@ android_binder {
client_ts: 25378250275
client_dur: 77754
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25378276198
server_dur: 28616
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5891,11 +6201,13 @@ android_binder {
client_ts: 25403423456
client_dur: 65101
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25403445450
server_dur: 23191
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -5929,11 +6241,13 @@ android_binder {
client_ts: 25403532822
client_dur: 243238
client_tid: 492
+ client_pid: 492
server_process: "system_server"
server_thread: "binder:641_4"
server_ts: 25403547799
server_dur: 210707
server_tid: 1596
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -5972,11 +6286,13 @@ android_binder {
client_ts: 25403800150
client_dur: 77678
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25403821750
server_dur: 43829
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6009,11 +6325,13 @@ android_binder {
client_ts: 25429003446
client_dur: 55342
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25429021995
server_dur: 20582
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6046,11 +6364,13 @@ android_binder {
client_ts: 25454157095
client_dur: 68221
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25454182918
server_dur: 20352
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6083,11 +6403,13 @@ android_binder {
client_ts: 25479325945
client_dur: 157863
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25479422370
server_dur: 35765
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6120,11 +6442,13 @@ android_binder {
client_ts: 25504631134
client_dur: 1082750
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25505253998
server_dur: 109396
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6158,11 +6482,13 @@ android_binder {
client_ts: 25505818197
client_dur: 3125407
client_tid: 492
+ client_pid: 492
server_process: "system_server"
server_thread: "binder:641_4"
server_ts: 25505891588
server_dur: 3000749
server_tid: 1596
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -6220,11 +6546,13 @@ android_binder {
client_ts: 25508998675
client_dur: 379026
client_tid: 492
+ client_pid: 492
server_process: "system_server"
server_thread: "binder:641_4"
server_ts: 25509052778
server_dur: 272193
server_tid: 1596
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6257,11 +6585,13 @@ android_binder {
client_ts: 25512878756
client_dur: 151351
client_tid: 492
+ client_pid: 492
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25512939518
server_dur: 62943
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6294,11 +6624,13 @@ android_binder {
client_ts: 21612276580
client_dur: 39977
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21612292301
server_dur: 14064
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6331,11 +6663,13 @@ android_binder {
client_ts: 21637405403
client_dur: 60035
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21637427285
server_dur: 24550
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6368,11 +6702,13 @@ android_binder {
client_ts: 21662560974
client_dur: 372941
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21662897046
server_dur: 22907
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6405,11 +6741,13 @@ android_binder {
client_ts: 21688024281
client_dur: 59297
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21688047484
server_dur: 21173
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6442,11 +6780,13 @@ android_binder {
client_ts: 21713127573
client_dur: 63596
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21713152373
server_dur: 21155
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6479,11 +6819,13 @@ android_binder {
client_ts: 21738283156
client_dur: 60407
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21738305184
server_dur: 24886
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6516,11 +6858,13 @@ android_binder {
client_ts: 21763445363
client_dur: 70801
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21763467940
server_dur: 30748
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6553,11 +6897,13 @@ android_binder {
client_ts: 21788612931
client_dur: 57076
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21788635008
server_dur: 21359
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6590,11 +6936,13 @@ android_binder {
client_ts: 21813762065
client_dur: 61236
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21813783295
server_dur: 25042
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6627,11 +6975,13 @@ android_binder {
client_ts: 21838919344
client_dur: 59886
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21838943470
server_dur: 20686
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6664,11 +7014,13 @@ android_binder {
client_ts: 21864144722
client_dur: 71604
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21864171886
server_dur: 25966
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6701,11 +7053,13 @@ android_binder {
client_ts: 21889317261
client_dur: 517889
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21889524828
server_dur: 21638
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6738,11 +7092,13 @@ android_binder {
client_ts: 21914927560
client_dur: 59832
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21914949348
server_dur: 23104
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6775,11 +7131,13 @@ android_binder {
client_ts: 21940080190
client_dur: 63873
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21940103851
server_dur: 24784
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6812,11 +7170,13 @@ android_binder {
client_ts: 21965236304
client_dur: 87480
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21965262841
server_dur: 47604
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -6855,11 +7215,13 @@ android_binder {
client_ts: 21990454958
client_dur: 89222
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21990491103
server_dur: 25934
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6892,11 +7254,13 @@ android_binder {
client_ts: 22015656850
client_dur: 62246
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22015682089
server_dur: 21161
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6929,11 +7293,13 @@ android_binder {
client_ts: 22040814163
client_dur: 64221
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22040838835
server_dur: 24377
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -6966,11 +7332,13 @@ android_binder {
client_ts: 22066737714
client_dur: 128820
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22066831151
server_dur: 19563
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7003,11 +7371,13 @@ android_binder {
client_ts: 22091960087
client_dur: 58325
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22091982875
server_dur: 21344
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7040,11 +7410,13 @@ android_binder {
client_ts: 22117113923
client_dur: 63410
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22117137718
server_dur: 23868
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7077,11 +7449,13 @@ android_binder {
client_ts: 22142267357
client_dur: 59986
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22142291376
server_dur: 21134
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7114,11 +7488,13 @@ android_binder {
client_ts: 22167423522
client_dur: 59967
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22167445520
server_dur: 22511
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7151,11 +7527,13 @@ android_binder {
client_ts: 22192579344
client_dur: 60820
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22192603786
server_dur: 21006
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7188,11 +7566,13 @@ android_binder {
client_ts: 22217730341
client_dur: 55283
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22217750903
server_dur: 20680
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7225,11 +7605,13 @@ android_binder {
client_ts: 22242880300
client_dur: 71100
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22242905309
server_dur: 26682
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7262,11 +7644,13 @@ android_binder {
client_ts: 22268043393
client_dur: 409558
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22268414904
server_dur: 21405
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7299,11 +7683,13 @@ android_binder {
client_ts: 22293548146
client_dur: 63871
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22293572042
server_dur: 22980
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7336,11 +7722,13 @@ android_binder {
client_ts: 22318716098
client_dur: 339826
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22318736854
server_dur: 23010
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7373,11 +7761,13 @@ android_binder {
client_ts: 22344146679
client_dur: 110188
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22344218394
server_dur: 24011
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7410,11 +7800,13 @@ android_binder {
client_ts: 22369334226
client_dur: 94388
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22369355609
server_dur: 48856
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7447,11 +7839,13 @@ android_binder {
client_ts: 22394536230
client_dur: 62982
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22394561551
server_dur: 22059
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7484,11 +7878,13 @@ android_binder {
client_ts: 22419697576
client_dur: 61323
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22419722756
server_dur: 21994
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7521,11 +7917,13 @@ android_binder {
client_ts: 22445031509
client_dur: 50515
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22445050820
server_dur: 17128
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7558,11 +7956,13 @@ android_binder {
client_ts: 22470174653
client_dur: 55822
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22470196239
server_dur: 21286
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7595,11 +7995,13 @@ android_binder {
client_ts: 22495325972
client_dur: 68180
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22495350975
server_dur: 26711
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7632,11 +8034,13 @@ android_binder {
client_ts: 22521360985
client_dur: 234231
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22521382730
server_dur: 21186
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7669,11 +8073,13 @@ android_binder {
client_ts: 22546697891
client_dur: 98444
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22546761058
server_dur: 19881
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7706,11 +8112,13 @@ android_binder {
client_ts: 22571892907
client_dur: 66101
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22571916881
server_dur: 25795
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7743,11 +8151,13 @@ android_binder {
client_ts: 22597062070
client_dur: 259462
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22597272531
server_dur: 34173
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7780,11 +8190,13 @@ android_binder {
client_ts: 22622418577
client_dur: 59816
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22622443274
server_dur: 21430
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7817,11 +8229,13 @@ android_binder {
client_ts: 22650180912
client_dur: 473997
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22650255041
server_dur: 19254
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7854,11 +8268,13 @@ android_binder {
client_ts: 22675764005
client_dur: 70615
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22675789713
server_dur: 25069
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7891,11 +8307,13 @@ android_binder {
client_ts: 22701432879
client_dur: 450491
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22701762194
server_dur: 23978
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7928,11 +8346,13 @@ android_binder {
client_ts: 22726978606
client_dur: 401005
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22727339544
server_dur: 23475
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -7965,11 +8385,13 @@ android_binder {
client_ts: 22752478293
client_dur: 586574
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22753025360
server_dur: 21422
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8002,11 +8424,13 @@ android_binder {
client_ts: 22778161650
client_dur: 349397
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22778472830
server_dur: 22980
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8039,11 +8463,13 @@ android_binder {
client_ts: 22803612048
client_dur: 67634
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22803636072
server_dur: 23917
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8076,11 +8502,13 @@ android_binder {
client_ts: 22828777874
client_dur: 318230
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22828822556
server_dur: 26877
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8113,11 +8541,13 @@ android_binder {
client_ts: 22854196228
client_dur: 561632
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22854720488
server_dur: 21460
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8150,11 +8580,13 @@ android_binder {
client_ts: 22879856680
client_dur: 63364
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22879882339
server_dur: 22238
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8187,11 +8619,13 @@ android_binder {
client_ts: 22905018627
client_dur: 66122
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22905041577
server_dur: 26326
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8224,11 +8658,13 @@ android_binder {
client_ts: 22930183511
client_dur: 67161
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22930213119
server_dur: 23605
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8261,11 +8697,13 @@ android_binder {
client_ts: 22955349414
client_dur: 156341
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22955463649
server_dur: 24599
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8298,11 +8736,13 @@ android_binder {
client_ts: 22980607439
client_dur: 65794
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22980629549
server_dur: 26192
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8335,11 +8775,13 @@ android_binder {
client_ts: 23005774838
client_dur: 62936
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23005798704
server_dur: 23801
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8372,11 +8814,13 @@ android_binder {
client_ts: 23030941978
client_dur: 89285
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23030973182
server_dur: 37855
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8409,11 +8853,13 @@ android_binder {
client_ts: 23056174448
client_dur: 200618
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23056329883
server_dur: 23980
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8446,11 +8892,13 @@ android_binder {
client_ts: 23081467052
client_dur: 59125
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23081486828
server_dur: 24680
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8483,11 +8931,13 @@ android_binder {
client_ts: 23106620846
client_dur: 61616
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23106642188
server_dur: 24012
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8520,11 +8970,13 @@ android_binder {
client_ts: 23131777328
client_dur: 123447
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23131861232
server_dur: 22637
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8557,11 +9009,13 @@ android_binder {
client_ts: 23157002672
client_dur: 79156
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23157030248
server_dur: 27226
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8594,11 +9048,13 @@ android_binder {
client_ts: 23182173903
client_dur: 376646
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23182500065
server_dur: 21132
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8631,11 +9087,13 @@ android_binder {
client_ts: 23207650439
client_dur: 67278
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23207680535
server_dur: 23155
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8668,11 +9126,13 @@ android_binder {
client_ts: 23233851428
client_dur: 892848
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23233871293
server_dur: 23312
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8705,11 +9165,13 @@ android_binder {
client_ts: 23259841421
client_dur: 63174
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23259863994
server_dur: 23889
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8742,11 +9204,13 @@ android_binder {
client_ts: 23284999517
client_dur: 56437
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23285019554
server_dur: 21307
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8779,11 +9243,13 @@ android_binder {
client_ts: 23310151865
client_dur: 642229
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23310751409
server_dur: 26103
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8816,11 +9282,13 @@ android_binder {
client_ts: 23335905400
client_dur: 357982
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23336222503
server_dur: 25821
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8853,11 +9321,13 @@ android_binder {
client_ts: 23361328882
client_dur: 63784
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23361351852
server_dur: 24700
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8890,11 +9360,13 @@ android_binder {
client_ts: 23386869959
client_dur: 66376
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23386894766
server_dur: 25613
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8927,11 +9399,13 @@ android_binder {
client_ts: 23412468379
client_dur: 144242
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23412492591
server_dur: 28309
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -8964,11 +9438,13 @@ android_binder {
client_ts: 23437712307
client_dur: 61646
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23437733692
server_dur: 21877
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9001,11 +9477,13 @@ android_binder {
client_ts: 23462870779
client_dur: 64694
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23462898239
server_dur: 21829
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9038,11 +9516,13 @@ android_binder {
client_ts: 23488042638
client_dur: 69970
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23488068942
server_dur: 26303
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9075,11 +9555,13 @@ android_binder {
client_ts: 23513211192
client_dur: 57998
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23513232838
server_dur: 22355
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9112,11 +9594,13 @@ android_binder {
client_ts: 23538364057
client_dur: 90805
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23538417034
server_dur: 21543
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9149,11 +9633,13 @@ android_binder {
client_ts: 23563555747
client_dur: 62301
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23563577896
server_dur: 23477
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9186,11 +9672,13 @@ android_binder {
client_ts: 23588716088
client_dur: 122069
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23588796199
server_dur: 21803
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9223,11 +9711,13 @@ android_binder {
client_ts: 23613942195
client_dur: 406560
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23614311041
server_dur: 21665
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9260,11 +9750,13 @@ android_binder {
client_ts: 23639449764
client_dur: 297834
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23639707345
server_dur: 24585
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9297,11 +9789,13 @@ android_binder {
client_ts: 23664840926
client_dur: 64026
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23664863549
server_dur: 25828
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9334,11 +9828,13 @@ android_binder {
client_ts: 23689999571
client_dur: 60667
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23690020989
server_dur: 24039
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9371,11 +9867,13 @@ android_binder {
client_ts: 23715668567
client_dur: 55651
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23715687865
server_dur: 20534
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9408,11 +9906,13 @@ android_binder {
client_ts: 23740820398
client_dur: 69779
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23740846289
server_dur: 26005
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9445,11 +9945,13 @@ android_binder {
client_ts: 23765983216
client_dur: 63111
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23766008333
server_dur: 22489
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9482,11 +9984,13 @@ android_binder {
client_ts: 23791142714
client_dur: 62184
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23791165515
server_dur: 24176
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9519,11 +10023,13 @@ android_binder {
client_ts: 23816748979
client_dur: 97527
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23816810994
server_dur: 19216
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9556,11 +10062,13 @@ android_binder {
client_ts: 23841937008
client_dur: 265351
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23842045870
server_dur: 21030
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9593,11 +10101,13 @@ android_binder {
client_ts: 23867298197
client_dur: 65269
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23867323342
server_dur: 24762
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9630,11 +10140,13 @@ android_binder {
client_ts: 23892458661
client_dur: 61895
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23892481485
server_dur: 23511
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9667,11 +10179,13 @@ android_binder {
client_ts: 23917612205
client_dur: 60756
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23917632161
server_dur: 27790
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9704,11 +10218,13 @@ android_binder {
client_ts: 23942767445
client_dur: 56639
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23942789248
server_dur: 20150
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9741,11 +10257,13 @@ android_binder {
client_ts: 23967917345
client_dur: 61714
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23967941212
server_dur: 23677
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9778,11 +10296,13 @@ android_binder {
client_ts: 23993073217
client_dur: 61426
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23993098746
server_dur: 21011
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9815,11 +10335,13 @@ android_binder {
client_ts: 24018227157
client_dur: 154788
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24018346321
server_dur: 21354
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9852,11 +10374,13 @@ android_binder {
client_ts: 24043472861
client_dur: 56072
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24043492721
server_dur: 20952
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9889,11 +10413,13 @@ android_binder {
client_ts: 24068623147
client_dur: 61422
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24068647003
server_dur: 23307
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9926,11 +10452,13 @@ android_binder {
client_ts: 24094174551
client_dur: 60440
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24094198265
server_dur: 20963
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -9963,11 +10491,13 @@ android_binder {
client_ts: 24119330336
client_dur: 62796
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24119353765
server_dur: 24014
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10000,11 +10530,13 @@ android_binder {
client_ts: 24144486541
client_dur: 57521
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24144507336
server_dur: 20651
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10037,11 +10569,13 @@ android_binder {
client_ts: 24169644272
client_dur: 59318
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24169667507
server_dur: 21848
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10074,11 +10608,13 @@ android_binder {
client_ts: 24194796993
client_dur: 61133
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24194818919
server_dur: 24981
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10111,11 +10647,13 @@ android_binder {
client_ts: 24219976971
client_dur: 80874
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24220009018
server_dur: 24029
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10148,11 +10686,13 @@ android_binder {
client_ts: 24245182141
client_dur: 75715
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24245212188
server_dur: 24869
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10185,11 +10725,13 @@ android_binder {
client_ts: 24270354623
client_dur: 72978
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24270381508
server_dur: 24460
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10222,11 +10764,13 @@ android_binder {
client_ts: 24296497808
client_dur: 74119
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24296524147
server_dur: 25619
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10259,11 +10803,13 @@ android_binder {
client_ts: 24321677437
client_dur: 1068351
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24322701227
server_dur: 22458
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10296,11 +10842,13 @@ android_binder {
client_ts: 24349464998
client_dur: 600120
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24349498235
server_dur: 21721
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10333,11 +10881,13 @@ android_binder {
client_ts: 24375203138
client_dur: 200814
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24375371665
server_dur: 20774
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10370,11 +10920,13 @@ android_binder {
client_ts: 24400499298
client_dur: 1655381
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24400525814
server_dur: 20740
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10407,11 +10959,13 @@ android_binder {
client_ts: 24427255856
client_dur: 74073
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24427281368
server_dur: 33400
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10444,11 +10998,13 @@ android_binder {
client_ts: 24452425092
client_dur: 66019
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24452453488
server_dur: 22713
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10481,11 +11037,13 @@ android_binder {
client_ts: 24477584081
client_dur: 77570
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24477603311
server_dur: 20359
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10518,11 +11076,13 @@ android_binder {
client_ts: 24502766882
client_dur: 85030
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24502792394
server_dur: 34540
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10555,11 +11115,13 @@ android_binder {
client_ts: 24528063792
client_dur: 88744
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24528100762
server_dur: 19035
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10592,11 +11154,13 @@ android_binder {
client_ts: 24553269933
client_dur: 102641
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24553320732
server_dur: 19753
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10629,11 +11193,13 @@ android_binder {
client_ts: 24578496582
client_dur: 75733
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24578522139
server_dur: 31879
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10666,11 +11232,13 @@ android_binder {
client_ts: 24603666160
client_dur: 32902
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24603676548
server_dur: 13734
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10703,11 +11271,13 @@ android_binder {
client_ts: 24628827055
client_dur: 77433
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24628855199
server_dur: 31376
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10740,11 +11310,13 @@ android_binder {
client_ts: 24654016554
client_dur: 82862
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24654047419
server_dur: 27392
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10777,11 +11349,13 @@ android_binder {
client_ts: 24679300128
client_dur: 51067
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24679317330
server_dur: 23251
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10814,11 +11388,13 @@ android_binder {
client_ts: 24704445330
client_dur: 53313
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24704463794
server_dur: 20543
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10851,11 +11427,13 @@ android_binder {
client_ts: 24729604221
client_dur: 73960
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24729643378
server_dur: 19819
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10888,11 +11466,13 @@ android_binder {
client_ts: 24754787089
client_dur: 79191
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24754812563
server_dur: 21216
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10925,11 +11505,13 @@ android_binder {
client_ts: 24779973546
client_dur: 61655
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24779997866
server_dur: 21840
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10962,11 +11544,13 @@ android_binder {
client_ts: 24805151631
client_dur: 65179
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24805176625
server_dur: 24502
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -10999,11 +11583,13 @@ android_binder {
client_ts: 24830317956
client_dur: 66289
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24830344368
server_dur: 21990
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11036,11 +11622,13 @@ android_binder {
client_ts: 24855481377
client_dur: 65228
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24855502595
server_dur: 27360
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11073,11 +11661,13 @@ android_binder {
client_ts: 24880648226
client_dur: 55511
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24880667129
server_dur: 21590
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11110,11 +11700,13 @@ android_binder {
client_ts: 24909335836
client_dur: 55761
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24909354477
server_dur: 24104
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11147,11 +11739,13 @@ android_binder {
client_ts: 24934490094
client_dur: 58244
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24934509872
server_dur: 22084
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11184,11 +11778,13 @@ android_binder {
client_ts: 24959652634
client_dur: 81523
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24959684793
server_dur: 28526
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11221,11 +11817,13 @@ android_binder {
client_ts: 24984851591
client_dur: 68470
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24984877747
server_dur: 26966
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11258,11 +11856,13 @@ android_binder {
client_ts: 25010040890
client_dur: 90947
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25010071568
server_dur: 37280
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11295,11 +11895,13 @@ android_binder {
client_ts: 25035275877
client_dur: 59761
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25035296221
server_dur: 25210
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11332,11 +11934,13 @@ android_binder {
client_ts: 25060426543
client_dur: 81204
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25060443769
server_dur: 22941
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11369,11 +11973,13 @@ android_binder {
client_ts: 25085672790
client_dur: 95011
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25085716849
server_dur: 37413
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11406,11 +12012,13 @@ android_binder {
client_ts: 25110861456
client_dur: 53363
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25110879022
server_dur: 22707
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11443,11 +12051,13 @@ android_binder {
client_ts: 25136012642
client_dur: 51978
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25136030960
server_dur: 22166
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11480,11 +12090,13 @@ android_binder {
client_ts: 25161156360
client_dur: 68046
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25161174689
server_dur: 37221
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11517,11 +12129,13 @@ android_binder {
client_ts: 25186325904
client_dur: 37128
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25186338341
server_dur: 14526
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11554,11 +12168,13 @@ android_binder {
client_ts: 25211748648
client_dur: 44699
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25211763861
server_dur: 18676
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11591,11 +12207,13 @@ android_binder {
client_ts: 25236887649
client_dur: 51265
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25236905107
server_dur: 21519
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11628,11 +12246,13 @@ android_binder {
client_ts: 25262053873
client_dur: 82396
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25262085792
server_dur: 26917
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11665,11 +12285,13 @@ android_binder {
client_ts: 25287387704
client_dur: 103899
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25287423221
server_dur: 43908
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11702,11 +12324,13 @@ android_binder {
client_ts: 25312712971
client_dur: 248879
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25312865501
server_dur: 53943
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11739,11 +12363,13 @@ android_binder {
client_ts: 25338145653
client_dur: 118734
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25338183347
server_dur: 50843
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11776,11 +12402,13 @@ android_binder {
client_ts: 25363427959
client_dur: 127185
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25363473345
server_dur: 52393
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11813,11 +12441,13 @@ android_binder {
client_ts: 25388666272
client_dur: 311561
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25388926887
server_dur: 27556
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -11850,11 +12480,13 @@ android_binder {
client_ts: 25389019468
client_dur: 2257654
client_tid: 537
+ client_pid: 537
server_process: "system_server"
server_thread: "binder:641_2"
server_ts: 25389272037
server_dur: 1993270
server_tid: 656
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -11912,11 +12544,13 @@ android_binder {
client_ts: 25391362853
client_dur: 2138663
client_tid: 537
+ client_pid: 537
server_process: "system_server"
server_thread: "binder:641_1"
server_ts: 25391432268
server_dur: 2057673
server_tid: 655
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -11973,11 +12607,13 @@ android_binder {
client_ts: 25393529331
client_dur: 72907
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25393544112
server_dur: 48279
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12010,11 +12646,13 @@ android_binder {
client_ts: 25418715954
client_dur: 46115
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25418731360
server_dur: 20385
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12047,11 +12685,13 @@ android_binder {
client_ts: 25443850387
client_dur: 44974
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25443866014
server_dur: 19042
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12084,11 +12724,13 @@ android_binder {
client_ts: 25469057379
client_dur: 66877
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25469081511
server_dur: 26836
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12121,11 +12763,13 @@ android_binder {
client_ts: 25494306485
client_dur: 127198
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25494352512
server_dur: 49015
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12158,11 +12802,13 @@ android_binder {
client_ts: 25519756306
client_dur: 101379
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25519800487
server_dur: 31778
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12196,11 +12842,13 @@ android_binder {
client_ts: 25519893501
client_dur: 154940
client_tid: 537
+ client_pid: 537
server_process: "system_server"
server_thread: "binder:641_4"
server_ts: 25519915012
server_dur: 115492
server_tid: 1596
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12234,11 +12882,13 @@ android_binder {
client_ts: 25520078379
client_dur: 176159
client_tid: 537
+ client_pid: 537
server_process: "system_server"
server_thread: "binder:641_1"
server_ts: 25520102430
server_dur: 134309
server_tid: 655
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12272,11 +12922,13 @@ android_binder {
client_ts: 25520281012
client_dur: 123400
client_tid: 537
+ client_pid: 537
server_process: "system_server"
server_thread: "binder:641_2"
server_ts: 25520299524
server_dur: 88243
server_tid: 656
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12309,11 +12961,13 @@ android_binder {
client_ts: 25520423828
client_dur: 343243
client_tid: 537
+ client_pid: 537
server_process: "system_server"
server_thread: "binder:641_3"
server_ts: 25520612948
server_dur: 123445
server_tid: 1595
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12346,11 +13000,13 @@ android_binder {
client_ts: 25520890215
client_dur: 293220
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25521075472
server_dur: 82900
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12384,11 +13040,13 @@ android_binder {
client_ts: 25521216286
client_dur: 489554
client_tid: 537
+ client_pid: 537
server_process: "system_server"
server_thread: "binder:641_3"
server_ts: 25521243526
server_dur: 435659
server_tid: 1595
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -12427,11 +13085,13 @@ android_binder {
client_ts: 25523480228
client_dur: 2277042
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/hwservicemanager"
server_thread: "hwservicemanage"
server_ts: 25523653053
server_dur: 2085804
server_tid: 247
+ server_pid: 247
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -12476,11 +13136,13 @@ android_binder {
client_ts: 25525828575
client_dur: 674113
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/hwservicemanager"
server_thread: "hwservicemanage"
server_ts: 25526007038
server_dur: 466892
server_tid: 247
+ server_pid: 247
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -12525,11 +13187,13 @@ android_binder {
client_ts: 25529470300
client_dur: 103937
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25529493228
server_dur: 62956
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12562,11 +13226,13 @@ android_binder {
client_ts: 25529642910
client_dur: 106592
client_tid: 537
+ client_pid: 537
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25529669348
server_dur: 64544
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12599,11 +13265,13 @@ android_binder {
client_ts: 21610888219
client_dur: 1404460
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21610912981
server_dur: 24345
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12636,11 +13304,13 @@ android_binder {
client_ts: 21713165109
client_dur: 1236372
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21713185409
server_dur: 12103
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12673,11 +13343,13 @@ android_binder {
client_ts: 21817588572
client_dur: 329198
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21817646283
server_dur: 29874
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12710,11 +13382,13 @@ android_binder {
client_ts: 21918044833
client_dur: 54295
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 21918066018
server_dur: 22515
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12747,11 +13421,13 @@ android_binder {
client_ts: 22018230040
client_dur: 4199277
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22018253018
server_dur: 20817
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12784,11 +13460,13 @@ android_binder {
client_ts: 22128615818
client_dur: 66352
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22128641106
server_dur: 21332
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12821,11 +13499,13 @@ android_binder {
client_ts: 22231107021
client_dur: 6202865
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22231126269
server_dur: 21216
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12858,11 +13538,13 @@ android_binder {
client_ts: 22338230784
client_dur: 5927748
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22338257085
server_dur: 22271
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12895,11 +13577,13 @@ android_binder {
client_ts: 22444315008
client_dur: 360477
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22444338001
server_dur: 22884
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12932,11 +13616,13 @@ android_binder {
client_ts: 22545342573
client_dur: 1367091
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22545364958
server_dur: 22936
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -12969,11 +13655,13 @@ android_binder {
client_ts: 22646870376
client_dur: 61414
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22646893001
server_dur: 24570
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13006,11 +13694,13 @@ android_binder {
client_ts: 22747766863
client_dur: 1605566
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22749199929
server_dur: 25123
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13043,11 +13733,13 @@ android_binder {
client_ts: 22849527732
client_dur: 3775048
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22849787260
server_dur: 22559
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13080,11 +13772,13 @@ android_binder {
client_ts: 22955387074
client_dur: 5918097
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 22955504595
server_dur: 12187
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13117,11 +13811,13 @@ android_binder {
client_ts: 23063243768
client_dur: 1153069
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23063268117
server_dur: 21864
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13154,11 +13850,13 @@ android_binder {
client_ts: 23171834613
client_dur: 468230
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23171888187
server_dur: 23659
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13191,11 +13889,13 @@ android_binder {
client_ts: 23274482309
client_dur: 56450
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23274502428
server_dur: 22204
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13228,11 +13928,13 @@ android_binder {
client_ts: 23375517889
client_dur: 2282317
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23377319838
server_dur: 23748
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13265,11 +13967,13 @@ android_binder {
client_ts: 23479410599
client_dur: 60331
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23479434099
server_dur: 24056
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13302,11 +14006,13 @@ android_binder {
client_ts: 23581096165
client_dur: 380036
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23581329034
server_dur: 23039
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13339,11 +14045,13 @@ android_binder {
client_ts: 23683521915
client_dur: 66608
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23683548740
server_dur: 23628
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13376,11 +14084,13 @@ android_binder {
client_ts: 23788017588
client_dur: 110886
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23788091294
server_dur: 22793
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13413,11 +14123,13 @@ android_binder {
client_ts: 23892497829
client_dur: 5298146
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23892520529
server_dur: 12354
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13450,11 +14162,13 @@ android_binder {
client_ts: 23997916363
client_dur: 128256
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 23997934258
server_dur: 22034
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13487,11 +14201,13 @@ android_binder {
client_ts: 24100588444
client_dur: 79761
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24100613596
server_dur: 21941
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13524,11 +14240,13 @@ android_binder {
client_ts: 24203608109
client_dur: 1476962
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24203662175
server_dur: 25824
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13561,11 +14279,13 @@ android_binder {
client_ts: 24305487641
client_dur: 69000
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24305515718
server_dur: 25348
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13598,11 +14318,13 @@ android_binder {
client_ts: 24405940362
client_dur: 114844
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24405962114
server_dur: 22212
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13635,11 +14357,13 @@ android_binder {
client_ts: 24506183075
client_dur: 76130
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24506212466
server_dur: 21817
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13672,11 +14396,13 @@ android_binder {
client_ts: 24606672569
client_dur: 71411
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24606692709
server_dur: 37402
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13709,11 +14435,13 @@ android_binder {
client_ts: 24706847915
client_dur: 77826
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24706871511
server_dur: 21505
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13746,11 +14474,13 @@ android_binder {
client_ts: 24807614065
client_dur: 142762
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24807635682
server_dur: 20956
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13783,11 +14513,13 @@ android_binder {
client_ts: 24909374599
client_dur: 3171973
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24909393940
server_dur: 10997
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13820,11 +14552,13 @@ android_binder {
client_ts: 25012679868
client_dur: 112287
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25012708944
server_dur: 35550
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13857,11 +14591,13 @@ android_binder {
client_ts: 25112924292
client_dur: 43230
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25112938063
server_dur: 18263
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13894,11 +14630,13 @@ android_binder {
client_ts: 25213072326
client_dur: 33395
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25213083753
server_dur: 13289
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13931,11 +14669,13 @@ android_binder {
client_ts: 25313259127
client_dur: 150680
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25313317394
server_dur: 52236
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -13968,11 +14708,13 @@ android_binder {
client_ts: 25415404685
client_dur: 1470768
client_tid: 1225
+ client_pid: 555
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25416823355
server_dur: 22986
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14005,11 +14747,13 @@ android_binder {
client_ts: 25417416478
client_dur: 321332
client_tid: 1225
+ client_pid: 555
server_process: "system_server"
server_thread: "binder:641_4"
server_ts: 25417428728
server_dur: 140719
server_tid: 1596
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14042,11 +14786,13 @@ android_binder {
client_ts: 25867907972
client_dur: 68305
client_tid: 522
+ client_pid: 496
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25867933710
server_dur: 25394
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14079,11 +14825,13 @@ android_binder {
client_ts: 21648847518
client_dur: 138863
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21648864955
server_dur: 110424
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14116,11 +14864,13 @@ android_binder {
client_ts: 21649020222
client_dur: 1298536
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21649025816
server_dur: 1271373
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14153,11 +14903,13 @@ android_binder {
client_ts: 21650405554
client_dur: 21176
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21650412827
server_dur: 7662
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14190,11 +14942,13 @@ android_binder {
client_ts: 21732179696
client_dur: 66330
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21732194327
server_dur: 42279
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14227,11 +14981,13 @@ android_binder {
client_ts: 21732276479
client_dur: 998493
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21732281653
server_dur: 980816
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14264,11 +15020,13 @@ android_binder {
client_ts: 21747805001
client_dur: 32253
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21747815991
server_dur: 13234
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14301,11 +15059,13 @@ android_binder {
client_ts: 21815501160
client_dur: 67864
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21815515197
server_dur: 44624
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14338,11 +15098,13 @@ android_binder {
client_ts: 21815599518
client_dur: 1843570
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21815604505
server_dur: 1825932
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14375,11 +15137,13 @@ android_binder {
client_ts: 21817527536
client_dur: 20911
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21817534229
server_dur: 6822
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14412,11 +15176,13 @@ android_binder {
client_ts: 21898832978
client_dur: 61578
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21898846685
server_dur: 38670
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14449,11 +15215,13 @@ android_binder {
client_ts: 21898923783
client_dur: 1096630
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21898928634
server_dur: 1080195
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14486,11 +15254,13 @@ android_binder {
client_ts: 21914447745
client_dur: 30172
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21914458873
server_dur: 11417
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14523,11 +15293,13 @@ android_binder {
client_ts: 21982278493
client_dur: 137675
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21982310594
server_dur: 80114
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14560,11 +15332,13 @@ android_binder {
client_ts: 21982477699
client_dur: 1235182
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21982492293
server_dur: 1187140
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14597,11 +15371,13 @@ android_binder {
client_ts: 21983894427
client_dur: 56732
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 21983913100
server_dur: 18080
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14634,11 +15410,13 @@ android_binder {
client_ts: 22065483496
client_dur: 63685
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22065497670
server_dur: 40803
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14671,11 +15449,13 @@ android_binder {
client_ts: 22065575735
client_dur: 1062604
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22065580382
server_dur: 1045862
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14708,11 +15488,13 @@ android_binder {
client_ts: 22081125903
client_dur: 31676
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22081137566
server_dur: 12008
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14745,11 +15527,13 @@ android_binder {
client_ts: 22148826292
client_dur: 66432
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22148840763
server_dur: 42889
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14782,11 +15566,13 @@ android_binder {
client_ts: 22148922210
client_dur: 1055199
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22148927117
server_dur: 1037009
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14819,11 +15605,13 @@ android_binder {
client_ts: 22150072810
client_dur: 21373
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22150080025
server_dur: 7715
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14856,11 +15644,13 @@ android_binder {
client_ts: 22232166904
client_dur: 64562
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22232181958
server_dur: 40112
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14893,11 +15683,13 @@ android_binder {
client_ts: 22232260319
client_dur: 1084947
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22232265525
server_dur: 1065811
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14930,11 +15722,13 @@ android_binder {
client_ts: 22247787616
client_dur: 29515
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22247797746
server_dur: 12125
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -14967,11 +15761,13 @@ android_binder {
client_ts: 22315503408
client_dur: 75460
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22315519682
server_dur: 49022
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15004,11 +15800,13 @@ android_binder {
client_ts: 22315610938
client_dur: 1046448
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22315616049
server_dur: 1029776
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15041,11 +15839,13 @@ android_binder {
client_ts: 22316735903
client_dur: 21152
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22316742808
server_dur: 7783
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15078,11 +15878,13 @@ android_binder {
client_ts: 22398839076
client_dur: 65963
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22398854027
server_dur: 42248
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15115,11 +15917,13 @@ android_binder {
client_ts: 22398960806
client_dur: 1018998
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22398966568
server_dur: 1000410
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15152,11 +15956,13 @@ android_binder {
client_ts: 22414462930
client_dur: 32955
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22414474372
server_dur: 13302
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15189,11 +15995,13 @@ android_binder {
client_ts: 22482179365
client_dur: 71661
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22482194253
server_dur: 47932
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15226,11 +16034,13 @@ android_binder {
client_ts: 22482282793
client_dur: 955159
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22482287911
server_dur: 938324
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15263,11 +16073,13 @@ android_binder {
client_ts: 22497465809
client_dur: 39624
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22497477915
server_dur: 17691
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15300,11 +16112,13 @@ android_binder {
client_ts: 22565521231
client_dur: 66993
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22565536155
server_dur: 42982
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15337,11 +16151,13 @@ android_binder {
client_ts: 22565618391
client_dur: 1026658
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22565623264
server_dur: 1009748
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15374,11 +16190,13 @@ android_binder {
client_ts: 22581241130
client_dur: 37185
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22581254325
server_dur: 15879
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15411,11 +16229,13 @@ android_binder {
client_ts: 22648855410
client_dur: 78080
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22648872617
server_dur: 51463
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15448,11 +16268,13 @@ android_binder {
client_ts: 22648965876
client_dur: 1080456
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22648971095
server_dur: 1061465
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15485,11 +16307,13 @@ android_binder {
client_ts: 22650134321
client_dur: 21145
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22650140974
server_dur: 7869
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15522,11 +16346,13 @@ android_binder {
client_ts: 22732183976
client_dur: 84922
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22732199541
server_dur: 59268
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15559,11 +16385,13 @@ android_binder {
client_ts: 22732300442
client_dur: 1084256
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22732305487
server_dur: 1066498
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15596,11 +16424,13 @@ android_binder {
client_ts: 22749316211
client_dur: 37389
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22749329367
server_dur: 15449
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15633,11 +16463,13 @@ android_binder {
client_ts: 22815554390
client_dur: 80259
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22815571850
server_dur: 52908
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15670,11 +16502,13 @@ android_binder {
client_ts: 22815665677
client_dur: 1846724
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22815670690
server_dur: 1827939
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15707,11 +16541,13 @@ android_binder {
client_ts: 22817599826
client_dur: 21169
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22817606552
server_dur: 8080
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15744,11 +16580,13 @@ android_binder {
client_ts: 22898837991
client_dur: 66016
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22898853740
server_dur: 41111
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15781,11 +16619,13 @@ android_binder {
client_ts: 22898932620
client_dur: 1881472
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22898937509
server_dur: 1862476
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15818,11 +16658,13 @@ android_binder {
client_ts: 22914460532
client_dur: 34598
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22914472324
server_dur: 14518
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15855,11 +16697,13 @@ android_binder {
client_ts: 22982182870
client_dur: 80394
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22982200371
server_dur: 52999
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15892,11 +16736,13 @@ android_binder {
client_ts: 22982296391
client_dur: 1052212
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22982301600
server_dur: 1033314
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15929,11 +16775,13 @@ android_binder {
client_ts: 22983445756
client_dur: 23169
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 22983452175
server_dur: 10357
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -15966,11 +16814,13 @@ android_binder {
client_ts: 23065513683
client_dur: 74423
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23065529019
server_dur: 49067
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16003,11 +16853,13 @@ android_binder {
client_ts: 23065619219
client_dur: 1146958
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23065624303
server_dur: 1129990
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16040,11 +16892,13 @@ android_binder {
client_ts: 23081285291
client_dur: 45213
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23081307603
server_dur: 14325
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16077,11 +16931,13 @@ android_binder {
client_ts: 23148835709
client_dur: 76791
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23148852272
server_dur: 50863
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16114,11 +16970,13 @@ android_binder {
client_ts: 23148944247
client_dur: 1986947
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23148949481
server_dur: 1965225
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16151,11 +17009,13 @@ android_binder {
client_ts: 23151027818
client_dur: 25087
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23151036483
server_dur: 9385
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16188,11 +17048,13 @@ android_binder {
client_ts: 23232183799
client_dur: 75511
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23232201226
server_dur: 48102
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16225,11 +17087,13 @@ android_binder {
client_ts: 23232290686
client_dur: 1140969
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23232295646
server_dur: 1123404
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16262,11 +17126,13 @@ android_binder {
client_ts: 23249891699
client_dur: 37797
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23249904526
server_dur: 16397
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16299,11 +17165,13 @@ android_binder {
client_ts: 23315566931
client_dur: 110557
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23315592450
server_dur: 69421
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16336,11 +17204,13 @@ android_binder {
client_ts: 23315722066
client_dur: 2606042
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23315729839
server_dur: 2583671
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16373,11 +17243,13 @@ android_binder {
client_ts: 23318420005
client_dur: 21345
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23318427118
server_dur: 7958
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16410,11 +17282,13 @@ android_binder {
client_ts: 23398873863
client_dur: 68770
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23398889934
server_dur: 41798
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16447,11 +17321,13 @@ android_binder {
client_ts: 23398973230
client_dur: 1176570
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23398978271
server_dur: 1158688
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16484,11 +17360,13 @@ android_binder {
client_ts: 23416727246
client_dur: 33867
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23416739503
server_dur: 14319
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16521,11 +17399,13 @@ android_binder {
client_ts: 23482185608
client_dur: 80279
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23482202317
server_dur: 53655
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16558,11 +17438,13 @@ android_binder {
client_ts: 23482297909
client_dur: 1040841
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23482303086
server_dur: 1022859
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16595,11 +17477,13 @@ android_binder {
client_ts: 23483420403
client_dur: 20295
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23483427104
server_dur: 6793
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16632,11 +17516,13 @@ android_binder {
client_ts: 23566095373
client_dur: 80168
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23566112317
server_dur: 53405
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16669,11 +17555,13 @@ android_binder {
client_ts: 23566207004
client_dur: 1080032
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23566212869
server_dur: 1062341
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16706,11 +17594,13 @@ android_binder {
client_ts: 23581426699
client_dur: 33178
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23581438242
server_dur: 13572
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16743,11 +17633,13 @@ android_binder {
client_ts: 23648877211
client_dur: 74827
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23648892093
server_dur: 50840
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16780,11 +17672,13 @@ android_binder {
client_ts: 23648984124
client_dur: 1869563
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23648989106
server_dur: 1850394
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16817,11 +17711,13 @@ android_binder {
client_ts: 23650943350
client_dur: 22389
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23650950419
server_dur: 8699
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16854,11 +17750,13 @@ android_binder {
client_ts: 23732162997
client_dur: 66948
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23732178223
server_dur: 42065
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16891,11 +17789,13 @@ android_binder {
client_ts: 23732260275
client_dur: 1099825
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23732265173
server_dur: 1083011
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16928,11 +17828,13 @@ android_binder {
client_ts: 23747796852
client_dur: 29683
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23747806637
server_dur: 12580
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -16965,11 +17867,13 @@ android_binder {
client_ts: 23815516337
client_dur: 68846
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23815530730
server_dur: 44894
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17002,11 +17906,13 @@ android_binder {
client_ts: 23815619259
client_dur: 986718
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23815623956
server_dur: 969888
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17039,11 +17945,13 @@ android_binder {
client_ts: 23816691292
client_dur: 20206
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23816697719
server_dur: 7427
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17076,11 +17984,13 @@ android_binder {
client_ts: 23898849538
client_dur: 73093
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23898865505
server_dur: 44882
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17113,11 +18023,13 @@ android_binder {
client_ts: 23898957000
client_dur: 1065096
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23898962241
server_dur: 1045751
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17150,11 +18062,13 @@ android_binder {
client_ts: 23914455173
client_dur: 29880
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23914466130
server_dur: 11108
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17187,11 +18101,13 @@ android_binder {
client_ts: 23982180549
client_dur: 85583
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23982199040
server_dur: 52914
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17224,11 +18140,13 @@ android_binder {
client_ts: 23982305851
client_dur: 1744711
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23982314504
server_dur: 1722762
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17261,11 +18179,13 @@ android_binder {
client_ts: 23984133705
client_dur: 20045
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 23984139858
server_dur: 7402
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17298,11 +18218,13 @@ android_binder {
client_ts: 24065542758
client_dur: 68668
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24065557894
server_dur: 43859
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17335,11 +18257,13 @@ android_binder {
client_ts: 24065652205
client_dur: 1049759
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24065657696
server_dur: 1032583
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17372,11 +18296,13 @@ android_binder {
client_ts: 24081125997
client_dur: 31826
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24081137112
server_dur: 13041
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17409,11 +18335,13 @@ android_binder {
client_ts: 24148820113
client_dur: 68214
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24148833979
server_dur: 44630
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17446,11 +18374,13 @@ android_binder {
client_ts: 24148918715
client_dur: 1009266
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24148923375
server_dur: 991906
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17483,11 +18413,13 @@ android_binder {
client_ts: 24150011467
client_dur: 21064
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24150018449
server_dur: 7359
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17520,11 +18452,13 @@ android_binder {
client_ts: 24247778973
client_dur: 34911
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24247791507
server_dur: 14684
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17557,11 +18491,13 @@ android_binder {
client_ts: 24248842389
client_dur: 66174
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24248855559
server_dur: 43223
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17594,11 +18530,13 @@ android_binder {
client_ts: 24248937934
client_dur: 1130965
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24248943066
server_dur: 1111247
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17631,11 +18569,13 @@ android_binder {
client_ts: 24250153754
client_dur: 21489
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24250161172
server_dur: 7362
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17668,11 +18608,13 @@ android_binder {
client_ts: 24332164030
client_dur: 78622
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24332193334
server_dur: 39186
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17705,11 +18647,13 @@ android_binder {
client_ts: 24332271286
client_dur: 1233475
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24332276288
server_dur: 1215090
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17742,11 +18686,13 @@ android_binder {
client_ts: 24350341616
client_dur: 97785
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24350364644
server_dur: 50768
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17779,11 +18725,13 @@ android_binder {
client_ts: 24415506341
client_dur: 73094
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24415521413
server_dur: 48860
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17816,11 +18764,13 @@ android_binder {
client_ts: 24415610395
client_dur: 1963175
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24415614985
server_dur: 1944970
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17853,11 +18803,13 @@ android_binder {
client_ts: 24417688619
client_dur: 22666
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24417696179
server_dur: 8868
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17890,11 +18842,13 @@ android_binder {
client_ts: 24498858408
client_dur: 72316
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24498874905
server_dur: 44364
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17927,11 +18881,13 @@ android_binder {
client_ts: 24498965251
client_dur: 2212172
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24498971364
server_dur: 2189623
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -17964,11 +18920,13 @@ android_binder {
client_ts: 24514530326
client_dur: 46445
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24514545922
server_dur: 16967
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18001,11 +18959,13 @@ android_binder {
client_ts: 24582239101
client_dur: 102168
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24582262241
server_dur: 62646
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18038,11 +18998,13 @@ android_binder {
client_ts: 24582383933
client_dur: 1125278
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24582393122
server_dur: 1094530
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18075,11 +19037,13 @@ android_binder {
client_ts: 24583627699
client_dur: 36229
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24583638897
server_dur: 12637
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18112,11 +19076,13 @@ android_binder {
client_ts: 24665516749
client_dur: 77492
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24665535013
server_dur: 46956
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18149,11 +19115,13 @@ android_binder {
client_ts: 24665629297
client_dur: 1056190
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24665650779
server_dur: 1018462
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18186,11 +19154,13 @@ android_binder {
client_ts: 24681436859
client_dur: 36053
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24681447493
server_dur: 17169
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18223,11 +19193,13 @@ android_binder {
client_ts: 24748868138
client_dur: 84885
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24748886644
server_dur: 54090
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18260,11 +19232,13 @@ android_binder {
client_ts: 24748988510
client_dur: 1030023
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24748994792
server_dur: 1007690
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18297,11 +19271,13 @@ android_binder {
client_ts: 24750114696
client_dur: 25844
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24750122620
server_dur: 9559
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18334,11 +19310,13 @@ android_binder {
client_ts: 24832172264
client_dur: 71964
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24832186234
server_dur: 48177
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18371,11 +19349,13 @@ android_binder {
client_ts: 24832278767
client_dur: 2319199
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24832284387
server_dur: 2299722
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18408,11 +19388,13 @@ android_binder {
client_ts: 24848194066
client_dur: 38990
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24848207084
server_dur: 16882
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18445,11 +19427,13 @@ android_binder {
client_ts: 24915569035
client_dur: 92319
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24915587307
server_dur: 61522
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18482,11 +19466,13 @@ android_binder {
client_ts: 24915703770
client_dur: 1154960
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24915710935
server_dur: 1133005
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18519,11 +19505,13 @@ android_binder {
client_ts: 24916964211
client_dur: 24607
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24916971111
server_dur: 10684
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18556,11 +19544,13 @@ android_binder {
client_ts: 24998945706
client_dur: 111229
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24998970836
server_dur: 66036
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18593,11 +19583,13 @@ android_binder {
client_ts: 24999109626
client_dur: 1079778
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 24999121401
server_dur: 1042002
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18630,11 +19622,13 @@ android_binder {
client_ts: 25014488039
client_dur: 70943
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25014504840
server_dur: 24296
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18667,11 +19661,13 @@ android_binder {
client_ts: 25082202078
client_dur: 73854
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25082217860
server_dur: 47920
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18704,11 +19700,13 @@ android_binder {
client_ts: 25082306875
client_dur: 1782258
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25082312116
server_dur: 1764384
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18741,11 +19739,13 @@ android_binder {
client_ts: 25084166020
client_dur: 20222
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25084172595
server_dur: 7394
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18778,11 +19778,13 @@ android_binder {
client_ts: 25165504670
client_dur: 81307
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25165518960
server_dur: 55941
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18815,11 +19817,13 @@ android_binder {
client_ts: 25165619958
client_dur: 997114
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25165625294
server_dur: 978831
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18852,11 +19856,13 @@ android_binder {
client_ts: 25181108704
client_dur: 38312
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25181120018
server_dur: 17603
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18889,11 +19895,13 @@ android_binder {
client_ts: 25248839993
client_dur: 71834
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25248855062
server_dur: 47208
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18926,11 +19934,13 @@ android_binder {
client_ts: 25248942032
client_dur: 1065822
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25248946700
server_dur: 1047977
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -18963,11 +19973,13 @@ android_binder {
client_ts: 25250092465
client_dur: 21121
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25250099244
server_dur: 7872
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19000,11 +20012,13 @@ android_binder {
client_ts: 25332433123
client_dur: 129185
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25332463293
server_dur: 75363
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19037,11 +20051,13 @@ android_binder {
client_ts: 25332622145
client_dur: 3970213
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25332636462
server_dur: 3919134
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19074,11 +20090,13 @@ android_binder {
client_ts: 25347937130
client_dur: 63143
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25347956107
server_dur: 23630
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19111,11 +20129,13 @@ android_binder {
client_ts: 25415532955
client_dur: 74958
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25415548486
server_dur: 48910
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19148,11 +20168,13 @@ android_binder {
client_ts: 25415639063
client_dur: 1045725
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25415643854
server_dur: 1028657
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19185,11 +20207,13 @@ android_binder {
client_ts: 25416779828
client_dur: 22459
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25416786530
server_dur: 8393
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19222,11 +20246,13 @@ android_binder {
client_ts: 25499090883
client_dur: 135524
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25499122517
server_dur: 77879
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19259,11 +20285,13 @@ android_binder {
client_ts: 25499287661
client_dur: 1179689
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25499301640
server_dur: 1130895
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19296,11 +20324,13 @@ android_binder {
client_ts: 25514592061
client_dur: 62604
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25514612449
server_dur: 22109
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19333,11 +20363,13 @@ android_binder {
client_ts: 25582338627
client_dur: 162705
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25582368275
server_dur: 92253
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19370,11 +20402,13 @@ android_binder {
client_ts: 25582559609
client_dur: 1051443
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25582572935
server_dur: 992794
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19407,11 +20441,13 @@ android_binder {
client_ts: 25583792668
client_dur: 57270
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25583811204
server_dur: 18520
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19444,11 +20480,13 @@ android_binder {
client_ts: 25665575887
client_dur: 98551
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25665594994
server_dur: 67512
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19481,11 +20519,13 @@ android_binder {
client_ts: 25665714191
client_dur: 2056246
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25665719790
server_dur: 2036405
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19518,11 +20558,13 @@ android_binder {
client_ts: 25681400816
client_dur: 89610
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25681427461
server_dur: 37612
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19555,11 +20597,13 @@ android_binder {
client_ts: 25748935127
client_dur: 126067
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25748964935
server_dur: 75428
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19592,11 +20636,13 @@ android_binder {
client_ts: 25749129537
client_dur: 1130001
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25749140148
server_dur: 1092654
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19629,11 +20675,13 @@ android_binder {
client_ts: 25750403211
client_dur: 43991
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25750417428
server_dur: 15659
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19666,11 +20714,13 @@ android_binder {
client_ts: 25832201262
client_dur: 76032
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25832217990
server_dur: 49551
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19703,11 +20753,13 @@ android_binder {
client_ts: 25832312368
client_dur: 1052337
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25832317105
server_dur: 1035144
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19740,11 +20792,13 @@ android_binder {
client_ts: 25847799175
client_dur: 40678
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25847812958
server_dur: 17906
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19777,11 +20831,13 @@ android_binder {
client_ts: 25855749248
client_dur: 31727
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25855758456
server_dur: 14151
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19814,11 +20870,13 @@ android_binder {
client_ts: 25865415841
client_dur: 46578
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25865424168
server_dur: 29991
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19851,11 +20909,13 @@ android_binder {
client_ts: 25865488539
client_dur: 1091161
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25865493112
server_dur: 1074785
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19888,11 +20948,13 @@ android_binder {
client_ts: 25882229417
client_dur: 49798
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25882240791
server_dur: 29545
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19925,11 +20987,13 @@ android_binder {
client_ts: 25882302427
client_dur: 976002
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25882306957
server_dur: 960192
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19962,11 +21026,13 @@ android_binder {
client_ts: 25915516257
client_dur: 67861
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25915531128
server_dur: 43477
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -19999,11 +21065,13 @@ android_binder {
client_ts: 25915614740
client_dur: 879798
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25915619820
server_dur: 861862
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20036,11 +21104,13 @@ android_binder {
client_ts: 25947791827
client_dur: 36462
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25947803365
server_dur: 16366
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20073,11 +21143,13 @@ android_binder {
client_ts: 25965634137
client_dur: 62809
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25965647687
server_dur: 39248
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20110,11 +21182,13 @@ android_binder {
client_ts: 25965727363
client_dur: 1082911
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25965732380
server_dur: 1065715
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20147,11 +21221,13 @@ android_binder {
client_ts: 25966880090
client_dur: 18647
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25966885882
server_dur: 6742
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20184,11 +21260,13 @@ android_binder {
client_ts: 25998857609
client_dur: 68802
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25998873383
server_dur: 43179
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20221,11 +21299,13 @@ android_binder {
client_ts: 25998956453
client_dur: 896029
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 25998961673
server_dur: 878692
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20258,11 +21338,13 @@ android_binder {
client_ts: 26064480113
client_dur: 41059
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26064494262
server_dur: 17230
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20295,11 +21377,13 @@ android_binder {
client_ts: 26082167007
client_dur: 68814
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26082181896
server_dur: 44307
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20332,11 +21416,13 @@ android_binder {
client_ts: 26082265345
client_dur: 984160
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26082270124
server_dur: 967726
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20369,11 +21455,13 @@ android_binder {
client_ts: 26083328041
client_dur: 20356
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26083334137
server_dur: 7873
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20406,11 +21494,13 @@ android_binder {
client_ts: 26165543672
client_dur: 76748
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26165564279
server_dur: 46139
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20443,11 +21533,13 @@ android_binder {
client_ts: 26165664730
client_dur: 952016
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26165670566
server_dur: 934833
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20480,11 +21572,13 @@ android_binder {
client_ts: 26181134030
client_dur: 39663
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26181147708
server_dur: 17312
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20517,11 +21611,13 @@ android_binder {
client_ts: 26265553005
client_dur: 106037
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26265570929
server_dur: 76133
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20554,11 +21650,13 @@ android_binder {
client_ts: 26265695797
client_dur: 1070288
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26265701257
server_dur: 1051768
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20591,11 +21689,13 @@ android_binder {
client_ts: 26266851930
client_dur: 21080
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26266858935
server_dur: 7493
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20628,11 +21728,13 @@ android_binder {
client_ts: 26348993760
client_dur: 74635
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26349012914
server_dur: 45210
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20665,11 +21767,13 @@ android_binder {
client_ts: 26349100408
client_dur: 985507
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26349105368
server_dur: 967525
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20702,11 +21806,13 @@ android_binder {
client_ts: 26364884926
client_dur: 48465
client_tid: 496
+ client_pid: 496
server_process: "/vendor/bin/hw/android.hardware.graphics.composer3-service.ranchu"
server_thread: "binder:446_1"
server_ts: 26364907480
server_dur: 16844
server_tid: 507
+ server_pid: 446
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20739,11 +21845,13 @@ android_binder {
client_ts: 25527594973
client_dur: 961513
client_tid: 431
+ client_pid: 431
server_process: "system_server"
server_thread: "system_server"
server_ts: 25528486848
server_dur: 41164
server_tid: 641
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20776,11 +21884,13 @@ android_binder {
client_ts: 25519230900
client_dur: 67687
client_tid: 458
+ client_pid: 458
server_process: "system_server"
server_thread: "system-server-i"
server_ts: 25519257217
server_dur: 19303
server_tid: 665
+ server_pid: 641
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20813,11 +21923,13 @@ android_binder {
client_ts: 25887934200
client_dur: 73511
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25887963950
server_dur: 31341
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20850,11 +21962,13 @@ android_binder {
client_ts: 25924014206
client_dur: 48397
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25924032607
server_dur: 19471
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20887,11 +22001,13 @@ android_binder {
client_ts: 25924552433
client_dur: 51388
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25924572649
server_dur: 16951
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20924,11 +22040,13 @@ android_binder {
client_ts: 25925236390
client_dur: 40800
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25925252802
server_dur: 11692
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20961,11 +22079,13 @@ android_binder {
client_ts: 25925312006
client_dur: 22098
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25925321018
server_dur: 4977
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -20998,11 +22118,13 @@ android_binder {
client_ts: 25925340685
client_dur: 18485
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25925348223
server_dur: 3660
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21035,11 +22157,13 @@ android_binder {
client_ts: 25925364763
client_dur: 18634
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25925372247
server_dur: 3490
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21072,11 +22196,13 @@ android_binder {
client_ts: 26046721012
client_dur: 137219
client_tid: 1625
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 26046826730
server_dur: 20407
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21109,11 +22235,13 @@ android_binder {
client_ts: 25848902022
client_dur: 109438
client_tid: 662
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25848918031
server_dur: 71184
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21147,11 +22275,13 @@ android_binder {
client_ts: 25849035817
client_dur: 85138
client_tid: 662
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25849046771
server_dur: 23591
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21184,11 +22314,13 @@ android_binder {
client_ts: 25965522657
client_dur: 87636
client_tid: 662
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25965536704
server_dur: 31166
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -21221,11 +22353,13 @@ android_binder {
client_ts: 26046475353
client_dur: 139999
client_tid: 662
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 26046494430
server_dur: 36023
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21252,11 +22386,13 @@ android_binder {
client_ts: 26049659202
client_dur: 66793
client_tid: 662
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 26049676304
server_dur: 21699
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21283,11 +22419,13 @@ android_binder {
client_ts: 25852597933
client_dur: 72360
client_tid: 663
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25852614647
server_dur: 40436
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21321,11 +22459,13 @@ android_binder {
client_ts: 25852691734
client_dur: 40316
client_tid: 663
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25852702316
server_dur: 18235
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21358,11 +22498,13 @@ android_binder {
client_ts: 25851140935
client_dur: 82845
client_tid: 661
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25851157134
server_dur: 45749
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21396,11 +22538,13 @@ android_binder {
client_ts: 25851245190
client_dur: 40441
client_tid: 661
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25851255329
server_dur: 18715
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21434,11 +22578,13 @@ android_binder {
client_ts: 25854136251
client_dur: 140850
client_tid: 661
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25854153001
server_dur: 42359
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21471,11 +22617,13 @@ android_binder {
client_ts: 25982476503
client_dur: 71952
client_tid: 660
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25982503060
server_dur: 29743
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21508,11 +22656,13 @@ android_binder {
client_ts: 25873131715
client_dur: 117082
client_tid: 659
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25873153628
server_dur: 22969
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21539,11 +22689,13 @@ android_binder {
client_ts: 25883734665
client_dur: 152980
client_tid: 659
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25883839992
server_dur: 25887
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21576,11 +22728,13 @@ android_binder {
client_ts: 25537922715
client_dur: 260041
client_tid: 1600
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.lights-service.example"
server_thread: "android.hardwar"
server_ts: 25537947459
server_dur: 137623
server_tid: 448
+ server_pid: 448
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21608,11 +22762,13 @@ android_binder {
client_ts: 25285800698
client_dur: 1963972
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25285972364
server_dur: 1764197
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -21670,11 +22826,13 @@ android_binder {
client_ts: 25359359930
client_dur: 58056845
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25359406757
server_dur: 57997245
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -21726,11 +22884,13 @@ android_binder {
client_ts: 25417583831
client_dur: 159127
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25417600127
server_dur: 117766
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21764,11 +22924,13 @@ android_binder {
client_ts: 25417795254
client_dur: 84143
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25417807548
server_dur: 52980
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21802,11 +22964,13 @@ android_binder {
client_ts: 25417900256
client_dur: 72685
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25417909455
server_dur: 47502
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21840,11 +23004,13 @@ android_binder {
client_ts: 25417989778
client_dur: 70644
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418000174
server_dur: 44675
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21878,11 +23044,13 @@ android_binder {
client_ts: 25418084967
client_dur: 63335
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418094122
server_dur: 43952
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21916,11 +23084,13 @@ android_binder {
client_ts: 25418162868
client_dur: 73089
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418174366
server_dur: 51193
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21954,11 +23124,13 @@ android_binder {
client_ts: 25418257945
client_dur: 71217
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418268205
server_dur: 50582
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -21992,11 +23164,13 @@ android_binder {
client_ts: 25418344237
client_dur: 68933
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418354448
server_dur: 48033
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22030,11 +23204,13 @@ android_binder {
client_ts: 25418434003
client_dur: 70051
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418444322
server_dur: 49218
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22068,11 +23244,13 @@ android_binder {
client_ts: 25418523244
client_dur: 71860
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418533528
server_dur: 51097
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22106,11 +23284,13 @@ android_binder {
client_ts: 25418613235
client_dur: 80217
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418623429
server_dur: 59922
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22144,11 +23324,13 @@ android_binder {
client_ts: 25418707467
client_dur: 100848
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25418716983
server_dur: 80176
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22182,11 +23364,13 @@ android_binder {
client_ts: 25418859801
client_dur: 96287
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25418874922
server_dur: 66129
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22220,11 +23404,13 @@ android_binder {
client_ts: 25418990456
client_dur: 73140
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419002227
server_dur: 50140
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22258,11 +23444,13 @@ android_binder {
client_ts: 25419082851
client_dur: 69691
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419093189
server_dur: 48614
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22296,11 +23484,13 @@ android_binder {
client_ts: 25419197218
client_dur: 97019
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419208385
server_dur: 75308
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22334,11 +23524,13 @@ android_binder {
client_ts: 25419309331
client_dur: 68503
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419319559
server_dur: 48070
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22372,11 +23564,13 @@ android_binder {
client_ts: 25419402979
client_dur: 68957
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419413041
server_dur: 48592
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22410,11 +23604,13 @@ android_binder {
client_ts: 25419490548
client_dur: 70455
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419500948
server_dur: 49673
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22448,11 +23644,13 @@ android_binder {
client_ts: 25419576883
client_dur: 68126
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419587154
server_dur: 47213
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22486,11 +23684,13 @@ android_binder {
client_ts: 25419662926
client_dur: 68985
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419673103
server_dur: 48313
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22524,11 +23724,13 @@ android_binder {
client_ts: 25419747914
client_dur: 70204
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419758511
server_dur: 49425
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22562,11 +23764,13 @@ android_binder {
client_ts: 25419838530
client_dur: 74294
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419851530
server_dur: 50943
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22600,11 +23804,13 @@ android_binder {
client_ts: 25419930878
client_dur: 71254
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25419941349
server_dur: 50447
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22638,11 +23844,13 @@ android_binder {
client_ts: 25420022065
client_dur: 70064
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420034446
server_dur: 47514
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22676,11 +23884,13 @@ android_binder {
client_ts: 25420107549
client_dur: 67997
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420117365
server_dur: 47959
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22714,11 +23924,13 @@ android_binder {
client_ts: 25420191395
client_dur: 67798
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420201429
server_dur: 47599
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22752,11 +23964,13 @@ android_binder {
client_ts: 25420275173
client_dur: 68378
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420285912
server_dur: 47561
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22790,11 +24004,13 @@ android_binder {
client_ts: 25420359212
client_dur: 68447
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420369692
server_dur: 47721
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22828,11 +24044,13 @@ android_binder {
client_ts: 25420458125
client_dur: 69217
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420468424
server_dur: 48683
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22866,11 +24084,13 @@ android_binder {
client_ts: 25420542827
client_dur: 68982
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420553053
server_dur: 48593
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22904,11 +24124,13 @@ android_binder {
client_ts: 25420642092
client_dur: 75336
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420652418
server_dur: 54692
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22942,11 +24164,13 @@ android_binder {
client_ts: 25420732600
client_dur: 66989
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420742486
server_dur: 46762
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -22980,11 +24204,13 @@ android_binder {
client_ts: 25420814670
client_dur: 66733
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420824622
server_dur: 46663
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23018,11 +24244,13 @@ android_binder {
client_ts: 25420898454
client_dur: 67283
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420908490
server_dur: 47258
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23056,11 +24284,13 @@ android_binder {
client_ts: 25420980515
client_dur: 68119
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25420990555
server_dur: 47881
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23094,11 +24324,13 @@ android_binder {
client_ts: 25421062960
client_dur: 67691
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25421073099
server_dur: 47279
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23132,11 +24364,13 @@ android_binder {
client_ts: 25421149398
client_dur: 67456
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25421159582
server_dur: 46812
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23170,11 +24404,13 @@ android_binder {
client_ts: 25421234249
client_dur: 102474
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25421244402
server_dur: 81689
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23208,11 +24444,13 @@ android_binder {
client_ts: 25421351001
client_dur: 68629
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25421361736
server_dur: 50268
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23246,11 +24484,13 @@ android_binder {
client_ts: 25421437438
client_dur: 78505
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25421447770
server_dur: 60705
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23284,11 +24524,13 @@ android_binder {
client_ts: 25421529017
client_dur: 90619
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25421536869
server_dur: 70139
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23322,11 +24564,13 @@ android_binder {
client_ts: 25421667924
client_dur: 93173
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25421681338
server_dur: 67854
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23360,11 +24604,13 @@ android_binder {
client_ts: 25421792054
client_dur: 79868
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25421807359
server_dur: 55975
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23398,11 +24644,13 @@ android_binder {
client_ts: 25421889199
client_dur: 85495
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25421897198
server_dur: 65834
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23436,11 +24684,13 @@ android_binder {
client_ts: 25422008441
client_dur: 90387
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25422024828
server_dur: 62034
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23474,11 +24724,13 @@ android_binder {
client_ts: 25422133767
client_dur: 75807
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25422147676
server_dur: 51244
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23512,11 +24764,13 @@ android_binder {
client_ts: 25422225432
client_dur: 98464
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25422233734
server_dur: 79168
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23550,11 +24804,13 @@ android_binder {
client_ts: 25422355100
client_dur: 93353
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25422370044
server_dur: 64908
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23588,11 +24844,13 @@ android_binder {
client_ts: 25422488580
client_dur: 81077
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25422503734
server_dur: 56902
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23626,11 +24884,13 @@ android_binder {
client_ts: 25422585669
client_dur: 81637
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25422593474
server_dur: 62945
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23664,11 +24924,13 @@ android_binder {
client_ts: 25422698364
client_dur: 307058
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25422912325
server_dur: 72852
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23702,11 +24964,13 @@ android_binder {
client_ts: 25423038416
client_dur: 85760
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25423050636
server_dur: 59617
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23740,11 +25004,13 @@ android_binder {
client_ts: 25423141970
client_dur: 65309
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25423147589
server_dur: 46373
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23778,11 +25044,13 @@ android_binder {
client_ts: 25423222741
client_dur: 83982
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25423241349
server_dur: 52179
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23816,11 +25084,13 @@ android_binder {
client_ts: 25423321767
client_dur: 84883
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25423330170
server_dur: 64541
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23854,11 +25124,13 @@ android_binder {
client_ts: 25423444205
client_dur: 97794
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25423460614
server_dur: 64145
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23892,11 +25164,13 @@ android_binder {
client_ts: 25423571069
client_dur: 79325
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25423585310
server_dur: 56042
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23930,11 +25204,13 @@ android_binder {
client_ts: 25423667089
client_dur: 80196
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25423674807
server_dur: 61267
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -23968,11 +25244,13 @@ android_binder {
client_ts: 25423778912
client_dur: 85732
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25423789294
server_dur: 63712
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24006,11 +25284,13 @@ android_binder {
client_ts: 25423899033
client_dur: 83874
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25423913207
server_dur: 61126
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24044,11 +25324,13 @@ android_binder {
client_ts: 25423999018
client_dur: 80807
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25424006723
server_dur: 62351
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24082,11 +25364,13 @@ android_binder {
client_ts: 25424119494
client_dur: 90723
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25424133267
server_dur: 65314
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24120,11 +25404,13 @@ android_binder {
client_ts: 25424244832
client_dur: 75424
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25424257485
server_dur: 54108
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24158,11 +25444,13 @@ android_binder {
client_ts: 25424340551
client_dur: 68134
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25424352371
server_dur: 47952
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24196,11 +25484,13 @@ android_binder {
client_ts: 25424423268
client_dur: 79235
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25424430889
server_dur: 60700
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24234,11 +25524,13 @@ android_binder {
client_ts: 25424532071
client_dur: 132824
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25424548055
server_dur: 63569
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24272,11 +25564,13 @@ android_binder {
client_ts: 25424695404
client_dur: 78895
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25424709439
server_dur: 55753
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24310,11 +25604,13 @@ android_binder {
client_ts: 25424790712
client_dur: 84106
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25424798759
server_dur: 65429
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24348,11 +25644,13 @@ android_binder {
client_ts: 25424904112
client_dur: 86631
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_3"
server_ts: 25424916724
server_dur: 62466
server_tid: 1590
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24386,11 +25684,13 @@ android_binder {
client_ts: 25425012627
client_dur: 82418
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25425020923
server_dur: 61511
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24424,11 +25724,13 @@ android_binder {
client_ts: 25425134890
client_dur: 80492
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25425151484
server_dur: 55304
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24462,11 +25764,13 @@ android_binder {
client_ts: 25425231522
client_dur: 103387
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25425239219
server_dur: 85661
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -24506,11 +25810,13 @@ android_binder {
client_ts: 25425372618
client_dur: 91185
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25425384448
server_dur: 68305
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24544,11 +25850,13 @@ android_binder {
client_ts: 25425498321
client_dur: 82574
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25425511999
server_dur: 60168
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24582,11 +25890,13 @@ android_binder {
client_ts: 25425597030
client_dur: 96570
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25425604832
server_dur: 77508
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24620,11 +25930,13 @@ android_binder {
client_ts: 25425734906
client_dur: 90504
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25425748243
server_dur: 65377
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24658,11 +25970,13 @@ android_binder {
client_ts: 25425853178
client_dur: 75664
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25425868250
server_dur: 50805
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24696,11 +26010,13 @@ android_binder {
client_ts: 25425949096
client_dur: 75914
client_tid: 1591
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25425967109
server_dur: 49564
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24733,11 +26049,13 @@ android_binder {
client_ts: 25507770941
client_dur: 659345
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25507817302
server_dur: 493959
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24764,11 +26082,13 @@ android_binder {
client_ts: 25508483480
client_dur: 113431
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25508520735
server_dur: 37596
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24795,11 +26115,13 @@ android_binder {
client_ts: 25512346526
client_dur: 247626
client_tid: 665
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.sensors-service.example"
server_thread: "android.hardwar"
server_ts: 25512379433
server_dur: 68665
server_tid: 458
+ server_pid: 458
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24832,11 +26154,13 @@ android_binder {
client_ts: 25519832521
client_dur: 244039
client_tid: 665
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.sensors-service.example"
server_thread: "android.hardwar"
server_ts: 25519857925
server_dur: 186450
server_tid: 458
+ server_pid: 458
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24863,11 +26187,13 @@ android_binder {
client_ts: 25520140841
client_dur: 73832
client_tid: 665
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.sensors-service.example"
server_thread: "android.hardwar"
server_ts: 25520164682
server_dur: 18571
server_tid: 458
+ server_pid: 458
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24894,11 +26220,13 @@ android_binder {
client_ts: 25523026906
client_dur: 340409
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25523191948
server_dur: 40297
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24931,11 +26259,13 @@ android_binder {
client_ts: 25524188687
client_dur: 89696
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25524226273
server_dur: 31748
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -24968,11 +26298,13 @@ android_binder {
client_ts: 25524630643
client_dur: 80450
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25524666614
server_dur: 25632
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25005,11 +26337,13 @@ android_binder {
client_ts: 25524881306
client_dur: 64099
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25524906781
server_dur: 18982
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25042,11 +26376,13 @@ android_binder {
client_ts: 25525155622
client_dur: 182063
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25525206343
server_dur: 111535
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25079,11 +26415,13 @@ android_binder {
client_ts: 25886972081
client_dur: 392512
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/hwservicemanager"
server_thread: "hwservicemanage"
server_ts: 25887243579
server_dur: 100309
server_tid: 247
+ server_pid: 247
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25116,11 +26454,13 @@ android_binder {
client_ts: 25887384160
client_dur: 146196
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/hwservicemanager"
server_thread: "hwservicemanage"
server_ts: 25887501006
server_dur: 15631
server_tid: 247
+ server_pid: 247
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25153,11 +26493,13 @@ android_binder {
client_ts: 25887600584
client_dur: 263828
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/hwservicemanager"
server_thread: "hwservicemanage"
server_ts: 25887779478
server_dur: 69332
server_tid: 247
+ server_pid: 247
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25190,11 +26532,13 @@ android_binder {
client_ts: 25888119355
client_dur: 387727
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25888158284
server_dur: 330571
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25221,11 +26565,13 @@ android_binder {
client_ts: 25888835343
client_dur: 324156
client_tid: 665
+ client_pid: 641
server_process: "/system/bin/hwservicemanager"
server_thread: "hwservicemanage"
server_ts: 25888991319
server_dur: 112375
server_tid: 247
+ server_pid: 247
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25258,11 +26604,13 @@ android_binder {
client_ts: 24562258099
client_dur: 95711
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24562294551
server_dur: 25989
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25295,11 +26643,13 @@ android_binder {
client_ts: 24576142302
client_dur: 100932
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24576178251
server_dur: 35440
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25326,11 +26676,13 @@ android_binder {
client_ts: 24577928034
client_dur: 98898
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24577965065
server_dur: 33433
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25357,11 +26709,13 @@ android_binder {
client_ts: 24579825258
client_dur: 91999
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24579857006
server_dur: 32771
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25388,11 +26742,13 @@ android_binder {
client_ts: 24586203617
client_dur: 160861
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24586241455
server_dur: 29609
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25425,11 +26781,13 @@ android_binder {
client_ts: 24588923637
client_dur: 381582
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24588962975
server_dur: 29095
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25462,11 +26820,13 @@ android_binder {
client_ts: 24592040006
client_dur: 240562
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24592076186
server_dur: 28582
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25499,11 +26859,13 @@ android_binder {
client_ts: 24594213703
client_dur: 673648
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24594243436
server_dur: 22881
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25536,11 +26898,13 @@ android_binder {
client_ts: 24595958354
client_dur: 77980
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24595993807
server_dur: 22950
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25573,11 +26937,13 @@ android_binder {
client_ts: 24597520537
client_dur: 49553
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24597542932
server_dur: 16294
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25610,11 +26976,13 @@ android_binder {
client_ts: 24598897106
client_dur: 68689
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24598922372
server_dur: 18191
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25647,11 +27015,13 @@ android_binder {
client_ts: 24600413274
client_dur: 57521
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24600434769
server_dur: 13168
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25684,11 +27054,13 @@ android_binder {
client_ts: 24602399966
client_dur: 80715
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24602431540
server_dur: 23433
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25721,11 +27093,13 @@ android_binder {
client_ts: 24603839586
client_dur: 50942
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24603864064
server_dur: 11482
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25758,11 +27132,13 @@ android_binder {
client_ts: 24605137324
client_dur: 53391
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24605161847
server_dur: 16108
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25795,11 +27171,13 @@ android_binder {
client_ts: 24607833798
client_dur: 79225
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24607864767
server_dur: 25864
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25832,11 +27210,13 @@ android_binder {
client_ts: 24609098413
client_dur: 86504
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24609132077
server_dur: 29462
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25869,11 +27249,13 @@ android_binder {
client_ts: 24646418600
client_dur: 104600
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24646446859
server_dur: 25546
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25900,11 +27282,13 @@ android_binder {
client_ts: 24671385803
client_dur: 170289
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24671409853
server_dur: 37825
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25931,11 +27315,13 @@ android_binder {
client_ts: 24681379300
client_dur: 57187
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24681399705
server_dur: 21305
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25962,11 +27348,13 @@ android_binder {
client_ts: 24682251210
client_dur: 182307
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24682273023
server_dur: 20664
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -25993,11 +27381,13 @@ android_binder {
client_ts: 24683246275
client_dur: 207024
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24683267459
server_dur: 20968
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26024,11 +27414,13 @@ android_binder {
client_ts: 24685075466
client_dur: 189680
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24685097014
server_dur: 20394
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26055,11 +27447,13 @@ android_binder {
client_ts: 24687047835
client_dur: 52825
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24687065149
server_dur: 20404
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26086,11 +27480,13 @@ android_binder {
client_ts: 24690752961
client_dur: 1138197
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24690773594
server_dur: 20275
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26117,11 +27513,13 @@ android_binder {
client_ts: 24692956765
client_dur: 967152
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24692973830
server_dur: 19601
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26148,11 +27546,13 @@ android_binder {
client_ts: 24699086985
client_dur: 2761757
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24699105127
server_dur: 19717
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26191,11 +27591,13 @@ android_binder {
client_ts: 24704026795
client_dur: 151503
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24704048621
server_dur: 19875
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26222,11 +27624,13 @@ android_binder {
client_ts: 24707823403
client_dur: 418749
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24707844258
server_dur: 19420
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26253,11 +27657,13 @@ android_binder {
client_ts: 24715413797
client_dur: 55453
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24715432924
server_dur: 20515
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26284,11 +27690,13 @@ android_binder {
client_ts: 24718094584
client_dur: 396933
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24718112985
server_dur: 20123
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26315,11 +27723,13 @@ android_binder {
client_ts: 24720389105
client_dur: 56955
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24720410588
server_dur: 19497
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26346,11 +27756,13 @@ android_binder {
client_ts: 24722237372
client_dur: 57988
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24722254479
server_dur: 19636
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26377,11 +27789,13 @@ android_binder {
client_ts: 24724223102
client_dur: 52789
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24724240486
server_dur: 19628
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26408,11 +27822,13 @@ android_binder {
client_ts: 24727963525
client_dur: 54516
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24727983399
server_dur: 19277
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26439,11 +27855,13 @@ android_binder {
client_ts: 24729275294
client_dur: 69527
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24729308987
server_dur: 19817
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26470,11 +27888,13 @@ android_binder {
client_ts: 24730464621
client_dur: 56830
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24730486611
server_dur: 19083
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26501,11 +27921,13 @@ android_binder {
client_ts: 24731541792
client_dur: 59775
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24731563743
server_dur: 19533
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26532,11 +27954,13 @@ android_binder {
client_ts: 24732635124
client_dur: 62661
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24732657580
server_dur: 22874
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26563,11 +27987,13 @@ android_binder {
client_ts: 24733694931
client_dur: 58749
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24733718525
server_dur: 19626
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26594,11 +28020,13 @@ android_binder {
client_ts: 24734519268
client_dur: 56933
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24734541289
server_dur: 19505
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26625,11 +28053,13 @@ android_binder {
client_ts: 24735621739
client_dur: 59911
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24735644076
server_dur: 19698
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26656,11 +28086,13 @@ android_binder {
client_ts: 24737578050
client_dur: 70375
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24737599805
server_dur: 19338
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26687,11 +28119,13 @@ android_binder {
client_ts: 24738379435
client_dur: 59307
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24738401334
server_dur: 19247
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26718,11 +28152,13 @@ android_binder {
client_ts: 24739381820
client_dur: 59860
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24739404070
server_dur: 19274
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26749,11 +28185,13 @@ android_binder {
client_ts: 24740296188
client_dur: 60137
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24740318642
server_dur: 19217
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26780,11 +28218,13 @@ android_binder {
client_ts: 24741062753
client_dur: 60144
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24741084854
server_dur: 19235
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26811,11 +28251,13 @@ android_binder {
client_ts: 24742188157
client_dur: 62717
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24742210951
server_dur: 22644
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26842,11 +28284,13 @@ android_binder {
client_ts: 24743215720
client_dur: 57215
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24743238157
server_dur: 19299
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26873,11 +28317,13 @@ android_binder {
client_ts: 24744310059
client_dur: 62304
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24744332347
server_dur: 22570
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26904,11 +28350,13 @@ android_binder {
client_ts: 24745726015
client_dur: 42535
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24745741462
server_dur: 13274
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26935,11 +28383,13 @@ android_binder {
client_ts: 24746812940
client_dur: 62487
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24746836091
server_dur: 21679
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26966,11 +28416,13 @@ android_binder {
client_ts: 24747614390
client_dur: 60851
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24747636567
server_dur: 21322
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -26997,11 +28449,13 @@ android_binder {
client_ts: 24748641464
client_dur: 98796
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24748705431
server_dur: 19737
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27028,11 +28482,13 @@ android_binder {
client_ts: 24749789307
client_dur: 58174
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24749812809
server_dur: 19265
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27059,11 +28515,13 @@ android_binder {
client_ts: 24753793235
client_dur: 285781
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24753872138
server_dur: 21667
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27090,11 +28548,13 @@ android_binder {
client_ts: 24760573761
client_dur: 55871
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24760593814
server_dur: 19818
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27121,11 +28581,13 @@ android_binder {
client_ts: 24761811419
client_dur: 104650
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24761830688
server_dur: 19717
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27152,11 +28614,13 @@ android_binder {
client_ts: 24763891343
client_dur: 52306
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24763908905
server_dur: 19517
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27183,11 +28647,13 @@ android_binder {
client_ts: 24764906537
client_dur: 55552
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24764927197
server_dur: 19435
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27214,11 +28680,13 @@ android_binder {
client_ts: 24766255714
client_dur: 69186
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24766285051
server_dur: 22399
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27245,11 +28713,13 @@ android_binder {
client_ts: 24767227873
client_dur: 55587
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24767248556
server_dur: 19425
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27276,11 +28746,13 @@ android_binder {
client_ts: 24770081943
client_dur: 54467
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24770101200
server_dur: 19938
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27307,11 +28779,13 @@ android_binder {
client_ts: 24773596028
client_dur: 197569
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24773614039
server_dur: 28282
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27338,11 +28812,13 @@ android_binder {
client_ts: 24785387433
client_dur: 2028794
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24785409117
server_dur: 20078
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27369,11 +28845,13 @@ android_binder {
client_ts: 24788209976
client_dur: 153903
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24788233234
server_dur: 20622
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27400,11 +28878,13 @@ android_binder {
client_ts: 24789221986
client_dur: 57706
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24789245188
server_dur: 19214
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27431,11 +28911,13 @@ android_binder {
client_ts: 24790705709
client_dur: 65167
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24790730301
server_dur: 25107
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27462,11 +28944,13 @@ android_binder {
client_ts: 24791500958
client_dur: 57742
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24791523460
server_dur: 19471
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27493,11 +28977,13 @@ android_binder {
client_ts: 24792307538
client_dur: 58314
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24792330556
server_dur: 19368
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27524,11 +29010,13 @@ android_binder {
client_ts: 24793372795
client_dur: 57390
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24793395000
server_dur: 19464
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27555,11 +29043,13 @@ android_binder {
client_ts: 24794492101
client_dur: 54114
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24794511315
server_dur: 19523
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27586,11 +29076,13 @@ android_binder {
client_ts: 24795410099
client_dur: 54987
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24795430573
server_dur: 19258
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27617,11 +29109,13 @@ android_binder {
client_ts: 24796677839
client_dur: 55067
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24796698242
server_dur: 19086
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27648,11 +29142,13 @@ android_binder {
client_ts: 24797815386
client_dur: 53079
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24797833699
server_dur: 19213
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27679,11 +29175,13 @@ android_binder {
client_ts: 24799449503
client_dur: 56617
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24799470930
server_dur: 19513
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27710,11 +29208,13 @@ android_binder {
client_ts: 24805536696
client_dur: 49858
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24805554922
server_dur: 16943
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27741,11 +29241,13 @@ android_binder {
client_ts: 24808769073
client_dur: 53981
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24808788665
server_dur: 19040
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27772,11 +29274,13 @@ android_binder {
client_ts: 24821382491
client_dur: 48977
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24821399252
server_dur: 17308
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27803,11 +29307,13 @@ android_binder {
client_ts: 24825799132
client_dur: 58481
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24825818665
server_dur: 20241
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27834,11 +29340,13 @@ android_binder {
client_ts: 24836015985
client_dur: 60190
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24836036269
server_dur: 24240
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27865,11 +29373,13 @@ android_binder {
client_ts: 24838902949
client_dur: 155997
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24838939369
server_dur: 21040
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27902,11 +29412,13 @@ android_binder {
client_ts: 24842361861
client_dur: 70409
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24842390226
server_dur: 21512
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27939,11 +29451,13 @@ android_binder {
client_ts: 24849556375
client_dur: 183165
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24849690991
server_dur: 24294
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -27976,11 +29490,13 @@ android_binder {
client_ts: 24871639354
client_dur: 68462
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24871671014
server_dur: 22834
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28013,11 +29529,13 @@ android_binder {
client_ts: 24873845755
client_dur: 1096098
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24873871989
server_dur: 21071
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28044,11 +29562,13 @@ android_binder {
client_ts: 24877992364
client_dur: 187259
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24878014368
server_dur: 20564
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28081,11 +29601,13 @@ android_binder {
client_ts: 24881598747
client_dur: 82762
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24881620007
server_dur: 37794
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28118,11 +29640,13 @@ android_binder {
client_ts: 24882762008
client_dur: 343179
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24883063470
server_dur: 18976
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28155,11 +29679,13 @@ android_binder {
client_ts: 24884363797
client_dur: 138909
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24884469472
server_dur: 19017
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28192,11 +29718,13 @@ android_binder {
client_ts: 24886610735
client_dur: 64238
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24886632996
server_dur: 20186
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28229,11 +29757,13 @@ android_binder {
client_ts: 24888078440
client_dur: 422798
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24888463594
server_dur: 19313
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28266,11 +29796,13 @@ android_binder {
client_ts: 24891297979
client_dur: 58221
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24891321099
server_dur: 19916
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28303,11 +29835,13 @@ android_binder {
client_ts: 24893930550
client_dur: 54133
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24893950723
server_dur: 20568
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28340,11 +29874,13 @@ android_binder {
client_ts: 24896595580
client_dur: 67589
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24896624063
server_dur: 20320
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28377,11 +29913,13 @@ android_binder {
client_ts: 24903024474
client_dur: 206934
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24903154456
server_dur: 20235
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28414,11 +29952,13 @@ android_binder {
client_ts: 24915150978
client_dur: 62178
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24915179748
server_dur: 21871
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28451,11 +29991,13 @@ android_binder {
client_ts: 24921237169
client_dur: 1189989
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24921585066
server_dur: 22945
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28488,11 +30030,13 @@ android_binder {
client_ts: 24924342216
client_dur: 260104
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24924548644
server_dur: 20604
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28525,11 +30069,13 @@ android_binder {
client_ts: 24932907687
client_dur: 61496
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24932929991
server_dur: 21719
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28562,11 +30108,13 @@ android_binder {
client_ts: 24936245311
client_dur: 89729
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24936266250
server_dur: 20798
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28593,11 +30141,13 @@ android_binder {
client_ts: 24943311799
client_dur: 214359
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24943331082
server_dur: 20072
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28624,11 +30174,13 @@ android_binder {
client_ts: 24967426046
client_dur: 238772
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 24967447878
server_dur: 21398
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28655,11 +30207,13 @@ android_binder {
client_ts: 25003883218
client_dur: 324891
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25003925054
server_dur: 43609
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28686,11 +30240,13 @@ android_binder {
client_ts: 25025076994
client_dur: 190930
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25025118986
server_dur: 30435
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28723,11 +30279,13 @@ android_binder {
client_ts: 25034377812
client_dur: 271653
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25034403338
server_dur: 27240
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28754,11 +30312,13 @@ android_binder {
client_ts: 25036622369
client_dur: 268217
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25036650886
server_dur: 26015
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28785,11 +30345,13 @@ android_binder {
client_ts: 25048460597
client_dur: 56503
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25048480970
server_dur: 20752
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28816,11 +30378,13 @@ android_binder {
client_ts: 25056764479
client_dur: 56793
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25056784331
server_dur: 20103
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28847,11 +30411,13 @@ android_binder {
client_ts: 25073721612
client_dur: 55061
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25073740814
server_dur: 20447
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28878,11 +30444,13 @@ android_binder {
client_ts: 25110161805
client_dur: 81154
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25110196375
server_dur: 24505
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28915,11 +30483,13 @@ android_binder {
client_ts: 25118254173
client_dur: 89345
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25118275515
server_dur: 30281
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28946,11 +30516,13 @@ android_binder {
client_ts: 25126211905
client_dur: 156793
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25126252664
server_dur: 31152
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -28983,11 +30555,13 @@ android_binder {
client_ts: 25128591519
client_dur: 86261
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25128613762
server_dur: 22079
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29014,11 +30588,13 @@ android_binder {
client_ts: 25137455943
client_dur: 138560
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25137492801
server_dur: 24108
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29051,11 +30627,13 @@ android_binder {
client_ts: 25171098007
client_dur: 86786
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25171119721
server_dur: 24637
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29082,11 +30660,13 @@ android_binder {
client_ts: 25176666011
client_dur: 68313
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25176690933
server_dur: 22908
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29125,11 +30705,13 @@ android_binder {
client_ts: 25180015030
client_dur: 119578
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25180094139
server_dur: 21082
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29168,11 +30750,13 @@ android_binder {
client_ts: 25185495297
client_dur: 90240
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25185546375
server_dur: 20903
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29211,11 +30795,13 @@ android_binder {
client_ts: 25190169442
client_dur: 56523
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25190190035
server_dur: 19360
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29248,11 +30834,13 @@ android_binder {
client_ts: 25192159947
client_dur: 67609
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25192191721
server_dur: 19584
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29285,11 +30873,13 @@ android_binder {
client_ts: 25194833721
client_dur: 54386
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25194853231
server_dur: 19541
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29316,11 +30906,13 @@ android_binder {
client_ts: 25197865886
client_dur: 55290
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25197885904
server_dur: 19555
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29347,11 +30939,13 @@ android_binder {
client_ts: 25205510080
client_dur: 53971
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25205529822
server_dur: 19108
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29378,11 +30972,13 @@ android_binder {
client_ts: 25210682525
client_dur: 54427
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25210701854
server_dur: 19875
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29409,11 +31005,13 @@ android_binder {
client_ts: 25212773102
client_dur: 143598
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25212807375
server_dur: 20140
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29446,11 +31044,13 @@ android_binder {
client_ts: 25219095678
client_dur: 62570
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25219117631
server_dur: 20590
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29490,11 +31090,13 @@ android_binder {
client_ts: 25230101202
client_dur: 295436
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25230125660
server_dur: 202423
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29528,11 +31130,13 @@ android_binder {
client_ts: 25243511980
client_dur: 489650
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25243544499
server_dur: 438512
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -29590,11 +31194,13 @@ android_binder {
client_ts: 25244949065
client_dur: 33302645
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25244971300
server_dur: 33241468
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -29676,11 +31282,13 @@ android_binder {
client_ts: 25279371214
client_dur: 141670
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25279387389
server_dur: 110471
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29714,11 +31322,13 @@ android_binder {
client_ts: 25279567724
client_dur: 1117204
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25279592927
server_dur: 1062729
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -29776,11 +31386,13 @@ android_binder {
client_ts: 25280736368
client_dur: 173449
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25280756522
server_dur: 131586
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29814,11 +31426,13 @@ android_binder {
client_ts: 25280932813
client_dur: 166964
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25280946041
server_dur: 122533
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29852,11 +31466,13 @@ android_binder {
client_ts: 25281131360
client_dur: 127300
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25281145719
server_dur: 98609
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29890,11 +31506,13 @@ android_binder {
client_ts: 25281273755
client_dur: 152610
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25281315273
server_dur: 97815
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29928,11 +31546,13 @@ android_binder {
client_ts: 25281454812
client_dur: 120876
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25281470206
server_dur: 94381
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -29966,11 +31586,13 @@ android_binder {
client_ts: 25281590129
client_dur: 151723
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25281611020
server_dur: 119089
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30004,11 +31626,13 @@ android_binder {
client_ts: 25281756115
client_dur: 115379
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25281769371
server_dur: 91666
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30042,11 +31666,13 @@ android_binder {
client_ts: 25281884499
client_dur: 116250
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25281896268
server_dur: 93727
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30080,11 +31706,13 @@ android_binder {
client_ts: 25282021405
client_dur: 113709
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282032972
server_dur: 91541
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30118,11 +31746,13 @@ android_binder {
client_ts: 25282147043
client_dur: 114363
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282159024
server_dur: 91525
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30156,11 +31786,13 @@ android_binder {
client_ts: 25282273296
client_dur: 113496
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282285050
server_dur: 91191
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30194,11 +31826,13 @@ android_binder {
client_ts: 25282398433
client_dur: 133314
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282413336
server_dur: 107722
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30232,11 +31866,13 @@ android_binder {
client_ts: 25282543082
client_dur: 113069
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282556151
server_dur: 89003
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30270,11 +31906,13 @@ android_binder {
client_ts: 25282667987
client_dur: 110166
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282679437
server_dur: 87774
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30308,11 +31946,13 @@ android_binder {
client_ts: 25282789771
client_dur: 113837
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282802242
server_dur: 90943
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30346,11 +31986,13 @@ android_binder {
client_ts: 25282914877
client_dur: 111627
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25282927602
server_dur: 88554
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30384,11 +32026,13 @@ android_binder {
client_ts: 25283038152
client_dur: 1992379
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_2"
server_ts: 25284866843
server_dur: 141149
server_tid: 548
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30421,11 +32065,13 @@ android_binder {
client_ts: 25374394471
client_dur: 2049689
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25374452290
server_dur: 56976
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30452,11 +32098,13 @@ android_binder {
client_ts: 25376513735
client_dur: 1298945
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25376552511
server_dur: 1229818
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -30513,11 +32161,13 @@ android_binder {
client_ts: 25380873939
client_dur: 94827
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25380918552
server_dur: 29189
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30544,11 +32194,13 @@ android_binder {
client_ts: 25382555538
client_dur: 499495
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25382942898
server_dur: 73464
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30581,11 +32233,13 @@ android_binder {
client_ts: 25383224119
client_dur: 475348
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25383318022
server_dur: 71453
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30618,11 +32272,13 @@ android_binder {
client_ts: 25384246889
client_dur: 2183818
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25386357038
server_dur: 45022
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30655,11 +32311,13 @@ android_binder {
client_ts: 25386462748
client_dur: 100360
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25386487821
server_dur: 60382
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30686,11 +32344,13 @@ android_binder {
client_ts: 25386597595
client_dur: 98608
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25386619074
server_dur: 61591
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30717,11 +32377,13 @@ android_binder {
client_ts: 25386719729
client_dur: 86786
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25386741757
server_dur: 49965
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30748,11 +32410,13 @@ android_binder {
client_ts: 25386829528
client_dur: 89755
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25386849083
server_dur: 55739
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30779,11 +32443,13 @@ android_binder {
client_ts: 25386948016
client_dur: 83210
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25386968208
server_dur: 48426
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30810,11 +32476,13 @@ android_binder {
client_ts: 25387051427
client_dur: 82153
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25387070661
server_dur: 48379
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30841,11 +32509,13 @@ android_binder {
client_ts: 25387162195
client_dur: 82295
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25387182559
server_dur: 47439
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30872,11 +32542,13 @@ android_binder {
client_ts: 25387268275
client_dur: 86930
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25387287442
server_dur: 52733
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30903,11 +32575,13 @@ android_binder {
client_ts: 25400532103
client_dur: 58804
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25400550889
server_dur: 23976
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30934,11 +32608,13 @@ android_binder {
client_ts: 25400815946
client_dur: 53189
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25400833837
server_dur: 20666
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30965,11 +32641,13 @@ android_binder {
client_ts: 25426768392
client_dur: 59432
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25426787956
server_dur: 24158
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -30996,11 +32674,13 @@ android_binder {
client_ts: 25428341210
client_dur: 87943
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25428360065
server_dur: 51321
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31028,11 +32708,13 @@ android_binder {
client_ts: 25428597840
client_dur: 1897216
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25428614184
server_dur: 1721051
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -31108,11 +32790,13 @@ android_binder {
client_ts: 25430545529
client_dur: 5604165
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25430555701
server_dur: 5580114
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -31176,11 +32860,13 @@ android_binder {
client_ts: 25436197115
client_dur: 165295
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_2"
server_ts: 25436268304
server_dur: 84720
server_tid: 541
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31214,11 +32900,13 @@ android_binder {
client_ts: 25436454693
client_dur: 101710
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25436467750
server_dur: 68620
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31258,11 +32946,13 @@ android_binder {
client_ts: 25436579821
client_dur: 1131075
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_2"
server_ts: 25436605605
server_dur: 1092472
server_tid: 541
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31296,11 +32986,13 @@ android_binder {
client_ts: 25437807385
client_dur: 35309
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_2"
server_ts: 25437821151
server_dur: 13284
server_tid: 541
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31334,11 +33026,13 @@ android_binder {
client_ts: 25437906939
client_dur: 108314
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25437930754
server_dur: 65111
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31384,11 +33078,13 @@ android_binder {
client_ts: 25438037598
client_dur: 1231074
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25438067211
server_dur: 1188167
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31428,11 +33124,13 @@ android_binder {
client_ts: 25439303208
client_dur: 56463
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25439340083
server_dur: 11933
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31466,11 +33164,13 @@ android_binder {
client_ts: 25439404915
client_dur: 28249
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25439417069
server_dur: 8812
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31504,11 +33204,13 @@ android_binder {
client_ts: 25439834153
client_dur: 149238
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25439854310
server_dur: 63659
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31548,11 +33250,13 @@ android_binder {
client_ts: 25440007897
client_dur: 617701
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25440026034
server_dur: 581007
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31586,11 +33290,13 @@ android_binder {
client_ts: 25440650480
client_dur: 37954
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25440669130
server_dur: 11644
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31624,11 +33330,13 @@ android_binder {
client_ts: 25440744629
client_dur: 130786
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25440759041
server_dur: 97590
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31668,11 +33376,13 @@ android_binder {
client_ts: 25440898977
client_dur: 1131318
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25440930592
server_dur: 1086590
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -31718,11 +33428,13 @@ android_binder {
client_ts: 25442065948
client_dur: 37271
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_1"
server_ts: 25442083599
server_dur: 12197
server_tid: 557
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31756,11 +33468,13 @@ android_binder {
client_ts: 25442154751
client_dur: 91298
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25442164438
server_dur: 64020
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31800,11 +33514,13 @@ android_binder {
client_ts: 25442267983
client_dur: 969844
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25442291581
server_dur: 932552
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31844,11 +33560,13 @@ android_binder {
client_ts: 25443270028
client_dur: 50947
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25443301118
server_dur: 11975
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -31882,11 +33600,13 @@ android_binder {
client_ts: 25443369306
client_dur: 97383
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25443387190
server_dur: 61382
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -31926,11 +33646,13 @@ android_binder {
client_ts: 25443488838
client_dur: 710384
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25443518308
server_dur: 668611
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -31976,11 +33698,13 @@ android_binder {
client_ts: 25444231572
client_dur: 52027
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25444264016
server_dur: 12085
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32014,11 +33738,13 @@ android_binder {
client_ts: 25444518761
client_dur: 104456
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25444539803
server_dur: 63755
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32058,11 +33784,13 @@ android_binder {
client_ts: 25444646123
client_dur: 413789
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25444674530
server_dur: 371297
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32096,11 +33824,13 @@ android_binder {
client_ts: 25445078459
client_dur: 37933
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25445097539
server_dur: 11521
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32134,11 +33864,13 @@ android_binder {
client_ts: 25445162965
client_dur: 98821
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25445176700
server_dur: 65755
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32178,11 +33910,13 @@ android_binder {
client_ts: 25445283998
client_dur: 1223250
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25445325570
server_dur: 1169074
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32228,11 +33962,13 @@ android_binder {
client_ts: 25446539928
client_dur: 55845
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25446574718
server_dur: 12523
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32266,11 +34002,13 @@ android_binder {
client_ts: 25446655842
client_dur: 102770
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25446673983
server_dur: 64748
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32310,11 +34048,13 @@ android_binder {
client_ts: 25446780771
client_dur: 484620
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25446802921
server_dur: 383705
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32354,11 +34094,13 @@ android_binder {
client_ts: 25447296204
client_dur: 32106
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25447307403
server_dur: 12025
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32392,11 +34134,13 @@ android_binder {
client_ts: 25447383428
client_dur: 99654
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25447399103
server_dur: 64249
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32436,11 +34180,13 @@ android_binder {
client_ts: 25447504358
client_dur: 1088603
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25447527457
server_dur: 1052788
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -32486,11 +34232,13 @@ android_binder {
client_ts: 25448618882
client_dur: 65160
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25448662606
server_dur: 12297
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32524,11 +34272,13 @@ android_binder {
client_ts: 25448732540
client_dur: 90622
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25448745055
server_dur: 61605
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32568,11 +34318,13 @@ android_binder {
client_ts: 25448844089
client_dur: 1341222
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25448878397
server_dur: 1294973
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32612,11 +34364,13 @@ android_binder {
client_ts: 25450214696
client_dur: 132324
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25450325232
server_dur: 12314
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32650,11 +34404,13 @@ android_binder {
client_ts: 25450401044
client_dur: 34066
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25450413421
server_dur: 8832
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32688,11 +34444,13 @@ android_binder {
client_ts: 25450477847
client_dur: 108090
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25450488460
server_dur: 82190
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32732,11 +34490,13 @@ android_binder {
client_ts: 25450607703
client_dur: 1259215
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25450647353
server_dur: 1203353
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32776,11 +34536,13 @@ android_binder {
client_ts: 25451902370
client_dur: 111453
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25451993380
server_dur: 11814
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32814,11 +34576,13 @@ android_binder {
client_ts: 25452994340
client_dur: 109726
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25453017159
server_dur: 64867
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32858,11 +34622,13 @@ android_binder {
client_ts: 25453126725
client_dur: 1046699
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25453215693
server_dur: 328275
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32896,11 +34662,13 @@ android_binder {
client_ts: 25454206920
client_dur: 37100
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25454216327
server_dur: 14099
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -32934,11 +34702,13 @@ android_binder {
client_ts: 25454305892
client_dur: 105614
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25454321058
server_dur: 71322
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -32978,11 +34748,13 @@ android_binder {
client_ts: 25454433615
client_dur: 1182599
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25454454326
server_dur: 1148464
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -33022,11 +34794,13 @@ android_binder {
client_ts: 25455648152
client_dur: 89055
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25455717688
server_dur: 10552
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33060,11 +34834,13 @@ android_binder {
client_ts: 25455783097
client_dur: 77504
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25455796471
server_dur: 53966
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33098,11 +34874,13 @@ android_binder {
client_ts: 25455870323
client_dur: 183133
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25455880236
server_dur: 164382
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33136,11 +34914,13 @@ android_binder {
client_ts: 25456454160
client_dur: 31893
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25456468473
server_dur: 7849
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33174,11 +34954,13 @@ android_binder {
client_ts: 25456548523
client_dur: 98167
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25456560742
server_dur: 75793
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -33218,11 +35000,13 @@ android_binder {
client_ts: 25456659359
client_dur: 202533
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25456689304
server_dur: 163129
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33256,11 +35040,13 @@ android_binder {
client_ts: 25456872988
client_dur: 29135
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/idmap2d"
server_thread: "binder:541_3"
server_ts: 25456888657
server_dur: 6402
server_tid: 1598
+ server_pid: 541
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33293,11 +35079,13 @@ android_binder {
client_ts: 25494548191
client_dur: 258095
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25494622231
server_dur: 150527
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33330,11 +35118,13 @@ android_binder {
client_ts: 25495244473
client_dur: 325048
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25495400405
server_dur: 128258
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33367,11 +35157,13 @@ android_binder {
client_ts: 25504141418
client_dur: 297361
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25504207270
server_dur: 133515
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33398,11 +35190,13 @@ android_binder {
client_ts: 25511329109
client_dur: 678596
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25511805543
server_dur: 136659
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33435,11 +35229,13 @@ android_binder {
client_ts: 25517948532
client_dur: 163240
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25518009843
server_dur: 44297
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33472,11 +35268,13 @@ android_binder {
client_ts: 25518739183
client_dur: 3265864
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25518779467
server_dur: 374561
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33509,11 +35307,13 @@ android_binder {
client_ts: 25523067296
client_dur: 1153803
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25523345752
server_dur: 24699
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33546,11 +35346,13 @@ android_binder {
client_ts: 25529407157
client_dur: 1243348
client_tid: 641
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.health-service.cuttlefish"
server_thread: "android.hardwar"
server_ts: 25529886580
server_dur: 502254
server_tid: 431
+ server_pid: 431
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -33589,11 +35391,13 @@ android_binder {
client_ts: 25530820205
client_dur: 1517480
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25530877699
server_dur: 79639
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33626,11 +35430,13 @@ android_binder {
client_ts: 25538312793
client_dur: 177283
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25538360355
server_dur: 73011
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33663,11 +35469,13 @@ android_binder {
client_ts: 25538521832
client_dur: 115418
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25538557132
server_dur: 51687
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33700,11 +35508,13 @@ android_binder {
client_ts: 25555649759
client_dur: 401986
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25555822535
server_dur: 166864
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33737,11 +35547,13 @@ android_binder {
client_ts: 25562439114
client_dur: 360669
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25562601598
server_dur: 147343
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33774,11 +35586,13 @@ android_binder {
client_ts: 25564138751
client_dur: 227016
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25564207677
server_dur: 112964
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33811,11 +35625,13 @@ android_binder {
client_ts: 25564950504
client_dur: 216354
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25565018623
server_dur: 104733
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33848,11 +35664,13 @@ android_binder {
client_ts: 25565861693
client_dur: 154693
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25565923809
server_dur: 44929
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33886,11 +35704,13 @@ android_binder {
client_ts: 25566098278
client_dur: 3268381
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25566134660
server_dur: 2297021
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33923,11 +35743,13 @@ android_binder {
client_ts: 25578643057
client_dur: 230121
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25578709142
server_dur: 126093
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33954,11 +35776,13 @@ android_binder {
client_ts: 25579716604
client_dur: 216367
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25579776806
server_dur: 121078
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -33985,11 +35809,13 @@ android_binder {
client_ts: 25584224256
client_dur: 249444
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25584297755
server_dur: 135137
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34016,11 +35842,13 @@ android_binder {
client_ts: 25585086651
client_dur: 284206
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25585152822
server_dur: 129855
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34047,11 +35875,13 @@ android_binder {
client_ts: 25587741520
client_dur: 249445
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25587810843
server_dur: 138515
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34078,11 +35908,13 @@ android_binder {
client_ts: 25588452300
client_dur: 243841
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25588512250
server_dur: 145542
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34109,11 +35941,13 @@ android_binder {
client_ts: 25607046968
client_dur: 141541
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25607085845
server_dur: 83802
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34140,11 +35974,13 @@ android_binder {
client_ts: 25626771532
client_dur: 407539
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25627067466
server_dur: 61702
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34177,11 +36013,13 @@ android_binder {
client_ts: 25627247935
client_dur: 118074
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25627290693
server_dur: 38186
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34208,11 +36046,13 @@ android_binder {
client_ts: 25627461473
client_dur: 244900
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25627519338
server_dur: 149891
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34239,11 +36079,13 @@ android_binder {
client_ts: 25632313567
client_dur: 258248
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25632388552
server_dur: 141000
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34270,11 +36112,13 @@ android_binder {
client_ts: 25637260298
client_dur: 196517
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25637328529
server_dur: 88341
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34301,11 +36145,13 @@ android_binder {
client_ts: 25656975183
client_dur: 72577
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25656999460
server_dur: 31187
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34332,11 +36178,13 @@ android_binder {
client_ts: 25657158859
client_dur: 49143
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25657175302
server_dur: 18337
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34363,11 +36211,13 @@ android_binder {
client_ts: 25659444951
client_dur: 67480
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25659467572
server_dur: 27682
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34394,11 +36244,13 @@ android_binder {
client_ts: 25710903029
client_dur: 196994
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25710975935
server_dur: 69286
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34431,11 +36283,13 @@ android_binder {
client_ts: 25779384485
client_dur: 6404465
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25779465833
server_dur: 115210
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34468,11 +36322,13 @@ android_binder {
client_ts: 25785903212
client_dur: 173175
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25785969981
server_dur: 74609
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34505,11 +36361,13 @@ android_binder {
client_ts: 25786187023
client_dur: 71969
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25786216656
server_dur: 16443
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34542,11 +36400,13 @@ android_binder {
client_ts: 25788338381
client_dur: 66978
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25788365130
server_dur: 26182
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34579,11 +36439,13 @@ android_binder {
client_ts: 25788426430
client_dur: 44938
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25788444575
server_dur: 12371
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34616,11 +36478,13 @@ android_binder {
client_ts: 25794664939
client_dur: 125489
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25794702859
server_dur: 70821
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34647,11 +36511,13 @@ android_binder {
client_ts: 25803399428
client_dur: 125121
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25803446233
server_dur: 61602
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34684,11 +36550,13 @@ android_binder {
client_ts: 25805561097
client_dur: 258904
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25805581639
server_dur: 24195
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34715,11 +36583,13 @@ android_binder {
client_ts: 25806638177
client_dur: 383567
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25806656214
server_dur: 348438
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34746,11 +36616,13 @@ android_binder {
client_ts: 25807042562
client_dur: 45260
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25807056567
server_dur: 14991
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34777,11 +36649,13 @@ android_binder {
client_ts: 25807129635
client_dur: 626529
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25807318058
server_dur: 335442
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "D"
@@ -34832,11 +36706,13 @@ android_binder {
client_ts: 25807794682
client_dur: 197460
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25807808849
server_dur: 31598
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34869,11 +36745,13 @@ android_binder {
client_ts: 25808041191
client_dur: 152874
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808112547
server_dur: 38477
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34906,11 +36784,13 @@ android_binder {
client_ts: 25808300543
client_dur: 216110
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808488934
server_dur: 5816
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34943,11 +36823,13 @@ android_binder {
client_ts: 25808536171
client_dur: 29720
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808549475
server_dur: 6142
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -34980,11 +36862,13 @@ android_binder {
client_ts: 25808580143
client_dur: 23193
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808589636
server_dur: 4653
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35017,11 +36901,13 @@ android_binder {
client_ts: 25808614611
client_dur: 24483
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808626104
server_dur: 4244
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35054,11 +36940,13 @@ android_binder {
client_ts: 25808649459
client_dur: 19535
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808656163
server_dur: 4039
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35091,11 +36979,13 @@ android_binder {
client_ts: 25808679113
client_dur: 22778
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808688986
server_dur: 3889
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35128,11 +37018,13 @@ android_binder {
client_ts: 25808712146
client_dur: 21102
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808720606
server_dur: 3664
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35165,11 +37057,13 @@ android_binder {
client_ts: 25808743343
client_dur: 49190
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808773138
server_dur: 4014
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35202,11 +37096,13 @@ android_binder {
client_ts: 25808803408
client_dur: 47244
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808832840
server_dur: 3744
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35239,11 +37135,13 @@ android_binder {
client_ts: 25808861280
client_dur: 23141
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808871693
server_dur: 4083
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35276,11 +37174,13 @@ android_binder {
client_ts: 25808894304
client_dur: 22212
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808903846
server_dur: 4193
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35313,11 +37213,13 @@ android_binder {
client_ts: 25808927915
client_dur: 23489
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808938201
server_dur: 4441
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35350,11 +37252,13 @@ android_binder {
client_ts: 25808963769
client_dur: 21106
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25808972274
server_dur: 4301
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35387,11 +37291,13 @@ android_binder {
client_ts: 25808996827
client_dur: 22150
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809006677
server_dur: 3852
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35424,11 +37330,13 @@ android_binder {
client_ts: 25809029487
client_dur: 30653
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809048418
server_dur: 3146
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35461,11 +37369,13 @@ android_binder {
client_ts: 25809070927
client_dur: 105314
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809156958
server_dur: 4090
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35498,11 +37408,13 @@ android_binder {
client_ts: 25809187458
client_dur: 21199
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809196575
server_dur: 3729
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35535,11 +37447,13 @@ android_binder {
client_ts: 25809219112
client_dur: 20851
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809227683
server_dur: 3856
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35572,11 +37486,13 @@ android_binder {
client_ts: 25809250949
client_dur: 271118
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809502291
server_dur: 4522
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35609,11 +37525,13 @@ android_binder {
client_ts: 25809543172
client_dur: 29191
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809555589
server_dur: 4714
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35646,11 +37564,13 @@ android_binder {
client_ts: 25809583743
client_dur: 23569
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809592470
server_dur: 3948
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35683,11 +37603,13 @@ android_binder {
client_ts: 25809618388
client_dur: 38876
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809637992
server_dur: 8798
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35720,11 +37642,13 @@ android_binder {
client_ts: 25809757746
client_dur: 171172
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809770125
server_dur: 89637
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -35763,11 +37687,13 @@ android_binder {
client_ts: 25809948987
client_dur: 120274
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25809967298
server_dur: 27536
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35800,11 +37726,13 @@ android_binder {
client_ts: 25810106019
client_dur: 110073
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25810132739
server_dur: 5193
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35837,11 +37765,13 @@ android_binder {
client_ts: 25810239347
client_dur: 148792
client_tid: 641
+ client_pid: 641
server_process: "/apex/com.android.hardware.vibrator/bin/hw/android.hardware.vibrator-service.example"
server_thread: "android.hardwar"
server_ts: 25810364813
server_dur: 3865
server_tid: 481
+ server_pid: 481
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35874,11 +37804,13 @@ android_binder {
client_ts: 25810497904
client_dur: 126359
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25810531969
server_dur: 73542
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35905,11 +37837,13 @@ android_binder {
client_ts: 25810646589
client_dur: 91503
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25810669576
server_dur: 52662
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35936,11 +37870,13 @@ android_binder {
client_ts: 25810948647
client_dur: 113503
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25810980358
server_dur: 64314
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35967,11 +37903,13 @@ android_binder {
client_ts: 25811246975
client_dur: 366342
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25811269261
server_dur: 324989
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -35998,11 +37936,13 @@ android_binder {
client_ts: 25811641918
client_dur: 83600
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25811659549
server_dur: 47010
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -36035,11 +37975,13 @@ android_binder {
client_ts: 25811827364
client_dur: 105911
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25811855742
server_dur: 60946
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36066,11 +38008,13 @@ android_binder {
client_ts: 25814468030
client_dur: 128573
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25814502303
server_dur: 75807
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36097,11 +38041,13 @@ android_binder {
client_ts: 25824457100
client_dur: 243653
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25824484172
server_dur: 202360
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -36134,11 +38080,13 @@ android_binder {
client_ts: 25826929585
client_dur: 134380
client_tid: 1618
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25826953314
server_dur: 57893
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36171,11 +38119,13 @@ android_binder {
client_ts: 25827095345
client_dur: 59551
client_tid: 1618
+ client_pid: 641
server_process: "/apex/com.android.os.statsd/bin/statsd"
server_thread: "binder:415_3"
server_ts: 25827112546
server_dur: 28045
server_tid: 422
+ server_pid: 415
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36208,11 +38158,13 @@ android_binder {
client_ts: 25828178041
client_dur: 75912
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25828192051
server_dur: 26713
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36245,11 +38197,13 @@ android_binder {
client_ts: 25828289955
client_dur: 48095
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25828303964
server_dur: 23818
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36282,11 +38236,13 @@ android_binder {
client_ts: 25833585425
client_dur: 213739
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25833674904
server_dur: 59579
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36319,11 +38275,13 @@ android_binder {
client_ts: 25834911169
client_dur: 66864
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25834940005
server_dur: 22905
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36356,11 +38314,13 @@ android_binder {
client_ts: 25835009103
client_dur: 41035
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25835029405
server_dur: 9917
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36393,11 +38353,13 @@ android_binder {
client_ts: 25835084036
client_dur: 39828
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25835102285
server_dur: 11104
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36430,11 +38392,13 @@ android_binder {
client_ts: 25835225817
client_dur: 39668
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25835244300
server_dur: 10401
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36467,11 +38431,13 @@ android_binder {
client_ts: 25835491757
client_dur: 94706
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25835523199
server_dur: 50044
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36504,11 +38470,13 @@ android_binder {
client_ts: 25838116144
client_dur: 101371
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25838145038
server_dur: 57786
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36535,11 +38503,13 @@ android_binder {
client_ts: 25854689410
client_dur: 72379
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25854716713
server_dur: 29735
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36572,11 +38542,13 @@ android_binder {
client_ts: 25854776152
client_dur: 84994
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25854792697
server_dur: 55053
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36609,11 +38581,13 @@ android_binder {
client_ts: 25856165265
client_dur: 41372
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25856179451
server_dur: 11065
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36646,11 +38620,13 @@ android_binder {
client_ts: 25859386674
client_dur: 62804
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25859406671
server_dur: 23198
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36677,11 +38653,13 @@ android_binder {
client_ts: 25860119896
client_dur: 89982
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25860140536
server_dur: 54911
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36708,11 +38686,13 @@ android_binder {
client_ts: 25861940989
client_dur: 112198
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25861960190
server_dur: 69698
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36745,11 +38725,13 @@ android_binder {
client_ts: 25862411224
client_dur: 72918
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25862426577
server_dur: 43364
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36782,11 +38764,13 @@ android_binder {
client_ts: 25862572364
client_dur: 43335
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25862583679
server_dur: 21214
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36819,11 +38803,13 @@ android_binder {
client_ts: 25862644016
client_dur: 35084
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25862653442
server_dur: 16522
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36856,11 +38842,13 @@ android_binder {
client_ts: 25862703240
client_dur: 43193
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25862712076
server_dur: 25328
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36893,11 +38881,13 @@ android_binder {
client_ts: 25863309305
client_dur: 56073
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25863321886
server_dur: 30965
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36930,11 +38920,13 @@ android_binder {
client_ts: 25863414967
client_dur: 48999
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25863426312
server_dur: 27403
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -36967,11 +38959,13 @@ android_binder {
client_ts: 25864046858
client_dur: 61808
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864062070
server_dur: 32956
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37004,11 +38998,13 @@ android_binder {
client_ts: 25864143436
client_dur: 51337
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864153386
server_dur: 30980
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37041,11 +39037,13 @@ android_binder {
client_ts: 25864216828
client_dur: 37990
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864226073
server_dur: 19004
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37078,11 +39076,13 @@ android_binder {
client_ts: 25864279759
client_dur: 37961
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864288819
server_dur: 19366
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37115,11 +39115,13 @@ android_binder {
client_ts: 25864345023
client_dur: 59115
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864354391
server_dur: 17778
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37152,11 +39154,13 @@ android_binder {
client_ts: 25864449726
client_dur: 51629
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864460717
server_dur: 26406
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37189,11 +39193,13 @@ android_binder {
client_ts: 25864530175
client_dur: 40230
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864539824
server_dur: 19580
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37226,11 +39232,13 @@ android_binder {
client_ts: 25864603443
client_dur: 64958
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864612742
server_dur: 44603
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37263,11 +39271,13 @@ android_binder {
client_ts: 25864687472
client_dur: 38679
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864696221
server_dur: 19520
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37300,11 +39310,13 @@ android_binder {
client_ts: 25864748376
client_dur: 41144
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864757238
server_dur: 21548
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37337,11 +39349,13 @@ android_binder {
client_ts: 25864814870
client_dur: 37926
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864824299
server_dur: 17299
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37374,11 +39388,13 @@ android_binder {
client_ts: 25864878443
client_dur: 41432
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864887850
server_dur: 21263
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37411,11 +39427,13 @@ android_binder {
client_ts: 25864943354
client_dur: 46446
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25864953070
server_dur: 26259
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37448,11 +39466,13 @@ android_binder {
client_ts: 25865010220
client_dur: 42768
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25865018943
server_dur: 22857
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37485,11 +39505,13 @@ android_binder {
client_ts: 25865078882
client_dur: 42845
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25865088374
server_dur: 22790
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37522,11 +39544,13 @@ android_binder {
client_ts: 25865143746
client_dur: 43541
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25865152587
server_dur: 24329
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37559,11 +39583,13 @@ android_binder {
client_ts: 25865208871
client_dur: 37989
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25865217954
server_dur: 18361
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37596,11 +39622,13 @@ android_binder {
client_ts: 25865269510
client_dur: 180816
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25865278803
server_dur: 44675
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -37639,11 +39667,13 @@ android_binder {
client_ts: 25865509380
client_dur: 1204393
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25866655580
server_dur: 37015
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37676,11 +39706,13 @@ android_binder {
client_ts: 25866765533
client_dur: 52077
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25866778140
server_dur: 25314
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37713,11 +39745,13 @@ android_binder {
client_ts: 25866847306
client_dur: 36125
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25866856611
server_dur: 17873
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37750,11 +39784,13 @@ android_binder {
client_ts: 25866907704
client_dur: 31809
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25866916674
server_dur: 14121
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37787,11 +39823,13 @@ android_binder {
client_ts: 25866963934
client_dur: 42576
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25866972903
server_dur: 18950
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37824,11 +39862,13 @@ android_binder {
client_ts: 25867031282
client_dur: 35871
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867040421
server_dur: 17984
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37861,11 +39901,13 @@ android_binder {
client_ts: 25867092641
client_dur: 34611
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867101335
server_dur: 17329
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37898,11 +39940,13 @@ android_binder {
client_ts: 25867155069
client_dur: 43809
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867163773
server_dur: 26243
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37935,11 +39979,13 @@ android_binder {
client_ts: 25867229729
client_dur: 32631
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867238857
server_dur: 14033
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -37972,11 +40018,13 @@ android_binder {
client_ts: 25867283252
client_dur: 40731
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867292366
server_dur: 21993
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38009,11 +40057,13 @@ android_binder {
client_ts: 25867343753
client_dur: 34724
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867353084
server_dur: 16650
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38046,11 +40096,13 @@ android_binder {
client_ts: 25867401523
client_dur: 50745
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867410223
server_dur: 32741
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38083,11 +40135,13 @@ android_binder {
client_ts: 25867475251
client_dur: 46815
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867485001
server_dur: 26611
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38120,11 +40174,13 @@ android_binder {
client_ts: 25867547843
client_dur: 36696
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867557467
server_dur: 18125
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38157,11 +40213,13 @@ android_binder {
client_ts: 25867605981
client_dur: 37415
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867614819
server_dur: 19663
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38194,11 +40252,13 @@ android_binder {
client_ts: 25867663292
client_dur: 35879
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867672122
server_dur: 17373
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38231,11 +40291,13 @@ android_binder {
client_ts: 25867751966
client_dur: 40848
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867761875
server_dur: 19072
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38269,11 +40331,13 @@ android_binder {
client_ts: 25867845030
client_dur: 180504
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25867860282
server_dur: 154468
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "R"
@@ -38318,11 +40382,13 @@ android_binder {
client_ts: 25872260669
client_dur: 83399
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25872278450
server_dur: 47096
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38355,11 +40421,13 @@ android_binder {
client_ts: 25885439966
client_dur: 1549817
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25886054638
server_dur: 24145
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38392,11 +40460,13 @@ android_binder {
client_ts: 25885831452
client_dur: 1452935
client_tid: 1623
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25886206332
server_dur: 305512
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38429,11 +40499,13 @@ android_binder {
client_ts: 25887309449
client_dur: 115655
client_tid: 1623
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25887326271
server_dur: 18512
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38460,11 +40532,13 @@ android_binder {
client_ts: 25887452954
client_dur: 283867
client_tid: 1623
+ client_pid: 641
server_process: "/vendor/bin/hw/android.hardware.input.processor-service.example"
server_thread: "android.hardwar"
server_ts: 25887467255
server_dur: 38055
server_tid: 447
+ server_pid: 447
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38491,11 +40565,13 @@ android_binder {
client_ts: 25892252212
client_dur: 2274293
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25894481596
server_dur: 27702
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38528,11 +40604,13 @@ android_binder {
client_ts: 25921269728
client_dur: 400263
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25921599983
server_dur: 52448
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38565,11 +40643,13 @@ android_binder {
client_ts: 25921747025
client_dur: 209278
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25921878602
server_dur: 66173
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38602,11 +40682,13 @@ android_binder {
client_ts: 25922308759
client_dur: 230930
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25922366800
server_dur: 58914
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38639,11 +40721,13 @@ android_binder {
client_ts: 25926152660
client_dur: 106426
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25926184604
server_dur: 59798
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38676,11 +40760,13 @@ android_binder {
client_ts: 25935520343
client_dur: 106898
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25935553945
server_dur: 59988
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38713,11 +40799,13 @@ android_binder {
client_ts: 25936096478
client_dur: 38431
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25936114070
server_dur: 13878
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38750,11 +40838,13 @@ android_binder {
client_ts: 25936154115
client_dur: 304852
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25936427202
server_dur: 13388
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38787,11 +40877,13 @@ android_binder {
client_ts: 25939273894
client_dur: 44659
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25939290557
server_dur: 19990
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38824,11 +40916,13 @@ android_binder {
client_ts: 25939575552
client_dur: 81712
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25939602201
server_dur: 44933
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38861,11 +40955,13 @@ android_binder {
client_ts: 25944988176
client_dur: 71994
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25945018540
server_dur: 25217
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38898,11 +40994,13 @@ android_binder {
client_ts: 25948938076
client_dur: 82091
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25948980882
server_dur: 27091
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38935,11 +41033,13 @@ android_binder {
client_ts: 25951851055
client_dur: 445134
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_3"
server_ts: 25951902501
server_dur: 183967
server_tid: 1575
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -38972,11 +41072,13 @@ android_binder {
client_ts: 25952609949
client_dur: 44997
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_2"
server_ts: 25952623297
server_dur: 18258
server_tid: 522
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39003,11 +41105,13 @@ android_binder {
client_ts: 25954386897
client_dur: 107947
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/surfaceflinger"
server_thread: "binder:496_3"
server_ts: 25954404617
server_dur: 18018
server_tid: 1575
+ server_pid: 496
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39040,11 +41144,13 @@ android_binder {
client_ts: 25955417145
client_dur: 248980
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25955442657
server_dur: 23870
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39078,11 +41184,13 @@ android_binder {
client_ts: 25955702503
client_dur: 1028567
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25955716400
server_dur: 923564
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39109,11 +41217,13 @@ android_binder {
client_ts: 25957071212
client_dur: 244964
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25957109467
server_dur: 68828
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39146,11 +41256,13 @@ android_binder {
client_ts: 25957345364
client_dur: 86035
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25957361868
server_dur: 39522
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39183,11 +41295,13 @@ android_binder {
client_ts: 25957477722
client_dur: 38342
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25957490997
server_dur: 14607
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39220,11 +41334,13 @@ android_binder {
client_ts: 25957561902
client_dur: 115285
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/vold"
server_thread: "binder:255_2"
server_ts: 25957584457
server_dur: 69879
server_tid: 255
+ server_pid: 255
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39257,11 +41373,13 @@ android_binder {
client_ts: 25957701552
client_dur: 31673
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/vold"
server_thread: "binder:255_2"
server_ts: 25957712540
server_dur: 11337
server_tid: 255
+ server_pid: 255
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39294,11 +41412,13 @@ android_binder {
client_ts: 25957917714
client_dur: 81359
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25957965656
server_dur: 19953
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39331,11 +41451,13 @@ android_binder {
client_ts: 25958179475
client_dur: 57952
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25958197817
server_dur: 12909
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39368,11 +41490,13 @@ android_binder {
client_ts: 25958259037
client_dur: 37816
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25958272198
server_dur: 12201
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39406,11 +41530,13 @@ android_binder {
client_ts: 25958323889
client_dur: 934386
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25958335597
server_dur: 816593
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39438,11 +41564,13 @@ android_binder {
client_ts: 25959279820
client_dur: 780373
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/installd"
server_thread: "binder:548_1"
server_ts: 25959289960
server_dur: 697719
server_tid: 565
+ server_pid: 548
thread_states {
thread_state_type: "binder_reply"
thread_state: "R+"
@@ -39475,11 +41603,13 @@ android_binder {
client_ts: 25960212392
client_dur: 138312
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25960246748
server_dur: 59922
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39512,11 +41642,13 @@ android_binder {
client_ts: 25960703658
client_dur: 185272
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25960733334
server_dur: 55452
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
@@ -39549,11 +41681,13 @@ android_binder {
client_ts: 25964272455
client_dur: 108953
client_tid: 641
+ client_pid: 641
server_process: "/system/bin/servicemanager"
server_thread: "servicemanager"
server_ts: 25964304630
server_dur: 66130
server_tid: 243
+ server_pid: 243
thread_states {
thread_state_type: "binder_reply"
thread_state: "Running"
diff --git a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out
index aa631943c..d75d44d3b 100644
--- a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out
+++ b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.out
@@ -5,6 +5,7 @@ android_blocking_calls_cuj_metric {
process {
name: "com.android.systemui"
uid: 10001
+ pid: 1000
}
ts: 2000000
dur: 15000000
@@ -22,6 +23,7 @@ android_blocking_calls_cuj_metric {
process {
name: "com.google.android.apps.nexuslauncher"
uid: 10002
+ pid: 2000
}
ts: 2000000
dur: 15000000
@@ -39,6 +41,7 @@ android_blocking_calls_cuj_metric {
process {
name: "com.google.android.third.process"
uid: 10003
+ pid: 3000
}
ts: 2000000
dur: 150000000
@@ -147,6 +150,7 @@ android_blocking_calls_cuj_metric {
process {
name: "com.android.systemui"
uid: 10001
+ pid: 1000
}
ts: 20000000
dur: 10000000
@@ -164,6 +168,7 @@ android_blocking_calls_cuj_metric {
process {
name: "com.android.systemui"
uid: 10001
+ pid: 1000
}
ts: 22000000
dur: 10000000
@@ -175,4 +180,29 @@ android_blocking_calls_cuj_metric {
min_dur_ms: 10
}
}
+ cuj {
+ id: 6
+ name: "WITH_NAMED_BINDER_TRANSACTION"
+ process {
+ name: "com.android.systemui"
+ uid: 10001
+ pid: 1000
+ }
+ ts: 40000000
+ dur: 10000000
+ blocking_calls {
+ name: "AIDL::java::IWindowManager::hasNavigationBar::server"
+ cnt: 1
+ total_dur_ms: 10
+ max_dur_ms: 10
+ min_dur_ms: 10
+ }
+ blocking_calls {
+ name: "binder transaction"
+ cnt: 1
+ total_dur_ms: 10
+ max_dur_ms: 10
+ min_dur_ms: 10
+ }
+ }
}
diff --git a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py
index 7573b76f6..1039e47f2 100755
--- a/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py
+++ b/test/trace_processor/diff_tests/android/android_blocking_calls_cuj_metric.py
@@ -45,6 +45,19 @@ def add_async_trace(trace, ts, ts_end, buf, pid):
trace.add_atrace_async_end(ts=ts_end, tid=pid, pid=pid, buf=buf)
+def add_binder_transaction(trace, tx_pid, rx_pid, start_ts, end_ts):
+ trace.add_binder_transaction(
+ transaction_id=tx_pid,
+ ts_start=start_ts,
+ ts_end=end_ts,
+ tid=tx_pid,
+ pid=tx_pid,
+ reply_id=rx_pid,
+ reply_ts_start=start_ts,
+ reply_ts_end=end_ts,
+ reply_tid=rx_pid,
+ reply_pid=rx_pid)
+
# Adds a set of predefined blocking calls in places near the cuj boundaries to
# verify that only the portion inside the cuj is counted in the metric.
def add_cuj_with_blocking_calls(trace, cuj_name, pid):
@@ -148,6 +161,31 @@ def add_overlapping_cujs_with_blocking_calls(trace, start_ts, pid):
pid=pid)
+def add_cuj_with_named_binder_transaction(pid, rx_pid):
+ cuj_begin = 40_000_000
+ cuj_end = 50_000_000
+
+ add_async_trace(
+ trace,
+ ts=cuj_begin,
+ ts_end=cuj_end,
+ buf="L<WITH_NAMED_BINDER_TRANSACTION>",
+ pid=pid)
+
+ add_binder_transaction(
+ trace, tx_pid=pid, rx_pid=rx_pid, start_ts=cuj_begin, end_ts=cuj_end)
+
+ # Slice inside the binder reply, to give a name to the binder call.
+ # The named binder slice introduced should be the length of the entire
+ # transaction even if the "name" slice only covers some of the binder reply.
+ add_main_thread_atrace(
+ trace,
+ ts=cuj_begin + 1_000_000,
+ ts_end=cuj_end - 1_000_000,
+ buf="AIDL::java::IWindowManager::hasNavigationBar::server",
+ pid=rx_pid)
+
+
def add_process(trace, package_name, uid, pid):
trace.add_package_list(ts=0, name=package_name, uid=uid, version_code=1)
trace.add_process(
@@ -180,6 +218,8 @@ add_all_blocking_calls_in_cuj(trace, pid=THIRD_PROCESS_PID)
add_overlapping_cujs_with_blocking_calls(trace, pid=SYSUI_PID,
start_ts=20_000_000)
+add_cuj_with_named_binder_transaction(pid=SYSUI_PID, rx_pid=LAUNCHER_PID)
+
# Note that J<*> events are not tested here.
# See test_android_blocking_calls_on_jank_cujs.
sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/test/trace_processor/diff_tests/android/android_blocking_calls_on_jank_cuj_metric.out b/test/trace_processor/diff_tests/android/android_blocking_calls_on_jank_cuj_metric.out
index 68b3c9f81..89d7c63f7 100644
--- a/test/trace_processor/diff_tests/android/android_blocking_calls_on_jank_cuj_metric.out
+++ b/test/trace_processor/diff_tests/android/android_blocking_calls_on_jank_cuj_metric.out
@@ -15,6 +15,7 @@ android_blocking_calls_cuj_metric {
apk_version_code: 1
debuggable: false
}
+ pid: 1000
}
ts: 0
dur: 115000000
@@ -42,6 +43,7 @@ android_blocking_calls_cuj_metric {
apk_version_code: 1
debuggable: false
}
+ pid: 1000
}
ts: 0
dur: 802000000
diff --git a/test/trace_processor/diff_tests/android/android_monitor_contention.out b/test/trace_processor/diff_tests/android/android_monitor_contention.out
index 02a64123e..163815d7a 100644
--- a/test/trace_processor/diff_tests/android/android_monitor_contention.out
+++ b/test/trace_processor/diff_tests/android/android_monitor_contention.out
@@ -12,7 +12,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "PackageManager"
+ blocked_thread_tid: 693
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -39,7 +42,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -66,7 +72,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -93,7 +102,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -120,7 +132,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1737055785896
@@ -154,7 +169,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "StorageUserConn"
+ blocked_thread_tid: 1759
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -171,7 +189,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "StorageUserConn"
+ blocked_thread_tid: 1759
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -208,7 +229,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -225,7 +249,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -242,7 +269,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -259,7 +289,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -276,7 +309,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -293,7 +329,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -310,7 +349,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -327,7 +369,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -344,7 +389,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -361,7 +409,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -378,7 +429,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -395,7 +449,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -412,7 +469,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -429,7 +489,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -446,7 +509,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -463,7 +529,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -480,7 +549,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -497,7 +569,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -514,7 +589,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -531,7 +609,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -548,7 +629,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -565,7 +649,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -582,7 +669,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -599,7 +689,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -616,7 +709,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -633,7 +729,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -650,7 +749,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -667,7 +769,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -684,7 +789,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -701,7 +809,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -718,7 +829,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -735,7 +849,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -752,7 +869,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -769,7 +889,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -786,7 +909,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -803,7 +929,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -820,7 +949,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -837,7 +969,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -854,7 +989,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -871,7 +1009,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -888,7 +1029,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -905,7 +1049,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -922,7 +1069,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -939,7 +1089,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -956,7 +1109,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -973,7 +1129,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -990,7 +1149,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1007,7 +1169,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1024,7 +1189,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1041,7 +1209,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.display"
+ blocked_thread_tid: 663
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1063,7 +1234,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1090,7 +1264,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1117,7 +1294,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1144,7 +1324,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "binder:642_11"
+ blocked_thread_tid: 2505
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1182,7 +1365,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1210,7 +1396,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1237,7 +1426,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "binder:642_12"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -1269,7 +1461,10 @@ android_monitor_contention {
waiter_count: 2
blocking_thread_name: "binder:642_12"
blocked_thread_name: "binder:642_2"
+ blocked_thread_tid: 658
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1291,7 +1486,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1308,7 +1506,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1325,7 +1526,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1342,7 +1546,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1359,7 +1566,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1376,7 +1586,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1393,7 +1606,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1410,7 +1626,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1427,7 +1646,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1444,7 +1666,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1461,7 +1686,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1478,7 +1706,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1495,7 +1726,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1512,7 +1746,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1529,7 +1766,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1546,7 +1786,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1563,7 +1806,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1580,7 +1826,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_12"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2720
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -1597,7 +1846,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1624,7 +1876,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1651,7 +1906,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1678,7 +1936,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "batterystats-handler"
blocked_thread_name: "binder:642_11"
+ blocked_thread_tid: 2505
+ blocking_thread_tid: 676
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1710,7 +1971,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1737,7 +2001,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1764,7 +2031,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1791,7 +2061,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1818,7 +2091,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1845,7 +2121,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1872,7 +2151,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1899,7 +2181,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1926,7 +2211,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1953,7 +2241,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -1980,7 +2271,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2007,7 +2301,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2034,7 +2331,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2061,7 +2361,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2088,7 +2391,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2115,7 +2421,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2142,7 +2451,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2169,7 +2481,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_11"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 2505
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2196,7 +2511,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "PowerManagerSer"
+ blocked_thread_tid: 687
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2223,7 +2541,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "PowerManagerSer"
+ blocked_thread_tid: 687
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2245,7 +2566,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "binder:642_2"
+ blocked_thread_tid: 658
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
binder_reply_ts: 1737145697570
@@ -2274,7 +2598,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "Thread-45"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 3486
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -2301,7 +2628,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2328,7 +2658,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2355,7 +2688,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "PowerManagerSer"
+ blocked_thread_tid: 687
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2382,7 +2718,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "PowerManagerSer"
+ blocked_thread_tid: 687
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2410,7 +2749,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "binder:642_14"
+ blocked_thread_tid: 3485
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -2442,7 +2784,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -2479,7 +2824,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2496,7 +2844,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2513,7 +2864,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2530,7 +2884,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "binder:642_11"
+ blocked_thread_tid: 2505
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1737164232343
@@ -2549,7 +2906,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2566,7 +2926,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2583,7 +2946,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2600,7 +2966,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2617,7 +2986,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2634,7 +3006,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2651,7 +3026,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2668,7 +3046,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2685,7 +3066,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2702,7 +3086,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2719,7 +3106,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2736,7 +3126,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2753,7 +3146,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2770,7 +3166,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2787,7 +3186,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2804,7 +3206,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2821,7 +3226,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2838,7 +3246,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -2855,7 +3266,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2882,7 +3296,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2909,7 +3326,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2936,7 +3356,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2963,7 +3386,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -2990,7 +3416,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3017,7 +3446,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3044,7 +3476,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3071,7 +3506,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3098,7 +3536,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3125,7 +3566,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3152,7 +3596,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3179,7 +3626,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -3206,7 +3656,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3233,7 +3686,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3260,7 +3716,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3287,7 +3746,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "binder:642_11"
+ blocked_thread_tid: 2505
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1737183173575
@@ -3316,7 +3778,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "binder:642_14"
+ blocked_thread_tid: 3485
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3343,7 +3808,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3370,7 +3838,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3397,7 +3868,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3424,7 +3898,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3451,7 +3928,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3478,7 +3958,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3505,7 +3988,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3532,7 +4018,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3559,7 +4048,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3586,7 +4078,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3613,7 +4108,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3640,7 +4138,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3667,7 +4168,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3694,7 +4198,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3721,7 +4228,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3748,7 +4258,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3775,7 +4288,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3802,7 +4318,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_14"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 3485
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3829,7 +4348,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3856,7 +4378,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3883,7 +4408,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3910,7 +4438,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3947,7 +4478,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -3964,7 +4498,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_2"
+ blocked_thread_tid: 658
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -3986,7 +4523,10 @@ android_monitor_contention {
waiter_count: 2
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_A"
+ blocked_thread_tid: 1675
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4008,7 +4548,10 @@ android_monitor_contention {
waiter_count: 3
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_8"
+ blocked_thread_tid: 1548
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4030,7 +4573,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_F"
blocked_thread_name: "binder:642_1"
+ blocked_thread_tid: 657
+ blocking_thread_tid: 2029
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4062,7 +4608,10 @@ android_monitor_contention {
waiter_count: 4
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_13"
+ blocked_thread_tid: 2721
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4084,7 +4633,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4101,7 +4653,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4118,7 +4673,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4135,7 +4693,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4152,7 +4713,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4169,7 +4733,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4186,7 +4753,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4203,7 +4773,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4220,7 +4793,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4237,7 +4813,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4254,7 +4833,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4271,7 +4853,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4288,7 +4873,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4305,7 +4893,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4322,7 +4913,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4339,7 +4933,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -4356,7 +4953,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4383,7 +4983,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4405,7 +5008,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4432,7 +5038,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_2"
+ blocked_thread_tid: 658
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4459,7 +5068,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_A"
+ blocked_thread_tid: 1675
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4481,7 +5093,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_8"
+ blocked_thread_tid: 1548
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4508,7 +5123,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_13"
+ blocked_thread_tid: 2721
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4530,7 +5148,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_13"
blocked_thread_name: "binder:642_12"
+ blocked_thread_tid: 2720
+ blocking_thread_tid: 2721
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1737229638872
@@ -4564,7 +5185,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_13"
blocked_thread_name: "binder:642_8"
+ blocked_thread_tid: 1548
+ blocking_thread_tid: 2721
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4591,7 +5215,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "binder:642_13"
blocked_thread_name: "binder:642_A"
+ blocked_thread_tid: 1675
+ blocking_thread_tid: 2721
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4628,7 +5255,10 @@ android_monitor_contention {
waiter_count: 2
blocking_thread_name: "binder:642_13"
blocked_thread_name: "binder:642_E"
+ blocked_thread_tid: 1934
+ blocking_thread_tid: 2721
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4650,7 +5280,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_8"
+ blocked_thread_tid: 1548
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4672,7 +5305,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_A"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1675
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4699,7 +5335,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "binder:642_E"
+ blocked_thread_tid: 1934
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4721,7 +5360,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -4743,7 +5385,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4770,7 +5415,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4797,7 +5445,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4824,7 +5475,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4851,7 +5505,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4878,7 +5535,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4905,7 +5565,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4932,7 +5595,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4959,7 +5625,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -4986,7 +5655,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5013,7 +5685,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5040,7 +5715,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5067,7 +5745,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5094,7 +5775,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5121,7 +5805,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5148,7 +5835,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5175,7 +5865,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5212,7 +5905,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
}
@@ -5229,7 +5925,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 672
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5256,7 +5955,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5283,7 +5985,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "tworkPolicy.uid"
+ blocked_thread_tid: 1193
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5310,7 +6015,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5337,7 +6045,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5359,7 +6070,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5386,7 +6100,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5413,7 +6130,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5440,7 +6160,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5467,7 +6190,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5494,7 +6220,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5521,7 +6250,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5548,7 +6280,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5575,7 +6310,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5602,7 +6340,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5629,7 +6370,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5656,7 +6400,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5683,7 +6430,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5710,7 +6460,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5737,7 +6490,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5764,7 +6520,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5791,7 +6550,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5818,7 +6580,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "PackageManager"
+ blocked_thread_tid: 693
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5845,7 +6610,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "tworkPolicy.uid"
+ blocked_thread_tid: 1193
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5872,7 +6640,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5899,7 +6670,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5926,7 +6700,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 670
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -5953,7 +6730,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -5980,7 +6760,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6007,7 +6790,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "android.fg"
+ blocked_thread_tid: 660
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6034,7 +6820,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -6076,7 +6865,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "binder:642_1"
+ blocked_thread_tid: 657
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1739927686578
@@ -6115,7 +6907,10 @@ android_monitor_contention {
waiter_count: 2
blocking_thread_name: "StorageManagerService"
blocked_thread_name: "binder:642_E"
+ blocked_thread_tid: 1934
+ blocking_thread_tid: 743
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1739931677940
@@ -6134,7 +6929,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "binder:642_E"
blocked_thread_name: "StorageManagerS"
+ blocked_thread_tid: 743
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6161,7 +6959,10 @@ android_monitor_contention {
waiter_count: 2
blocking_thread_name: "binder:642_E"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
}
@@ -6178,7 +6979,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "PowerManagerSer"
+ blocked_thread_tid: 687
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6200,7 +7004,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6227,7 +7034,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "PackageManager"
+ blocked_thread_tid: 693
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6254,7 +7064,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6281,7 +7094,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6308,7 +7124,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_1"
+ blocked_thread_tid: 657
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6335,7 +7154,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6352,7 +7174,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6369,7 +7194,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6386,7 +7214,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_13"
+ blocked_thread_tid: 2721
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1739956996641
@@ -6415,7 +7246,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6432,7 +7266,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6449,7 +7286,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6466,7 +7306,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6483,7 +7326,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6500,7 +7346,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6517,7 +7366,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6534,7 +7386,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6551,7 +7406,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6568,7 +7426,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6585,7 +7446,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -6617,7 +7481,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6634,7 +7501,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "batterystats-ha"
+ blocked_thread_tid: 676
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6651,7 +7521,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "PowerManagerSer"
+ blocked_thread_tid: 687
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6668,7 +7541,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "PowerManagerSer"
+ blocked_thread_tid: 687
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -6685,7 +7561,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "fg"
+ blocked_thread_tid: 3516
+ blocking_thread_tid: 3519
process_name: "com.android.providers.media.module"
+ pid: 3487
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6712,7 +7591,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "binder:642_E"
+ blocked_thread_tid: 1934
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
binder_reply_ts: 1739981897430
@@ -6741,7 +7623,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "main"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -6778,7 +7663,10 @@ android_monitor_contention {
waiter_count: 2
blocking_thread_name: "main"
blocked_thread_name: "StorageManagerS"
+ blocked_thread_tid: 743
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -6800,7 +7688,10 @@ android_monitor_contention {
waiter_count: 3
blocking_thread_name: "main"
blocked_thread_name: "binder:642_13"
+ blocked_thread_tid: 2721
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
binder_reply_ts: 1739982622780
@@ -6819,7 +7710,10 @@ android_monitor_contention {
waiter_count: 3
blocking_thread_name: "binder:642_E"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -6841,7 +7735,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "fg"
+ blocked_thread_tid: 3516
+ blocking_thread_tid: 3487
process_name: "com.android.providers.media.module"
+ pid: 3487
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -6868,7 +7765,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "fg"
+ blocked_thread_tid: 3516
+ blocking_thread_tid: 3519
process_name: "com.android.providers.media.module"
+ pid: 3487
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6895,7 +7795,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_13"
blocked_thread_name: "system_server"
+ blocked_thread_tid: 642
+ blocking_thread_tid: 2721
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -6922,7 +7825,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "fg"
+ blocked_thread_tid: 3516
+ blocking_thread_tid: 3487
process_name: "com.android.providers.media.module"
+ pid: 3487
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -6949,7 +7855,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "fg"
+ blocked_thread_tid: 3516
+ blocking_thread_tid: 3519
process_name: "com.android.providers.media.module"
+ pid: 3487
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -6976,7 +7885,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "binder:642_1"
+ blocked_thread_tid: 657
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
binder_reply_ts: 1740012085111
@@ -7010,7 +7922,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.bg"
blocked_thread_name: "fg"
+ blocked_thread_tid: 3516
+ blocking_thread_tid: 3519
process_name: "com.android.providers.media.module"
+ pid: 3487
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7037,7 +7952,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "binder:642_13"
+ blocked_thread_tid: 2721
+ blocking_thread_tid: 642
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: true
binder_reply_ts: 1740024094690
@@ -7066,7 +7984,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "StorageManagerS"
+ blocked_thread_tid: 743
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7098,7 +8019,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -7115,7 +8039,10 @@ android_monitor_contention {
waiter_count: 1
blocking_thread_name: "binder:642_E"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7137,7 +8064,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -7154,7 +8084,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -7171,7 +8104,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_E"
blocked_thread_name: "tworkPolicy.uid"
+ blocked_thread_tid: 1193
+ blocking_thread_tid: 1934
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
}
@@ -7188,7 +8124,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "fg"
+ blocked_thread_tid: 3516
+ blocking_thread_tid: 3487
process_name: "com.android.providers.media.module"
+ pid: 3487
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -7215,7 +8154,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7242,7 +8184,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7269,7 +8214,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7296,7 +8244,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7323,7 +8274,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7350,7 +8304,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7377,7 +8334,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7404,7 +8364,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7431,7 +8394,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7458,7 +8424,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7485,7 +8454,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7512,7 +8484,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7539,7 +8514,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7566,7 +8544,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7593,7 +8574,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7620,7 +8604,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7647,7 +8634,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7674,7 +8664,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7701,7 +8694,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7728,7 +8724,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7755,7 +8754,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7782,7 +8784,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7809,7 +8814,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7836,7 +8844,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7863,7 +8874,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7890,7 +8904,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7917,7 +8934,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7944,7 +8964,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_1"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 657
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -7971,7 +8994,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -7998,7 +9024,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8025,7 +9054,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8052,7 +9084,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8079,7 +9114,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8106,7 +9144,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8133,7 +9174,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8160,7 +9204,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8187,7 +9234,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8214,7 +9264,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "android.ui"
blocked_thread_name: "android.bg"
+ blocked_thread_tid: 670
+ blocking_thread_tid: 661
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8246,7 +9299,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8273,7 +9329,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "ActivityManager"
+ blocked_thread_tid: 671
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8300,7 +9359,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8327,7 +9389,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8354,7 +9419,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8381,7 +9449,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8408,7 +9479,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8435,7 +9509,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8462,7 +9539,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8489,7 +9569,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8516,7 +9599,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8543,7 +9629,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8570,7 +9659,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8597,7 +9689,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8624,7 +9719,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8651,7 +9749,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8678,7 +9779,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8705,7 +9809,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8732,7 +9839,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8759,7 +9869,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "binder:642_8"
blocked_thread_name: "android.ui"
+ blocked_thread_tid: 661
+ blocking_thread_tid: 1548
process_name: "system_server"
+ pid: 642
is_blocked_thread_main: false
is_blocking_thread_main: false
thread_states {
@@ -8786,7 +9899,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8813,7 +9929,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8840,7 +9959,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "sAsyncHandlerThread"
blocked_thread_name: "d.process.media"
+ blocked_thread_tid: 2003
+ blocking_thread_tid: 2128
process_name: "android.process.media"
+ pid: 2003
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8867,7 +9989,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "SysUiBg"
blocked_thread_name: "ndroid.systemui"
+ blocked_thread_tid: 1253
+ blocking_thread_tid: 1331
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8894,7 +10019,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "SysUiBg"
blocked_thread_name: "ndroid.systemui"
+ blocked_thread_tid: 1253
+ blocking_thread_tid: 1331
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8921,7 +10049,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "SysUiBg"
blocked_thread_name: "ndroid.systemui"
+ blocked_thread_tid: 1253
+ blocking_thread_tid: 1331
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8948,7 +10079,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "SysUiBg"
blocked_thread_name: "ndroid.systemui"
+ blocked_thread_tid: 1253
+ blocking_thread_tid: 1331
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -8975,7 +10109,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "SysUiBg"
blocked_thread_name: "ndroid.systemui"
+ blocked_thread_tid: 1253
+ blocking_thread_tid: 1331
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: true
is_blocking_thread_main: false
thread_states {
@@ -9002,7 +10139,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "SysUiBg"
+ blocked_thread_tid: 1331
+ blocking_thread_tid: 1253
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -9024,7 +10164,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "plugin"
+ blocked_thread_tid: 1341
+ blocking_thread_tid: 1253
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
@@ -9051,7 +10194,10 @@ android_monitor_contention {
waiter_count: 0
blocking_thread_name: "main"
blocked_thread_name: "RenderThread"
+ blocked_thread_tid: 1436
+ blocking_thread_tid: 1253
process_name: "com.android.systemui"
+ pid: 1253
is_blocked_thread_main: false
is_blocking_thread_main: true
thread_states {
diff --git a/test/trace_processor/diff_tests/android/android_network_activity.out b/test/trace_processor/diff_tests/android/android_network_activity.out
new file mode 100644
index 000000000..14418e4cd
--- /dev/null
+++ b/test/trace_processor/diff_tests/android/android_network_activity.out
@@ -0,0 +1,4 @@
+"package_name","ts","dur","packet_count","packet_length"
+"uid=123",1000,1010,2,100
+"uid=123",3000,2500,4,200
+"uid=456",1005,1010,2,300
diff --git a/test/trace_processor/diff_tests/android/android_system_property_slice.out b/test/trace_processor/diff_tests/android/android_system_property_slice.out
index 8fe8d0782..2505d36d8 100644
--- a/test/trace_processor/diff_tests/android/android_system_property_slice.out
+++ b/test/trace_processor/diff_tests/android/android_system_property_slice.out
@@ -1,3 +1,3 @@
-"id","type","name","id","ts","dur","type","name"
-1,"track","DeviceStateChanged",0,1000,0,"internal_slice","some_state_from_sysprops"
-1,"track","DeviceStateChanged",1,3000,0,"internal_slice","some_state_from_atrace"
+"type","name","id","ts","dur","type","name"
+"track","DeviceStateChanged",0,1000,0,"internal_slice","some_state_from_sysprops"
+"track","DeviceStateChanged",1,3000,0,"internal_slice","some_state_from_atrace"
diff --git a/test/trace_processor/diff_tests/android/tests.py b/test/trace_processor/diff_tests/android/tests.py
index b808d1b36..84bafc1d1 100644
--- a/test/trace_processor/diff_tests/android/tests.py
+++ b/test/trace_processor/diff_tests/android/tests.py
@@ -58,14 +58,14 @@ class Android(TestSuite):
}
"""),
query="""
- SELECT t.id, t.type, t.name, c.id, c.ts, c.type, c.value
+ SELECT t.type, t.name, c.id, c.ts, c.type, c.value
FROM counter_track t JOIN counter c ON t.id = c.track_id
WHERE name = 'ScreenState';
""",
out=Csv("""
- "id","type","name","id","ts","type","value"
- 0,"counter_track","ScreenState",0,1000,"counter",2.000000
- 0,"counter_track","ScreenState",1,2000,"counter",1.000000
+ "type","name","id","ts","type","value"
+ "counter_track","ScreenState",0,1000,"counter",2.000000
+ "counter_track","ScreenState",1,2000,"counter",1.000000
"""))
def test_android_system_property_slice(self):
@@ -105,12 +105,163 @@ class Android(TestSuite):
}
"""),
query="""
- SELECT t.id, t.type, t.name, s.id, s.ts, s.dur, s.type, s.name
+ SELECT t.type, t.name, s.id, s.ts, s.dur, s.type, s.name
FROM track t JOIN slice s ON s.track_id = t.id
WHERE t.name = 'DeviceStateChanged';
""",
out=Path('android_system_property_slice.out'))
+ def test_android_battery_stats_event_slices(self):
+ # The following has three events
+ # * top (123, mail) from 1000 to 9000 explicit
+ # * job (456, mail_job) starting at 3000 (end is inferred as trace end)
+ # * job (789, video_job) ending at 4000 (start is inferred as trace start)
+ return DiffTestBlueprint(
+ trace=TextProto(r"""
+ packet {
+ ftrace_events {
+ cpu: 1
+ event {
+ timestamp: 1000
+ pid: 1
+ print {
+ buf: "N|1000|battery_stats.top|+top=123:\"mail\"\n"
+ }
+ }
+ event {
+ timestamp: 3000
+ pid: 1
+ print {
+ buf: "N|1000|battery_stats.job|+job=456:\"mail_job\"\n"
+ }
+ }
+ event {
+ timestamp: 4000
+ pid: 1
+ print {
+ buf: "N|1000|battery_stats.job|-job=789:\"video_job\"\n"
+ }
+ }
+ event {
+ timestamp: 9000
+ pid: 1
+ print {
+ buf: "N|1000|battery_stats.top|-top=123:\"mail\"\n"
+ }
+ }
+ }
+ }
+ """),
+ query="""
+ SELECT IMPORT('android.battery_stats');
+ SELECT * FROM android_battery_stats_event_slices
+ ORDER BY str_value;
+ """,
+ out=Path('android_battery_stats_event_slices.out'))
+
+ def test_android_battery_stats_counters(self):
+ return DiffTestBlueprint(
+ trace=TextProto(r"""
+ packet {
+ ftrace_events {
+ cpu: 1
+ event {
+ timestamp: 1000
+ pid: 1
+ print {
+ buf: "C|1000|battery_stats.data_conn|13\n"
+ }
+ }
+ event {
+ timestamp: 4000
+ pid: 1
+ print {
+ buf: "C|1000|battery_stats.data_conn|20\n"
+ }
+ }
+ event {
+ timestamp: 1000
+ pid: 1
+ print {
+ buf: "C|1000|battery_stats.audio|1\n"
+ }
+ }
+ }
+ }
+ """),
+ query="""
+ SELECT IMPORT('android.battery_stats');
+ SELECT * FROM android_battery_stats_state
+ ORDER BY ts, track_name;
+ """,
+ out=Path('android_battery_stats_state.out'))
+
+ def test_android_network_activity(self):
+ # The following should have three activity regions:
+ # * uid=123 from 1000 to 2010 (note: end is max(ts)+idle_ns)
+ # * uid=456 from 1005 to 2015 (note: doesn't group with above due to name)
+ # * uid=123 from 3000 to 5500 (note: gap between 1010 to 3000 > idle_ns)
+ # Note: packet_timestamps are delta encoded from the base timestamp.
+ return DiffTestBlueprint(
+ trace=TextProto(r"""
+ packet {
+ timestamp: 0
+ network_packet_bundle {
+ ctx {
+ direction: DIR_EGRESS
+ interface: "wlan"
+ uid: 123
+ }
+ packet_timestamps: [
+ 1000, 1010,
+ 3000, 3050, 4000, 4500
+ ],
+ packet_lengths: [
+ 50, 50,
+ 50, 50, 50, 50
+ ],
+ }
+ }
+ packet {
+ timestamp: 0
+ network_packet_bundle {
+ ctx {
+ direction: DIR_EGRESS
+ interface: "wlan"
+ uid: 456
+ }
+ packet_timestamps: [1005, 1015]
+ packet_lengths: [100, 200]
+ }
+ }
+ packet {
+ timestamp: 0
+ network_packet_bundle {
+ ctx {
+ direction: DIR_INGRESS
+ interface: "loopback"
+ uid: 123
+ }
+ packet_timestamps: [6000]
+ packet_lengths: [100]
+ }
+ }
+ """),
+ query="""
+ SELECT RUN_METRIC(
+ 'android/network_activity_template.sql',
+ 'view_name', 'android_network_activity',
+ 'group_by', 'package_name',
+ 'filter', 'iface = "wlan"',
+ 'idle_ns', '1000',
+ 'quant_ns', '100'
+ );
+
+ SELECT * FROM android_network_activity
+ ORDER BY package_name, ts;
+ """,
+ out=Path('android_network_activity.out'))
+
def test_binder_sync_binder_metrics(self):
return DiffTestBlueprint(
trace=DataPath('android_binder_metric_trace.atr'),
@@ -236,15 +387,18 @@ class Android(TestSuite):
query="""
SELECT IMPORT('android.monitor_contention');
SELECT
- *
+ blocking_method,
+ blocked_method,
+ short_blocking_method,
+ short_blocked_method
FROM android_monitor_contention
WHERE binder_reply_id IS NOT NULL
ORDER BY dur DESC
LIMIT 1;
""",
out=Csv("""
- "blocking_method","blocked_method","short_blocking_method","short_blocked_method","blocking_src","blocked_src","waiter_count","blocked_utid","blocked_thread_name","blocking_utid","blocking_thread_name","blocking_tid","upid","process_name","id","ts","dur","track_id","is_blocked_thread_main","is_blocking_thread_main","binder_reply_id","binder_reply_ts","binder_reply_tid"
- "boolean com.android.server.am.ActivityManagerService.forceStopPackageLocked(java.lang.String, int, boolean, boolean, boolean, boolean, boolean, int, java.lang.String)","boolean com.android.server.am.ActivityManagerService.isUidActive(int, java.lang.String)","com.android.server.am.ActivityManagerService.forceStopPackageLocked","com.android.server.am.ActivityManagerService.isUidActive","ActivityManagerService.java:4484","ActivityManagerService.java:7325",0,656,"binder:642_12",495,"binder:642_1",657,250,"system_server",291,1737056375519,37555955,1235,0,0,285,1737055785896,2720
+ "blocking_method","blocked_method","short_blocking_method","short_blocked_method"
+ "boolean com.android.server.am.ActivityManagerService.forceStopPackageLocked(java.lang.String, int, boolean, boolean, boolean, boolean, boolean, int, java.lang.String)","boolean com.android.server.am.ActivityManagerService.isUidActive(int, java.lang.String)","com.android.server.am.ActivityManagerService.forceStopPackageLocked","com.android.server.am.ActivityManagerService.isUidActive"
"""))
def test_monitor_contention_chain_blocked_functions(self):
@@ -305,7 +459,6 @@ class Android(TestSuite):
id,
ts,
dur,
- track_id,
is_blocked_thread_main,
is_blocking_thread_main,
IIF(binder_reply_id IS NULL, "", binder_reply_id) AS binder_reply_id,
@@ -316,8 +469,8 @@ class Android(TestSuite):
LIMIT 1;
""",
out=Csv("""
- "parent_id","blocking_method","blocked_method","short_blocking_method","short_blocked_method","blocking_src","blocked_src","waiter_count","blocked_utid","blocked_thread_name","blocking_utid","blocking_thread_name","upid","process_name","id","ts","dur","track_id","is_blocked_thread_main","is_blocking_thread_main","binder_reply_id","binder_reply_ts","binder_reply_tid"
- "","void com.android.server.am.ActivityManagerService.forceStopPackage(java.lang.String, int)","boolean com.android.server.am.ActivityManagerService.unbindService(android.app.IServiceConnection)","com.android.server.am.ActivityManagerService.forceStopPackage","com.android.server.am.ActivityManagerService.unbindService","ActivityManagerService.java:3992","ActivityManagerService.java:12719",0,640,"StorageUserConn",495,"binder:642_1",250,"system_server",327,1737063410007,46114664,1238,0,0,"","",""
+ "parent_id","blocking_method","blocked_method","short_blocking_method","short_blocked_method","blocking_src","blocked_src","waiter_count","blocked_utid","blocked_thread_name","blocking_utid","blocking_thread_name","upid","process_name","id","ts","dur","is_blocked_thread_main","is_blocking_thread_main","binder_reply_id","binder_reply_ts","binder_reply_tid"
+ "","void com.android.server.am.ActivityManagerService.forceStopPackage(java.lang.String, int)","boolean com.android.server.am.ActivityManagerService.unbindService(android.app.IServiceConnection)","com.android.server.am.ActivityManagerService.forceStopPackage","com.android.server.am.ActivityManagerService.unbindService","ActivityManagerService.java:3992","ActivityManagerService.java:12719",0,640,"StorageUserConn",495,"binder:642_1",250,"system_server",327,1737063410007,46114664,0,0,"","",""
"""))
def test_monitor_contention_metric(self):
diff --git a/test/trace_processor/diff_tests/android/tests_general.py b/test/trace_processor/diff_tests/android/tests_general.py
deleted file mode 100644
index fd555a58f..000000000
--- a/test/trace_processor/diff_tests/android/tests_general.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License a
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from python.generators.diff_tests.testing import Path, DataPath, Metric
-from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
-from python.generators.diff_tests.testing import DiffTestModule
-
-
-class AndroidGeneral(DiffTestModule):
-
- def test_game_intervention_list(self):
- return DiffTestBlueprint(
- trace=Path('game_intervention_list_test.textproto'),
- query="""
-SELECT
- package_name,
- uid,
- current_mode,
- standard_mode_supported,
- standard_mode_downscale,
- standard_mode_use_angle,
- standard_mode_fps,
- perf_mode_supported,
- perf_mode_downscale,
- perf_mode_use_angle,
- perf_mode_fps,
- battery_mode_supported,
- battery_mode_downscale,
- battery_mode_use_angle,
- battery_mode_fps
-FROM android_game_intervention_list
-ORDER BY package_name;
-""",
- out=Path('game_intervention_list_test.out'))
-
- def test_android_system_property_counter(self):
- return DiffTestBlueprint(
- trace=Path('android_system_property.textproto'),
- query="""
-SELECT t.id, t.type, t.name, c.id, c.ts, c.type, c.value
-FROM counter_track t JOIN counter c ON t.id = c.track_id
-WHERE name = 'ScreenState';
-""",
- out=Csv("""
-"id","type","name","id","ts","type","value"
-0,"counter_track","ScreenState",0,1000,"counter",2.000000
-0,"counter_track","ScreenState",1,2000,"counter",1.000000
-"""))
-
- def test_android_system_property_slice(self):
- return DiffTestBlueprint(
- trace=Path('android_system_property.textproto'),
- query="""
-SELECT t.id, t.type, t.name, s.id, s.ts, s.dur, s.type, s.name
-FROM track t JOIN slice s ON s.track_id = t.id
-WHERE t.name = 'DeviceStateChanged';
-""",
- out=Path('android_system_property_slice.out'))
diff --git a/test/trace_processor/diff_tests/chrome/chrome_scroll_check.py b/test/trace_processor/diff_tests/chrome/chrome_scroll_check.py
new file mode 100644
index 000000000..4c51da444
--- /dev/null
+++ b/test/trace_processor/diff_tests/chrome/chrome_scroll_check.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Discarded events that do not get to GPU are invisible for UMA metric and
+# therefore should be excluded in trace-based metric. This tests ensures that's
+# the case.
+
+from os import sys
+
+import synth_common
+
+from synth_common import ms_to_ns
+trace = synth_common.create_trace()
+
+from chrome_scroll_helper import ChromeScrollHelper
+
+helper = ChromeScrollHelper(trace, start_id=1234, start_gesture_id=5678)
+
+# First scroll
+helper.begin(from_ms=0, dur_ms=10)
+helper.update(from_ms=15, dur_ms=10)
+helper.update(from_ms=30, dur_ms=10)
+helper.end(from_ms=45, dur_ms=10)
+
+# Second scroll
+helper.begin(from_ms=60, dur_ms=10)
+helper.update(from_ms=75, dur_ms=10)
+helper.end(from_ms=90, dur_ms=10)
+
+# Third scroll, won't have a GestureScrollEnd value.
+helper.begin(from_ms=120, dur_ms=10)
+helper.update(from_ms=135, dur_ms=10)
+helper.update(from_ms=150, dur_ms=10)
+helper.update(from_ms=150, dur_ms=10)
+helper.update(from_ms=180, dur_ms=10)
+
+sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/test/trace_processor/diff_tests/chrome/chrome_scroll_helper.py b/test/trace_processor/diff_tests/chrome/chrome_scroll_helper.py
new file mode 100644
index 000000000..7b7cee113
--- /dev/null
+++ b/test/trace_processor/diff_tests/chrome/chrome_scroll_helper.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Discarded events that do not get to GPU are invisible for UMA metric and
+# therefore should be excluded in trace-based metric. This tests ensures that's
+# the case.
+
+import synth_common
+
+from synth_common import ms_to_ns
+trace = synth_common.create_trace()
+
+
+class ChromeScrollHelper:
+
+ def __init__(self, trace, start_id, start_gesture_id):
+ self.trace = trace
+ self.id = start_id
+ self.gesture_id = start_gesture_id
+
+ def begin(self, from_ms, dur_ms):
+ self.trace.add_input_latency_event_slice(
+ "GestureScrollBegin",
+ ts=ms_to_ns(from_ms),
+ dur=ms_to_ns(dur_ms),
+ track=self.id,
+ trace_id=self.id,
+ gesture_scroll_id=self.gesture_id,
+ )
+ self.id += 1
+
+ def update(self, from_ms, dur_ms, gets_to_gpu=True):
+ self.trace.add_input_latency_event_slice(
+ "GestureScrollUpdate",
+ ts=ms_to_ns(from_ms),
+ dur=ms_to_ns(dur_ms),
+ track=self.id,
+ trace_id=self.id,
+ gesture_scroll_id=self.gesture_id,
+ gets_to_gpu=gets_to_gpu,
+ is_coalesced=False,
+ )
+ self.id += 1
+
+ def end(self, from_ms, dur_ms):
+ self.trace.add_input_latency_event_slice(
+ "GestureScrollEnd",
+ ts=ms_to_ns(from_ms),
+ dur=ms_to_ns(dur_ms),
+ track=self.id,
+ trace_id=self.id,
+ gesture_scroll_id=self.gesture_id)
+ self.id += 1
+ self.gesture_id += 1
diff --git a/test/trace_processor/diff_tests/chrome/chrome_tasks.out b/test/trace_processor/diff_tests/chrome/chrome_tasks.out
index ef3383735..7ca510e92 100644
--- a/test/trace_processor/diff_tests/chrome/chrome_tasks.out
+++ b/test/trace_processor/diff_tests/chrome/chrome_tasks.out
@@ -16,7 +16,6 @@
"sendTouchEvent","java",194
"viz.mojom.CompositorFrameSinkClient message (hash=3114070324)","mojo",178
"viz.mojom.CompositorFrameSink message (hash=3089589715)","mojo",170
-"RunTask(posted_from=mojo/public/cpp/system/simple_watcher.cc:ArmOrNotify)","scheduler",158
"RunTask(posted_from=cc/scheduler/scheduler.cc:ScheduleBeginImplFrameDeadline)","scheduler",149
"RunTask(posted_from=net/quic/quic_chromium_alarm_factory.cc:SetImpl)","scheduler",135
"RunTask(posted_from=mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:SendMessage)","scheduler",114
@@ -25,6 +24,7 @@
"blink.mojom.WidgetInputHandler reply (hash=3392143105)","mojo",97
"tracing.mojom.ProducerHost message (hash=3013694824)","mojo",82
"RunTask(posted_from=net/disk_cache/simple/simple_entry_impl.cc:WriteDataInternal)","scheduler",81
+"RunTask(posted_from=mojo/public/cpp/system/simple_watcher.cc:ArmOrNotify)","mojo",74
"RunTask(posted_from=net/disk_cache/simple/simple_entry_impl.cc:CloseInternal)","scheduler",73
"RunTask(posted_from=base/android/task_scheduler/task_runner_android.cc:PostDelayedTask)","scheduler",63
"RunTask(posted_from=base/android/application_status_listener.cc:NotifyApplicationStateChange)","scheduler",54
@@ -37,16 +37,16 @@
"RunTask(posted_from=cc/trees/proxy_impl.cc:ScheduledActionSendBeginMainFrame)","scheduler",47
"RunTask(posted_from=cc/trees/proxy_main.cc:BeginMainFrame)","scheduler",47
"network.mojom.URLLoaderClient message (hash=374770486)","mojo",46
+"network.mojom.URLLoaderFactory message (hash=2397174083)","mojo",46
"viz.mojom.CompositorFrameSink message (hash=1654984935)","mojo",46
"RunTask(posted_from=components/update_client/component.cc:ChangeState)","scheduler",45
-"network.mojom.URLLoaderFactory message (hash=2397174083)","mojo",45
"Choreographer(java_views=OmniboxSuggestionsList)","choreographer",44
"RunTask(posted_from=net/disk_cache/simple/simple_entry_impl.cc:CreateEntryInternal)","scheduler",44
"network.mojom.ProxyConfigPollerClient message (hash=2347231843)","mojo",43
"blink.mojom.AssociatedInterfaceProvider message (hash=2648115757)","mojo",37
+"network.mojom.URLLoaderClient message (hash=3734484340)","mojo",35
"network.mojom.URLLoaderNetworkServiceObserver message (hash=3598259070)","mojo",35
"Looper.dispatch: com.android.internal.view.IInputConnectionWrapper$MyHandler(null)","other",34
"RunTask(posted_from=net/disk_cache/simple/simple_entry_impl.cc:OpenOrCreateEntryInternal)","scheduler",34
-"network.mojom.URLLoaderClient message (hash=3734484340)","mojo",34
+"network.mojom.URLLoaderClient message (hash=2503424824)","mojo",32
"RunTask(posted_from=components/update_client/component.cc:TransitionState)","scheduler",31
-"RunTask(posted_from=net/http/http_stream_factory_job.cc:RunLoop)","scheduler",31
diff --git a/test/trace_processor/diff_tests/chrome/scroll_jank_gpu_check.py b/test/trace_processor/diff_tests/chrome/scroll_jank_gpu_check.py
index 7e33ac21e..c9ba45ca4 100644
--- a/test/trace_processor/diff_tests/chrome/scroll_jank_gpu_check.py
+++ b/test/trace_processor/diff_tests/chrome/scroll_jank_gpu_check.py
@@ -24,51 +24,9 @@ import synth_common
from synth_common import ms_to_ns
trace = synth_common.create_trace()
+from chrome_scroll_helper import ChromeScrollHelper
-class Helper:
-
- def __init__(self, trace, start_id, start_gesture_id):
- self.trace = trace
- self.id = start_id
- self.gesture_id = start_gesture_id
-
- def begin(self, from_ms, dur_ms):
- self.trace.add_input_latency_event_slice(
- "GestureScrollBegin",
- ts=ms_to_ns(from_ms),
- dur=ms_to_ns(dur_ms),
- track=self.id,
- trace_id=self.id,
- gesture_scroll_id=self.gesture_id,
- )
- self.id += 1
-
- def update(self, from_ms, dur_ms, gets_to_gpu=True):
- self.trace.add_input_latency_event_slice(
- "GestureScrollUpdate",
- ts=ms_to_ns(from_ms),
- dur=ms_to_ns(dur_ms),
- track=self.id,
- trace_id=self.id,
- gesture_scroll_id=self.gesture_id,
- gets_to_gpu=gets_to_gpu,
- is_coalesced=False,
- )
- self.id += 1
-
- def end(self, from_ms, dur_ms):
- self.trace.add_input_latency_event_slice(
- "GestureScrollEnd",
- ts=ms_to_ns(from_ms),
- dur=ms_to_ns(dur_ms),
- track=self.id,
- trace_id=self.id,
- gesture_scroll_id=self.gesture_id)
- self.id += 1
- self.gesture_id += 1
-
-
-helper = Helper(trace, start_id=1234, start_gesture_id=5678)
+helper = ChromeScrollHelper(trace, start_id=1234, start_gesture_id=5678)
helper.begin(from_ms=0, dur_ms=10)
helper.update(from_ms=15, dur_ms=10)
diff --git a/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py b/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
index c5fd3bcb8..62833c226 100644
--- a/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
+++ b/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
@@ -518,3 +518,25 @@ class ChromeScrollJank(TestSuite):
30000000,1
115000000,0
"""))
+
+ def test_chrome_scrolls(self):
+ return DiffTestBlueprint(
+ trace=Path('chrome_scroll_check.py'),
+ query="""
+ SELECT IMPORT('chrome.chrome_scrolls');
+
+ SELECT
+ id,
+ ts,
+ dur,
+ scroll_start_ts,
+ scroll_end_ts
+ FROM chrome_scrolls
+ ORDER by id;
+ """,
+ out=Csv("""
+ "id","ts","dur","scroll_start_ts","scroll_end_ts"
+ 5678,0,55000000,0,45000000
+ 5679,60000000,40000000,60000000,90000000
+ 5680,120000000,70000000,120000000,-1
+ """))
diff --git a/test/trace_processor/diff_tests/fuchsia/tests.py b/test/trace_processor/diff_tests/fuchsia/tests.py
index 54d0773b9..d7b8b4d0d 100644
--- a/test/trace_processor/diff_tests/fuchsia/tests.py
+++ b/test/trace_processor/diff_tests/fuchsia/tests.py
@@ -231,3 +231,27 @@ class Fuchsia(TestSuite):
"Update time(ms)",21
"Vsync interval",900
"""))
+
+ def test_fuchsia_args_import(self):
+ return DiffTestBlueprint(
+ trace=DataPath('fuchsia_events_and_args.fxt'),
+ query="""
+ SELECT key,int_value,string_value,real_value,value_type,display_value
+ FROM args
+ LIMIT 12;
+ """,
+ out=Csv("""
+ "key","int_value","string_value","real_value","value_type","display_value"
+ "SomeNullArg","[NULL]","null","[NULL]","string","null"
+ "Someuint32",2145,"[NULL]","[NULL]","int","2145"
+ "Someuint64",423621626134123415,"[NULL]","[NULL]","int","423621626134123415"
+ "Someint32",-7,"[NULL]","[NULL]","int","-7"
+ "Someint64",-234516543631231,"[NULL]","[NULL]","int","-234516543631231"
+ "Somedouble","[NULL]","[NULL]",3.141500,"real","3.1415"
+ "ping","[NULL]","pong","[NULL]","string","pong"
+ "somepointer",3285933758964,"[NULL]","[NULL]","pointer","0x2fd10ea19f4"
+ "someotherpointer",43981,"[NULL]","[NULL]","pointer","0xabcd"
+ "somekoid",18,"[NULL]","[NULL]","int","18"
+ "somebool",1,"[NULL]","[NULL]","bool","true"
+ "someotherbool",0,"[NULL]","[NULL]","bool","false"
+ """))
diff --git a/test/trace_processor/diff_tests/graphics/android_jank_cuj.out b/test/trace_processor/diff_tests/graphics/android_jank_cuj.out
index 41cf687d4..22045da50 100644
--- a/test/trace_processor/diff_tests/graphics/android_jank_cuj.out
+++ b/test/trace_processor/diff_tests/graphics/android_jank_cuj.out
@@ -16,6 +16,7 @@ android_jank_cuj {
apk_version_code: 1
debuggable: false
}
+ pid: 1000
}
ts: 0
dur: 123000000
@@ -27,6 +28,8 @@ android_jank_cuj {
app_missed: false
sf_missed: false
dur_expected: 16000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 2
@@ -36,6 +39,8 @@ android_jank_cuj {
app_missed: true
sf_missed: true
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 3
@@ -45,6 +50,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 4
@@ -54,6 +61,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 5
@@ -63,6 +72,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 6
@@ -72,6 +83,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
sf_frame {
frame_number: 1
@@ -127,6 +140,8 @@ android_jank_cuj {
missed_app_frames: 5
missed_sf_frames: 1
frame_dur_max: 40000000
+ sf_callback_missed_frames: 0
+ hwui_callback_missed_frames: 0
}
timeline_metrics {
total_frames: 6
@@ -143,6 +158,8 @@ android_jank_cuj {
frame_dur_ms_p90: 34.0
frame_dur_ms_p95: 37.0
frame_dur_ms_p99: 39.400000000000006
+ sf_callback_missed_frames: 0
+ hwui_callback_missed_frames: 0
}
trace_metrics {
total_frames: 6
@@ -159,6 +176,8 @@ android_jank_cuj {
frame_dur_ms_p90: 34.0
frame_dur_ms_p95: 37.0
frame_dur_ms_p99: 39.400000000000006
+ sf_callback_missed_frames: 0
+ hwui_callback_missed_frames: 0
}
}
cuj {
@@ -178,6 +197,7 @@ android_jank_cuj {
apk_version_code: 1
debuggable: false
}
+ pid: 1000
}
ts: 0
dur: 901000010
@@ -189,6 +209,8 @@ android_jank_cuj {
app_missed: false
sf_missed: false
dur_expected: 16000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 2
@@ -198,6 +220,8 @@ android_jank_cuj {
app_missed: true
sf_missed: true
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 3
@@ -207,6 +231,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 4
@@ -216,6 +242,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 5
@@ -225,6 +253,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 6
@@ -234,6 +264,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 7
@@ -243,6 +275,8 @@ android_jank_cuj {
app_missed: false
sf_missed: true
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 8
@@ -252,6 +286,8 @@ android_jank_cuj {
app_missed: false
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 9
@@ -261,6 +297,8 @@ android_jank_cuj {
app_missed: false
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 10
@@ -270,6 +308,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 11
@@ -279,6 +319,8 @@ android_jank_cuj {
app_missed: true
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 12
@@ -288,6 +330,8 @@ android_jank_cuj {
app_missed: false
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: false
+ hwui_callback_missed: false
}
frame {
frame_number: 13
@@ -297,6 +341,8 @@ android_jank_cuj {
app_missed: false
sf_missed: false
dur_expected: 20000000
+ sf_callback_missed: true
+ hwui_callback_missed: true
}
sf_frame {
frame_number: 1
@@ -361,6 +407,8 @@ android_jank_cuj {
missed_sf_frames: 2
missed_frames_max_successive: 5
frame_dur_max: 62000000
+ sf_callback_missed_frames: 1
+ hwui_callback_missed_frames: 1
}
timeline_metrics {
total_frames: 13
@@ -377,6 +425,8 @@ android_jank_cuj {
frame_dur_ms_p90: 56.80000000000001
frame_dur_ms_p95: 61.000000
frame_dur_ms_p99: 61.000000
+ sf_callback_missed_frames: 1
+ hwui_callback_missed_frames: 1
}
trace_metrics {
total_frames: 13
@@ -393,6 +443,8 @@ android_jank_cuj {
frame_dur_ms_p90: 60.000000
frame_dur_ms_p95: 61.000000
frame_dur_ms_p99: 61.000000
+ sf_callback_missed_frames: 1
+ hwui_callback_missed_frames: 1
}
}
}
diff --git a/test/trace_processor/diff_tests/graphics/android_jank_cuj.py b/test/trace_processor/diff_tests/graphics/android_jank_cuj.py
index 830d6ac46..beb39f72b 100644
--- a/test/trace_processor/diff_tests/graphics/android_jank_cuj.py
+++ b/test/trace_processor/diff_tests/graphics/android_jank_cuj.py
@@ -227,6 +227,17 @@ trace.add_track_event_slice_begin(ts=10, track=SHADE_CUJ_TRACK,
name="J<SHADE_ROW_EXPAND>")
trace.add_track_event_slice_end(ts=901_000_010, track=SHADE_CUJ_TRACK)
add_instant_for_track(trace, ts=11, track=SHADE_CUJ_TRACK, name="FT#layerId#0")
+add_instant_for_track(
+ trace,
+ ts=950_100_000,
+ track=SHADE_CUJ_TRACK,
+ name="FT#MissedHWUICallback#150")
+add_instant_for_track(
+ trace,
+ ts=950_100_000,
+ track=SHADE_CUJ_TRACK,
+ name="FT#MissedSFCallback#150")
+
trace.add_track_event_slice_begin(
ts=100_100_000, track=CANCELED_CUJ_TRACK, name="J<CANCELED>")
trace.add_track_event_slice_end(ts=999_000_000, track=CANCELED_CUJ_TRACK)
diff --git a/test/trace_processor/diff_tests/graphics/frame_missed.py b/test/trace_processor/diff_tests/graphics/frame_missed.py
index d08191d68..04469b7d4 100644
--- a/test/trace_processor/diff_tests/graphics/frame_missed.py
+++ b/test/trace_processor/diff_tests/graphics/frame_missed.py
@@ -28,12 +28,12 @@ trace.add_process(11, 10, "child_process")
trace.add_ftrace_packet(1)
-trace.add_print(ts=99, tid=11, buf='C|10|PrevFrameMissed|0')
-trace.add_print(ts=100, tid=11, buf='C|10|PrevFrameMissed|0')
-trace.add_print(ts=101, tid=11, buf='C|10|PrevFrameMissed|1')
-trace.add_print(ts=102, tid=11, buf='C|10|PrevFrameMissed|0')
-trace.add_print(ts=103, tid=11, buf='C|10|PrevFrameMissed|1')
-trace.add_print(ts=104, tid=11, buf='C|10|PrevFrameMissed|1')
-trace.add_print(ts=105, tid=11, buf='C|10|PrevFrameMissed|0')
+trace.add_print(ts=99, tid=11, buf='C|10|PrevFrameMissed 101|0')
+trace.add_print(ts=100, tid=11, buf='C|10|PrevFrameMissed 102|0')
+trace.add_print(ts=101, tid=11, buf='C|10|PrevFrameMissed 102|1')
+trace.add_print(ts=102, tid=11, buf='C|10|PrevFrameMissed 102|0')
+trace.add_print(ts=103, tid=11, buf='C|10|PrevFrameMissed 101|1')
+trace.add_print(ts=104, tid=11, buf='C|10|PrevFrameMissed 101|1')
+trace.add_print(ts=105, tid=11, buf='C|10|PrevFrameMissed 101|0')
sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/test/trace_processor/diff_tests/graphics/tests.py b/test/trace_processor/diff_tests/graphics/tests.py
index aea2818ee..7ab6c8901 100644
--- a/test/trace_processor/diff_tests/graphics/tests.py
+++ b/test/trace_processor/diff_tests/graphics/tests.py
@@ -111,6 +111,20 @@ class Graphics(TestSuite):
missed_gpu_frames: 0
missed_frame_rate: 0.42857142857142855 # = 3/7
gpu_invocations: 0
+ metrics_per_display: {
+ display_id: "101"
+ missed_frames: 2
+ missed_hwc_frames: 0
+ missed_gpu_frames: 0
+ missed_frame_rate: 0.5
+ }
+ metrics_per_display: {
+ display_id: "102"
+ missed_frames: 1
+ missed_hwc_frames: 0
+ missed_gpu_frames: 0
+ missed_frame_rate: 0.33333333333333333
+ }
}
"""))
diff --git a/test/trace_processor/diff_tests/parsing/sched_waking_raw_test.sql b/test/trace_processor/diff_tests/parsing/sched_waking_raw_test.sql
index 7fe9c9d8f..481f3f5f1 100644
--- a/test/trace_processor/diff_tests/parsing/sched_waking_raw_test.sql
+++ b/test/trace_processor/diff_tests/parsing/sched_waking_raw_test.sql
@@ -13,4 +13,7 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-SELECT ts, name, cpu, key, int_value, string_value FROM raw JOIN args ON raw.arg_set_id = args.arg_set_id WHERE name = "sched_waking" ORDER BY cpu ASC, ts ASC;
+SELECT ts, name, cpu, key, int_value, string_value
+FROM ftrace_event JOIN args USING(arg_set_id)
+WHERE name = "sched_waking"
+ORDER BY cpu ASC, ts ASC;
diff --git a/test/trace_processor/diff_tests/parsing/tests.py b/test/trace_processor/diff_tests/parsing/tests.py
index 609bdf182..41abe1cb9 100644
--- a/test/trace_processor/diff_tests/parsing/tests.py
+++ b/test/trace_processor/diff_tests/parsing/tests.py
@@ -175,7 +175,7 @@ class Parsing(TestSuite):
trace=DataPath('lmk_userspace.pb'),
query="""
SELECT to_ftrace(id)
- FROM raw;
+ FROM ftrace_event;
""",
out=Path('print_systrace_lmk_userspace.out'))
@@ -272,7 +272,7 @@ class Parsing(TestSuite):
trace=Path('print_systrace_unsigned.py'),
query="""
SELECT to_ftrace(id)
- FROM raw;
+ FROM ftrace_event;
""",
out=Path('print_systrace_unsigned.out'))
@@ -299,7 +299,7 @@ class Parsing(TestSuite):
"""),
query="""
SELECT to_ftrace(id)
- FROM raw;
+ FROM ftrace_event;
""",
out=Path('cgroup_attach_task_pre_s_print_systrace.out'))
@@ -326,7 +326,7 @@ class Parsing(TestSuite):
"""),
query="""
SELECT to_ftrace(id)
- FROM raw;
+ FROM ftrace_event;
""",
out=Path('cgroup_attach_task_post_s_print_systrace.out'))
@@ -919,7 +919,7 @@ class Parsing(TestSuite):
trace=Path('sched_blocked_reason_symbolized.textproto'),
query="""
SELECT to_ftrace(id) AS line
- FROM raw;
+ FROM ftrace_event;
""",
out=Path('sched_blocked_reason_symbolized_to_systrace.out'))
diff --git a/test/trace_processor/diff_tests/performance/frame_timeline_metric.out b/test/trace_processor/diff_tests/performance/frame_timeline_metric.out
index eac9136a9..1a034f009 100644
--- a/test/trace_processor/diff_tests/performance/frame_timeline_metric.out
+++ b/test/trace_processor/diff_tests/performance/frame_timeline_metric.out
@@ -6,6 +6,7 @@ android_frame_timeline_metric {
process {
process {
name: "process1"
+ pid: 1001
}
total_frames: 2
missed_frames: 2
@@ -27,6 +28,7 @@ android_frame_timeline_metric {
process {
process {
name: "process2"
+ pid: 1002
}
total_frames: 2
missed_frames: 1
@@ -48,6 +50,7 @@ android_frame_timeline_metric {
process {
process {
name: "process3"
+ pid: 1003
}
total_frames: 2
missed_frames: 2
@@ -69,6 +72,7 @@ android_frame_timeline_metric {
process {
process {
name: "process4"
+ pid: 1004
}
total_frames: 5
missed_frames: 4
diff --git a/test/trace_processor/diff_tests/power/tests_power_rails.py b/test/trace_processor/diff_tests/power/tests_power_rails.py
index 869604cb2..5085cd24c 100644
--- a/test/trace_processor/diff_tests/power/tests_power_rails.py
+++ b/test/trace_processor/diff_tests/power/tests_power_rails.py
@@ -58,18 +58,18 @@ class PowerPowerRails(TestSuite):
return DiffTestBlueprint(
trace=Path('power_rails.textproto'),
query="""
- SELECT ts, value, t.name AS name
+ SELECT ts, extract_arg(arg_set_id,'packet_ts') as packet_ts, value, t.name AS name
FROM counter c JOIN counter_track t ON t.id = c.track_id
ORDER BY ts
LIMIT 20;
""",
out=Csv("""
- "ts","value","name"
- 3000000,333.000000,"power.test_rail_uws"
- 3000000,0.000000,"power.test_rail_uws"
- 3000004,1000.000000,"Testing"
- 3000005,999.000000,"power.test_rail2_uws"
- 5000000,666.000000,"power.test_rail_uws"
+ "ts","packet_ts","value","name"
+ 3000000,3000003,333.000000,"power.test_rail_uws"
+ 3000000,3000005,0.000000,"power.test_rail_uws"
+ 3000004,"[NULL]",1000.000000,"Testing"
+ 3000005,3000005,999.000000,"power.test_rail2_uws"
+ 5000000,3000005,666.000000,"power.test_rail_uws"
"""))
def test_power_rails_well_known_power_rails(self):
diff --git a/test/trace_processor/diff_tests/profiling/heap_graph.textproto b/test/trace_processor/diff_tests/profiling/heap_graph.textproto
index b3decefb9..a6e314b77 100644
--- a/test/trace_processor/diff_tests/profiling/heap_graph.textproto
+++ b/test/trace_processor/diff_tests/profiling/heap_graph.textproto
@@ -21,7 +21,7 @@ packet {
pid: 2
rss_anon_kb: 1000
vm_swap_kb: 0
- oom_score_adj: 0
+ oom_score_adj: -800
}
}
}
diff --git a/test/trace_processor/diff_tests/profiling/heap_stats_closest_proc.out b/test/trace_processor/diff_tests/profiling/heap_stats_closest_proc.out
index 1ee09bf04..9a786535e 100644
--- a/test/trace_processor/diff_tests/profiling/heap_stats_closest_proc.out
+++ b/test/trace_processor/diff_tests/profiling/heap_stats_closest_proc.out
@@ -4,6 +4,7 @@ java_heap_stats {
process {
name: "proc1"
uid: 1000
+ pid: 2
}
samples {
ts: 200000000
@@ -28,6 +29,7 @@ java_heap_stats {
process {
name: "proc2"
uid: 1000
+ pid: 3
}
samples {
ts: 1500000000
diff --git a/test/trace_processor/diff_tests/profiling/java_heap_histogram.out b/test/trace_processor/diff_tests/profiling/java_heap_histogram.out
index 206dc7ccb..c5aaf4924 100644
--- a/test/trace_processor/diff_tests/profiling/java_heap_histogram.out
+++ b/test/trace_processor/diff_tests/profiling/java_heap_histogram.out
@@ -3,7 +3,8 @@ java_heap_histogram {
upid: 2
process {
name: "system_server"
- uid: 1000
+ uid: 1000,
+ pid: 2
}
samples {
ts: 10
diff --git a/test/trace_processor/diff_tests/profiling/tests.py b/test/trace_processor/diff_tests/profiling/tests.py
index e56fbffae..4c5c2e313 100644
--- a/test/trace_processor/diff_tests/profiling/tests.py
+++ b/test/trace_processor/diff_tests/profiling/tests.py
@@ -116,6 +116,7 @@ class Profiling(TestSuite):
process {
name: "system_server"
uid: 1000
+ pid: 2
}
mappings {
path: "[anon: libc_malloc]"
diff --git a/test/trace_processor/diff_tests/profiling/tests_metrics.py b/test/trace_processor/diff_tests/profiling/tests_metrics.py
index cb210cfea..9a4ff07c3 100644
--- a/test/trace_processor/diff_tests/profiling/tests_metrics.py
+++ b/test/trace_processor/diff_tests/profiling/tests_metrics.py
@@ -71,6 +71,7 @@ class ProfilingMetrics(TestSuite):
process {
name: "system_server"
uid: 1000
+ pid: 2
}
samples {
ts: 10
@@ -81,6 +82,7 @@ class ProfilingMetrics(TestSuite):
obj_count: 6
reachable_obj_count: 3
anon_rss_and_swap_size: 4096000
+ oom_score_adj: 0
roots {
root_type: "ROOT_JAVA_FRAME"
type_name: "DeobfuscatedA[]"
diff --git a/test/trace_processor/diff_tests/startup/android_startup.out b/test/trace_processor/diff_tests/startup/android_startup.out
index 48fa752ba..18b879c9d 100644
--- a/test/trace_processor/diff_tests/startup/android_startup.out
+++ b/test/trace_processor/diff_tests/startup/android_startup.out
@@ -42,7 +42,8 @@ android_startup {
package_name: "com.google.android.calendar"
apk_version_code: 123
debuggable: false
- }
+ },
+ pid: 3
}
report_fully_drawn {
dur_ns: 198
diff --git a/test/trace_processor/diff_tests/startup/android_startup_attribution.out b/test/trace_processor/diff_tests/startup/android_startup_attribution.out
index e55fe5574..ea96296b7 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_attribution.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_attribution.out
@@ -25,8 +25,8 @@ android_startup {
}
dur_ms: 999.9999
time_dex_open {
- dur_ns: 20
- dur_ms: 2e-05
+ dur_ns: 499999845
+ dur_ms: 499.999845
}
time_verify_class {
dur_ns: 40
@@ -45,6 +45,14 @@ android_startup {
dur_ns: 50
dur_ms: 5e-05
}
+ time_dex_open_thread_main {
+ dur_ns: 499999845
+ dur_ms: 499.999845
+ }
+ time_dlopen_thread_main {
+ dur_ns: 2
+ dur_ms: 2e-06
+ }
}
activity_hosting_process_count: 1
process {
@@ -60,6 +68,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
event_timestamps {
intent_received: 100
@@ -106,8 +115,11 @@ android_startup {
name: "dl"
dur_ns: 5
}
+ dlopen_file: "libandroid.so"
+ dlopen_file: "libandroid2.so"
startup_type: "hot"
slow_start_reason: "GC Activity"
+ slow_start_reason: "Main Thread - Time spent in OpenDexFilesFromOat*"
slow_start_reason: "Main Thread - Binder transactions blocked"
}
}
diff --git a/test/trace_processor/diff_tests/startup/android_startup_attribution.py b/test/trace_processor/diff_tests/startup/android_startup_attribution.py
index b92120194..59301e05e 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_attribution.py
+++ b/test/trace_processor/diff_tests/startup/android_startup_attribution.py
@@ -78,13 +78,22 @@ trace.add_atrace_end(ts=165, pid=APP_PID, tid=APP_TID)
trace.add_atrace_begin(
ts=170, pid=APP_PID, tid=APP_TID, buf='OpenDexFilesFromOat(something else)')
-trace.add_atrace_end(ts=175, pid=APP_PID, tid=APP_TID)
+trace.add_atrace_end(ts=5*10**8, pid=APP_PID, tid=APP_TID)
# OpenDex slice outside the startup.
trace.add_atrace_begin(
ts=5, pid=APP_PID, tid=APP_TID, buf='OpenDexFilesFromOat(nothing)')
trace.add_atrace_end(ts=35, pid=APP_PID, tid=APP_TID)
+# dlopen slices within the startup.
+trace.add_atrace_begin(
+ ts=166, pid=APP_PID, tid=APP_TID, buf='dlopen: libandroid.so')
+trace.add_atrace_end(ts=167, pid=APP_PID, tid=APP_TID)
+
+trace.add_atrace_begin(
+ ts=168, pid=APP_PID, tid=APP_TID, buf='dlopen: libandroid2.so')
+trace.add_atrace_end(ts=169, pid=APP_PID, tid=APP_TID)
+
trace.add_atrace_async_end(
ts=LAUNCH_END_TS,
tid=SYSTEM_SERVER_TID,
diff --git a/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out b/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out
index 368b7f251..4bf3fff3e 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_attribution_slow.out
@@ -45,6 +45,10 @@ android_startup {
dur_ns: 50000000000
dur_ms: 50000
}
+ time_dex_open_thread_main {
+ dur_ns: 20000000000
+ dur_ms: 20000.0
+ }
}
activity_hosting_process_count: 1
process {
@@ -60,6 +64,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
event_timestamps {
intent_received: 100000000000
diff --git a/test/trace_processor/diff_tests/startup/android_startup_breakdown.out b/test/trace_processor/diff_tests/startup/android_startup_breakdown.out
index 36aab5fac..2f930d3f3 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_breakdown.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_breakdown.out
@@ -70,6 +70,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
activities {
name: "com.google.android.calendar.MainActivity"
@@ -107,7 +108,7 @@ android_startup {
slow_start_reason: "Time spent in bindApplication"
slow_start_reason: "Time spent in view inflation"
slow_start_reason: "Time spent in ResourcesManager#getResources"
- slow_start_reason: "Potential CPU contention with init"
+ slow_start_reason: "Potential CPU contention with another process"
startup_type: "cold"
}
}
diff --git a/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out b/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out
index 0b17116d0..441709154 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_breakdown_slow.out
@@ -70,6 +70,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
activities {
name: "com.google.android.calendar.MainActivity"
@@ -106,7 +107,7 @@ android_startup {
slow_start_reason: "Time spent in bindApplication"
slow_start_reason: "Time spent in view inflation"
slow_start_reason: "Time spent in ResourcesManager#getResources"
- slow_start_reason: "Potential CPU contention with init"
+ slow_start_reason: "Potential CPU contention with another process"
startup_type: "cold"
}
}
diff --git a/test/trace_processor/diff_tests/startup/android_startup_lock_contention.out b/test/trace_processor/diff_tests/startup/android_startup_lock_contention.out
index e570b2212..ba1311c7f 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_lock_contention.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_lock_contention.out
@@ -55,6 +55,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
event_timestamps {
intent_received: 110
diff --git a/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out b/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out
index cd5dc6c83..aa4ec05bf 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_lock_contention_slow.out
@@ -55,6 +55,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
event_timestamps {
intent_received: 110000000000
diff --git a/test/trace_processor/diff_tests/startup/android_startup_minsdk33.out b/test/trace_processor/diff_tests/startup/android_startup_minsdk33.out
index 1723d34fb..2a8307b07 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_minsdk33.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_minsdk33.out
@@ -63,6 +63,7 @@ android_startup {
apk_version_code: 123
debuggable: true
}
+ pid: 3
}
event_timestamps {
intent_received: 220
diff --git a/test/trace_processor/diff_tests/startup/android_startup_process_track.out b/test/trace_processor/diff_tests/startup/android_startup_process_track.out
index 41b26e5e2..561fb0d2e 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_process_track.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_process_track.out
@@ -51,6 +51,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
event_timestamps {
intent_received: 100
@@ -118,6 +119,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 4
}
event_timestamps {
intent_received: 200
diff --git a/test/trace_processor/diff_tests/startup/android_startup_slow.out b/test/trace_processor/diff_tests/startup/android_startup_slow.out
index 3b5d1ab18..f791fd655 100644
--- a/test/trace_processor/diff_tests/startup/android_startup_slow.out
+++ b/test/trace_processor/diff_tests/startup/android_startup_slow.out
@@ -43,6 +43,7 @@ android_startup {
apk_version_code: 123
debuggable: false
}
+ pid: 3
}
report_fully_drawn {
dur_ns: 198000000000
@@ -66,6 +67,6 @@ android_startup {
slow_start_reason: "Main Thread - Time spent in Runnable state"
slow_start_reason: "Main Thread - Time spent in interruptible sleep state"
slow_start_reason: "Main Thread - Time spent in Blocking I/O"
- slow_start_reason: "Potential CPU contention with init"
+ slow_start_reason: "Potential CPU contention with another process"
}
}
diff --git a/third_party/.gitignore b/third_party/.gitignore
new file mode 100644
index 000000000..16428546e
--- /dev/null
+++ b/third_party/.gitignore
@@ -0,0 +1,3 @@
+clang-format/
+gn/
+ninja/
diff --git a/tools/cpu_profile b/tools/cpu_profile
index 07e795a19..1dfdbb762 100755
--- a/tools/cpu_profile
+++ b/tools/cpu_profile
@@ -37,18 +37,18 @@ import uuid
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7822272,
+ 7904536,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/traceconv',
'sha256':
- '2b1bae4755ee0dd7f3a8e55653f8a7c344f688ea29700064ef8211c55bb4ae9f',
+ '037f84ac943f3f4d75447c668cc49c966fe3d85eca3a455c958b24fc6a9e314a',
'platform':
'darwin',
'machine': ['x86_64']
@@ -58,11 +58,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6604056,
+ 6554600,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/traceconv',
'sha256':
- 'c0bd6d1ebe2c61ffeefbd4f01426e9b853c81daf70530be7e78c97a4d3af100c',
+ 'eda545ef4fa37fdfa1b47ced7cbbe0aa3c0df9bd161cacd7c78e6c55aef98d20',
'platform':
'darwin',
'machine': ['arm64']
@@ -72,11 +72,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 8122112,
+ 7664384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/traceconv',
'sha256':
- 'c4c57d8e7b435822a1437b2dc7f7154f6ff2e197deff1f9284bbd36bbedb004f',
+ '24285e6e0e873d393fa5a993bac18ec8e1ab5fae6f4e3453214e095ef36e4c45',
'platform':
'linux',
'machine': ['x86_64']
@@ -86,11 +86,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6692016,
+ 5657944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/traceconv',
'sha256':
- 'da666eb9f80bcbec4c959f4adf493a59ff89e4106666fe1884291078dba0243b',
+ 'c9af3d976f849fc75e96c2c552cb14fcc9eacce6fe7c45c4a8289080b0f66706',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -100,11 +100,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 7575344,
+ 7184224,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/traceconv',
'sha256':
- '8ca00c39c5ec7bd78576f64c4ab05e663d803b06b36fbddf968825edbe236fca',
+ 'c6dc936492d58a40cd8e0b58abc46bd479e0c1c387cd1ba29198a6c9b2000d7a',
'platform':
'linux',
'machine': ['aarch64']
@@ -114,55 +114,55 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 5376396,
+ 5325260,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/traceconv',
'sha256':
- 'b77e7f0274ba45ff32d34df347845bc996763291fcc6b2a697f56c0c9a543150'
+ '963267dcb58cdde9f61a952e5cb7f3557833209d3251e7fdcefc3b52db54f77b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 6793744,
+ 6572688,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/traceconv',
'sha256':
- 'e83f3d43f8782cb57e9d3e8a3cd31826c9713da9f92bd8d8be2c48872ed423eb'
+ '87373c351fe5e947826cd957438cab8a37a352bf83b1cbbb15fe276eee9d873a'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 7694692,
+ 7303588,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/traceconv',
'sha256':
- 'c9ee2c3c91d6c68cb7f52a626767bde5e267f34c6ddf987ff73eec3d813c0a2c'
+ 'dfc4e714963b5ed662d29d6028ffa69e67f8cd2f9a28223f715437a260fd456f'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7940680,
+ 7482056,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/traceconv',
'sha256':
- 'f75122ca3e6bbe393b705c3bc5514d81c57f38bf408d857d89c4268b79a39e08'
+ '79c666c629fcffd810635270b45e58b40ed253d22650f41550057e5d8f8c49a7'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7239168,
+ 7072768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/windows-amd64/traceconv.exe',
'sha256':
- '5be5d698f69d44b4baa8ae1f21955becad9d0e6774e967f923b8386744002cfe',
+ '40fac80fdeae443a924e160650c94629e6463c1fb5a4f04f4ef6e9e5e72a3965',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/gen_amalgamated b/tools/gen_amalgamated
index c52915582..fac7f60f0 100755
--- a/tools/gen_amalgamated
+++ b/tools/gen_amalgamated
@@ -44,6 +44,7 @@ default_targets = [
# line).
gn_args = ' '.join([
'enable_perfetto_ipc=true',
+ 'enable_perfetto_zlib=false',
'is_debug=false',
'is_perfetto_build_generator=true',
'is_perfetto_embedder=true',
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index d0eb99f9c..531791499 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -819,10 +819,9 @@ def create_tp_tables_module(blueprint: Blueprint, gn: GnParser,
module.cmd = ' '.join([
f'$(location {bp_binary_module_name})',
'--gen-dir=$(genDir)',
+ '--relative-input-dir=external/perfetto',
'--inputs',
'$(in)',
- '--outputs',
- '$(out)',
])
module.out.update(target.outputs)
module.genrule_headers.add(module.name)
diff --git a/tools/gen_bazel b/tools/gen_bazel
index a514fe3e7..7461e4d47 100755
--- a/tools/gen_bazel
+++ b/tools/gen_bazel
@@ -76,16 +76,23 @@ public_targets = [
# exported publicly.
default_targets = [
'//src/base:perfetto_base_default_platform',
+ '//src/cloud_trace_processor:cloud_trace_processor',
'//src/ipc:perfetto_ipc',
'//src/ipc/protoc_plugin:ipc_plugin',
'//src/protozero:protozero',
- '//src/protozero/protoc_plugin:protozero_plugin',
'//src/protozero/protoc_plugin:cppgen_plugin',
- '//test:client_api_example',
+ '//src/protozero/protoc_plugin:protozero_plugin',
'//src/tools/proto_filter:proto_filter',
'//src/tools/proto_merger:proto_merger',
+ '//test:client_api_example',
] + public_targets
+# Proto targets are required by internal build rules but don't need to be
+# exported publicly.
+proto_default_targets = [
+ '//protos/perfetto/cloud_trace_processor:lite'
+]
+
# Proto target groups which will be made public.
proto_groups = {
'config': {
@@ -582,6 +589,9 @@ def gen_cc_tp_tables(target: GnParser.Target):
label = BazelLabel(get_bazel_label_name(target.name), 'perfetto_cc_tp_tables')
label.comment = target.name
label.srcs += (gn_utils.label_to_path(x) for x in target.sources)
+ label.deps += sorted(':' + get_bazel_label_name(x.name)
+ for x in target.transitive_deps
+ if x.name not in default_python_targets)
label.outs += target.outputs
return [label]
@@ -784,6 +794,10 @@ exports_files(["NOTICE"])
continue
gn.get_target(re.sub('(lite|zero|cpp|ipc)$', 'source_set', target.name))
+ # Discover all the default proto targets so it will be generated next.
+ for target in sorted(proto_default_targets):
+ gn.get_target(target)
+
# Generate targets for the transitive set of proto targets.
labels = [
l for target in sorted(itervalues(gn.proto_libs))
diff --git a/tools/gen_binary_descriptors b/tools/gen_binary_descriptors
index 952e809e6..e09a5c4de 100755
--- a/tools/gen_binary_descriptors
+++ b/tools/gen_binary_descriptors
@@ -21,7 +21,6 @@ import re
import argparse
import tempfile
import subprocess
-import hashlib
from compat import iteritems
SOURCE_TARGET = [
@@ -36,13 +35,6 @@ ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
SCRIPT_PATH = 'tools/gen_binary_descriptors'
-def hash_path(path):
- hash = hashlib.sha1()
- with open(os.path.join(ROOT_DIR, path), 'rb') as f:
- hash.update(f.read())
- return hash.hexdigest()
-
-
def find_protoc():
for root, _, files in os.walk(os.path.join(ROOT_DIR, 'out')):
if 'protoc' in files:
@@ -50,26 +42,7 @@ def find_protoc():
return None
-def check(source, target):
- assert os.path.exists(os.path.join(ROOT_DIR, target)), \
- 'Output file {} does not exist and so cannot be checked'.format(target)
-
- sha1_file = target + '.sha1'
- assert os.path.exists(sha1_file), \
- 'SHA1 file {} does not exist and so cannot be checked'.format(sha1_file)
-
- with open(sha1_file, 'rb') as f:
- s = f.read()
-
- hashes = re.findall(r'// SHA1\((.*)\)\n// (.*)\n', s.decode())
- assert sorted([SCRIPT_PATH, source]) == sorted([key for key, _ in hashes])
- for path, expected_sha1 in hashes:
- actual_sha1 = hash_path(os.path.join(ROOT_DIR, path))
- assert actual_sha1 == expected_sha1, \
- 'In {} hash given for {} did not match'.format(target, path)
-
-
-def generate(source, target, protoc_path):
+def generate(source, target, protoc_path, check_only):
# delete=False + manual unlink is required for Windows. Otherwise the temp
# file is kept locked exclusively and unaccassible until it's destroyed.
with tempfile.NamedTemporaryFile(delete=False) as fdescriptor:
@@ -86,23 +59,17 @@ def generate(source, target, protoc_path):
s = fdescriptor.read()
fdescriptor.close()
os.remove(fdescriptor.name)
+
+ if check_only:
+ with open(target, 'rb') as old:
+ old_content = old.read()
+ if (s != old_content):
+ raise AssertionError('Target {} does not match', target)
+ return
+
with open(target, 'wb') as out:
out.write(s)
- sha1_path = target + '.sha1'
- with open(sha1_path, 'wb') as c:
- c.write("""
-// SHA1({script_path})
-// {script_hash}
-// SHA1({source_path})
-// {source_hash}
- """.format(
- script_path=SCRIPT_PATH,
- script_hash=hash_path(__file__),
- source_path=source,
- source_hash=hash_path(os.path.join(source)),
- ).encode())
-
def main():
parser = argparse.ArgumentParser()
@@ -112,15 +79,12 @@ def main():
try:
for source, target in SOURCE_TARGET:
- if args.check_only:
- check(source, target)
- else:
- protoc = args.protoc or find_protoc()
- assert protoc, 'protoc not found specific (--protoc PROTOC_PATH)'
- assert os.path.exists(protoc), '{} does not exist'.format(protoc)
- if protoc is not args.protoc:
- print('Using protoc: {}'.format(protoc))
- generate(source, target, protoc)
+ protoc = args.protoc or find_protoc()
+ assert protoc, 'protoc not found specific (--protoc PROTOC_PATH)'
+ assert os.path.exists(protoc), '{} does not exist'.format(protoc)
+ if protoc is not args.protoc:
+ print('Using protoc: {}'.format(protoc))
+ generate(source, target, protoc, args.check_only)
except AssertionError as e:
if not str(e):
raise
diff --git a/tools/gen_tp_table_docs.py b/tools/gen_tp_table_docs.py
index 8b8565aff..04339bfa0 100755
--- a/tools/gen_tp_table_docs.py
+++ b/tools/gen_tp_table_docs.py
@@ -27,6 +27,7 @@ sys.path.append(os.path.join(ROOT_DIR))
#pylint: disable=wrong-import-position
from python.generators.trace_processor_table.public import ColumnDoc
+from python.generators.trace_processor_table.public import ColumnFlag
import python.generators.trace_processor_table.util as util
from python.generators.trace_processor_table.util import ParsedTable
from python.generators.trace_processor_table.util import ParsedColumn
@@ -43,6 +44,10 @@ def gen_json_for_column(table: ParsedTable,
if table.table.tabledoc.skip_id_and_type and is_skippable_col:
return None
+ # Ignore hidden columns in the documentation.
+ if ColumnFlag.HIDDEN in col.column.flags:
+ return None
+
# Our default assumption is the documentation for a column is a plain string
# so just make the comment for the column equal to that.
@@ -59,7 +64,9 @@ def gen_json_for_column(table: ParsedTable,
raise Exception('Unknown column documentation type '
f'{table.table.class_name}::{col.column.name}')
- parsed_type = table.parse_type(col.column.type)
+ parsed_type = util.parse_type_with_cols(table.table,
+ [c.column for c in table.columns],
+ col.column.type)
docs_type = parsed_type.cpp_type
if docs_type == 'StringPool::Id':
docs_type = 'string'
@@ -88,11 +95,20 @@ def main():
parser = argparse.ArgumentParser()
parser.add_argument('--out', required=True)
parser.add_argument('inputs', nargs='*')
+ parser.add_argument('--relative-input-dir')
args = parser.parse_args()
- tables = util.parse_tables_from_files(args.inputs)
+ def get_relin_path(in_path: str):
+ if not args.relative_input_dir:
+ return in_path
+ return os.path.relpath(in_path, args.relative_input_dir)
+
+ modules = [
+ os.path.splitext(get_relin_path(i).replace('/', '.'))[0]
+ for i in args.inputs
+ ]
table_docs = []
- for parsed in tables:
+ for parsed in util.parse_tables_from_modules(modules):
table = parsed.table
doc = table.tabledoc
assert doc
diff --git a/tools/gen_tp_table_headers.py b/tools/gen_tp_table_headers.py
index 1ce096354..f15245ef8 100755
--- a/tools/gen_tp_table_headers.py
+++ b/tools/gen_tp_table_headers.py
@@ -28,63 +28,71 @@ sys.path.append(os.path.join(ROOT_DIR))
#pylint: disable=wrong-import-position
from python.generators.trace_processor_table.serialize import serialize_header
+from python.generators.trace_processor_table.util import find_table_deps
from python.generators.trace_processor_table.util import ParsedTable
-from python.generators.trace_processor_table.util import parse_tables_from_files
+from python.generators.trace_processor_table.util import parse_tables_from_modules
#pylint: enable=wrong-import-position
+# Suffix which replaces the .py extension for all input modules.
+OUT_HEADER_SUFFIX = '_py.h'
+
@dataclass
class Header:
"""Represents a Python module which will be converted to a header."""
- out_path: str
- relout_path: str
tables: List[ParsedTable]
def main():
"""Main function."""
parser = argparse.ArgumentParser()
- parser.add_argument('--gen-dir', required=True)
parser.add_argument('--inputs', required=True, nargs='*')
- parser.add_argument('--outputs', required=True, nargs='*')
- parser.add_argument('--header-prefix')
+ parser.add_argument('--gen-dir', required=True)
+ parser.add_argument('--relative-input-dir')
+ parser.add_argument('--import-prefix', default='')
args = parser.parse_args()
- if len(args.inputs) != len(args.outputs):
- raise Exception('Number of inputs must match number of outputs')
+ def get_relin_path(in_path: str):
+ if not args.relative_input_dir:
+ return in_path
+ return os.path.relpath(in_path, args.relative_input_dir)
- header_prefix = args.header_prefix if args.header_prefix else ''
- in_to_out = dict(zip(args.inputs, args.outputs))
- headers: Dict[str, Header] = {}
- for table in parse_tables_from_files(args.inputs):
- out_path = in_to_out[table.input_path]
- relout_path = os.path.join(header_prefix,
- os.path.relpath(out_path, args.gen_dir))
+ def get_relout_path(in_path: str):
+ return os.path.splitext(in_path)[0] + OUT_HEADER_SUFFIX
- header = headers.get(table.input_path, Header(out_path, relout_path, []))
+ def get_out_path(in_path: str):
+ return os.path.join(args.gen_dir, get_relout_path(in_path))
+
+ def get_header_path(in_path: str):
+ return os.path.join(args.import_prefix, get_relout_path(in_path))
+
+ modules = [
+ os.path.splitext(get_relin_path(i).replace(os.sep, '.'))[0]
+ for i in args.inputs
+ ]
+ headers: Dict[str, Header] = {}
+ for table in parse_tables_from_modules(modules):
+ input_path = os.path.relpath(table.table.python_module, ROOT_DIR)
+ header = headers.get(input_path, Header([]))
header.tables.append(table)
- headers[table.input_path] = header
+ headers[input_path] = header
- # Build a mapping from table class name to the output path of the header
- # which will be generated for it. This is used to include one header into
- # another for Id dependencies.
- table_class_name_to_relout: Dict[str, str] = {}
- for header in headers.values():
- for table in header.tables:
- table_class_name_to_relout[table.table.class_name] = header.relout_path
+ for in_path, header in headers.items():
+ out_path = get_out_path(in_path)
+ relout_path = get_relout_path(in_path)
- for header in headers.values():
# Find all headers depended on by this table. These will be #include-ed when
# generating the header file below so ensure we remove ourself.
header_relout_deps: Set[str] = set()
for table in header.tables:
- header_relout_deps = header_relout_deps.union(
- [table_class_name_to_relout[c] for c in table.find_table_deps()])
- header_relout_deps.discard(header.relout_path)
+ header_relout_deps = header_relout_deps.union([
+ get_header_path(os.path.relpath(c.python_module, ROOT_DIR))
+ for c in find_table_deps(table.table)
+ ])
+ header_relout_deps.discard(relout_path)
- with open(header.out_path, 'w', encoding='utf8') as out:
- ifdef_guard = re.sub(r'[^a-zA-Z0-9_-]', '_',
- header.relout_path).upper() + '_'
+ with open(out_path, 'w', encoding='utf8') as out:
+ ifdef_guard = re.sub(r'[^a-zA-Z0-9_-]', '_', relout_path).upper() + '_'
out.write(
serialize_header(ifdef_guard, header.tables,
sorted(header_relout_deps)))
diff --git a/tools/heap_profile b/tools/heap_profile
index 40e7f403d..6e32c4bfd 100755
--- a/tools/heap_profile
+++ b/tools/heap_profile
@@ -34,18 +34,18 @@ import uuid
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7822272,
+ 7904536,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/traceconv',
'sha256':
- '2b1bae4755ee0dd7f3a8e55653f8a7c344f688ea29700064ef8211c55bb4ae9f',
+ '037f84ac943f3f4d75447c668cc49c966fe3d85eca3a455c958b24fc6a9e314a',
'platform':
'darwin',
'machine': ['x86_64']
@@ -55,11 +55,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6604056,
+ 6554600,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/traceconv',
'sha256':
- 'c0bd6d1ebe2c61ffeefbd4f01426e9b853c81daf70530be7e78c97a4d3af100c',
+ 'eda545ef4fa37fdfa1b47ced7cbbe0aa3c0df9bd161cacd7c78e6c55aef98d20',
'platform':
'darwin',
'machine': ['arm64']
@@ -69,11 +69,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 8122112,
+ 7664384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/traceconv',
'sha256':
- 'c4c57d8e7b435822a1437b2dc7f7154f6ff2e197deff1f9284bbd36bbedb004f',
+ '24285e6e0e873d393fa5a993bac18ec8e1ab5fae6f4e3453214e095ef36e4c45',
'platform':
'linux',
'machine': ['x86_64']
@@ -83,11 +83,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6692016,
+ 5657944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/traceconv',
'sha256':
- 'da666eb9f80bcbec4c959f4adf493a59ff89e4106666fe1884291078dba0243b',
+ 'c9af3d976f849fc75e96c2c552cb14fcc9eacce6fe7c45c4a8289080b0f66706',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -97,11 +97,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 7575344,
+ 7184224,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/traceconv',
'sha256':
- '8ca00c39c5ec7bd78576f64c4ab05e663d803b06b36fbddf968825edbe236fca',
+ 'c6dc936492d58a40cd8e0b58abc46bd479e0c1c387cd1ba29198a6c9b2000d7a',
'platform':
'linux',
'machine': ['aarch64']
@@ -111,55 +111,55 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 5376396,
+ 5325260,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/traceconv',
'sha256':
- 'b77e7f0274ba45ff32d34df347845bc996763291fcc6b2a697f56c0c9a543150'
+ '963267dcb58cdde9f61a952e5cb7f3557833209d3251e7fdcefc3b52db54f77b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 6793744,
+ 6572688,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/traceconv',
'sha256':
- 'e83f3d43f8782cb57e9d3e8a3cd31826c9713da9f92bd8d8be2c48872ed423eb'
+ '87373c351fe5e947826cd957438cab8a37a352bf83b1cbbb15fe276eee9d873a'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 7694692,
+ 7303588,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/traceconv',
'sha256':
- 'c9ee2c3c91d6c68cb7f52a626767bde5e267f34c6ddf987ff73eec3d813c0a2c'
+ 'dfc4e714963b5ed662d29d6028ffa69e67f8cd2f9a28223f715437a260fd456f'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7940680,
+ 7482056,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/traceconv',
'sha256':
- 'f75122ca3e6bbe393b705c3bc5514d81c57f38bf408d857d89c4268b79a39e08'
+ '79c666c629fcffd810635270b45e58b40ed253d22650f41550057e5d8f8c49a7'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7239168,
+ 7072768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/windows-amd64/traceconv.exe',
'sha256':
- '5be5d698f69d44b4baa8ae1f21955becad9d0e6774e967f923b8386744002cfe',
+ '40fac80fdeae443a924e160650c94629e6463c1fb5a4f04f4ef6e9e5e72a3965',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/install-build-deps b/tools/install-build-deps
index 255be950a..c72eae971 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -23,6 +23,7 @@ import subprocess
import stat
import sys
import tempfile
+import time
import zipfile
from collections import namedtuple
@@ -60,6 +61,17 @@ CLEANUP_OLD_DIRS = [
'buildtools/emsdk', # Moved to buildtools/{mac,linux64}/emsdk
'buildtools/test_data', # Moved to test/data by r.android.com/1539381 .
'buildtools/d8', # Removed by r.android.com/1424334 .
+
+ # Build toools moved to third_party/ by r.android.com/2327602 .
+ 'buildtools/mac/clang-format',
+ 'buildtools/mac/gn',
+ 'buildtools/mac/ninja',
+ 'buildtools/linux64/clang-format',
+ 'buildtools/linux64/gn',
+ 'buildtools/linux64/ninja',
+ 'buildtools/win/clang-format.exe',
+ 'buildtools/win/gn.exe',
+ 'buildtools/win/ninja.exe',
]
# Dependencies required to build code on the host or when targeting desktop OS.
@@ -67,22 +79,22 @@ BUILD_DEPS_TOOLCHAIN_HOST = [
# GN. From https://chrome-infra-packages.appspot.com/dl/gn/gn/.
# git_revision:0725d7827575b239594fbc8fd5192873a1d62f44 .
Dependency(
- 'buildtools/mac/gn',
+ 'third_party/gn/gn',
'https://storage.googleapis.com/perfetto/gn-mac-1968-0725d782',
'9ced623a664560bba38bbadb9b91158ca4186358c847e17ab7d982b351373c2e',
'darwin', 'x64'),
Dependency(
- 'buildtools/mac/gn',
+ 'third_party/gn/gn',
'https://storage.googleapis.com/perfetto/gn-mac-arm64-1968-0725d782',
'd22336b5210b4dad5e36e8c28ce81187f491822cf4d8fd0a257b30d6bee3fd3f',
'darwin', 'arm64'),
Dependency(
- 'buildtools/linux64/gn',
+ 'third_party/gn/gn',
'https://storage.googleapis.com/perfetto/gn-linux64-1968-0725d782',
'f706aaa0676e3e22f5fc9ca482295d7caee8535d1869f99efa2358177b64f5cd',
'linux', 'x64'),
Dependency(
- 'buildtools/win/gn.exe',
+ 'third_party/gn/gn.exe',
'https://storage.googleapis.com/perfetto/gn-win-1968-0725d782',
'001f777f023c7a6959c778fb3a6b6cfc63f6baef953410ecdeaec350fb12285b',
'windows', 'x64'),
@@ -90,19 +102,19 @@ BUILD_DEPS_TOOLCHAIN_HOST = [
# clang-format
# From https://chromium.googlesource.com/chromium/src/buildtools/+/refs/heads/master/mac/clang-format.sha1
Dependency(
- 'buildtools/mac/clang-format',
+ 'third_party/clang-format/clang-format',
'https://storage.googleapis.com/chromium-clang-format/62bde1baa7196ad9df969fc1f06b66360b1a927b',
'6df686a937443cbe6efc013467a7ba5f98d3f187eb7765bb7abc6ce47626cf66',
'darwin', 'all'),
# From https://chromium.googlesource.com/chromium/src/buildtools/+/refs/heads/master/linux64/clang-format.sha1
Dependency(
- 'buildtools/linux64/clang-format',
+ 'third_party/clang-format/clang-format',
'https://storage.googleapis.com/chromium-clang-format/1baf0089e895c989a311b6a38ed94d0e8be4c0a7',
'd02a97a87e8c28898033aaf5986967b24dc47ebd5b376e1cd93e5009f22cd75e',
'linux', 'x64'),
# From https://chromium.googlesource.com/chromium/src/buildtools/+/refs/heads/master/win/clang-format.exe.sha1
Dependency(
- 'buildtools/win/clang-format.exe',
+ 'third_party/clang-format/clang-format.exe',
'https://storage.googleapis.com/chromium-clang-format/d4afd4eba27022f5f6d518133aebde57281677c9',
'2ba1b4d3ade90ea80316890b598ab5fc16777572be26afec6ce23117da121b80',
'windows', 'x64'),
@@ -115,17 +127,17 @@ BUILD_DEPS_TOOLCHAIN_HOST = [
# Ninja
Dependency(
- 'buildtools/mac/ninja',
+ 'third_party/ninja/ninja',
'https://storage.googleapis.com/perfetto/ninja-mac-x64_and_arm64-182',
'36e8b7aaa06911e1334feb664dd731a1cd69a15eb916a231a3d10ff65fca2c73',
'darwin', 'all'),
Dependency(
- 'buildtools/linux64/ninja',
+ 'third_party/ninja/ninja',
'https://storage.googleapis.com/perfetto/ninja-linux64-182',
'54ac6a01362190aaabf4cf276f9c8982cdf11b225438940fdde3339be0f2ecdc',
'linux', 'x64'),
Dependency(
- 'buildtools/win/ninja.exe',
+ 'third_party/ninja/ninja.exe',
'https://storage.googleapis.com/perfetto/ninja-win-182',
'09ced0fcd1a4dec7d1b798a2cf9ce5d20e5d2fbc2337343827f192ce47d0f491',
'windows', 'x64'),
@@ -399,8 +411,22 @@ NODE_MODULES_STATUS_FILE = os.path.join(UI_DIR, 'node_modules', '.last_install')
TEST_DATA_SCRIPT = os.path.join(TOOLS_DIR, 'test_data')
+def CheckCallRetry(*args, **kwargs):
+ """ Like subprocess.check_call, with retries up to 5 times. """
+ MAX_ATTEMPTS = 5
+ for attempt in range(1, MAX_ATTEMPTS + 1):
+ try:
+ return subprocess.check_call(*args, **kwargs)
+ except subprocess.CalledProcessError as error:
+ if attempt == MAX_ATTEMPTS:
+ raise error
+ else:
+ logging.error(error)
+ time.sleep(attempt * 3)
+
+
def DownloadURL(url, out_file):
- subprocess.check_call(['curl', '-L', '-#', '-o', out_file, url])
+ CheckCallRetry(['curl', '-L', '-#', '-o', out_file, url])
def GetArch():
@@ -458,16 +484,23 @@ def RmtreeIfExists(path):
if not os.path.exists(path):
return
+ third_party_path = os.path.abspath(os.path.join(ROOT_DIR, 'third_party'))
buildtools_path = os.path.abspath(os.path.join(ROOT_DIR, 'buildtools'))
test_path = os.path.abspath(os.path.join(ROOT_DIR, 'test', 'data'))
if (not os.path.abspath(path).startswith(buildtools_path) and
- not os.path.abspath(path).startswith(test_path)):
+ not os.path.abspath(path).startswith(test_path) and
+ not os.path.abspath(path).startswith(third_party_path)):
# Safety check to prevent that some merge confilct ends up doing some
# rm -rf / or similar.
- logging.fatal('Cannot remove %s: outside of buildtools and test/data', path)
+ logging.fatal(
+ 'Cannot remove %s: outside of {buildtools, test/data, third_party}',
+ path)
sys.exit(1)
logging.info('Removing %s' % path)
- shutil.rmtree(path, onerror=del_read_only_for_windows)
+ if os.path.isdir(path):
+ shutil.rmtree(path, onerror=del_read_only_for_windows)
+ else:
+ os.remove(path)
def CheckoutGitRepo(path, git_url, revision, check_only):
@@ -480,10 +513,10 @@ def CheckoutGitRepo(path, git_url, revision, check_only):
MkdirRecursive(path)
logging.info('Fetching %s @ %s into %s', git_url, revision, path)
subprocess.check_call(['git', 'init', path], cwd=path)
- subprocess.check_call(
- ['git', 'fetch', '--quiet', '--depth', '1', git_url, revision], cwd=path)
+ CheckCallRetry(['git', 'fetch', '--quiet', '--depth', '1', git_url, revision],
+ cwd=path)
subprocess.check_call(['git', 'checkout', revision, '--quiet'], cwd=path)
- subprocess.check_call(
+ CheckCallRetry(
['git', 'submodule', 'update', '--init', '--recursive', '--quiet'],
cwd=path)
assert (IsGitRepoCheckoutOutAtRevision(path, revision))
@@ -538,6 +571,21 @@ def CheckHashes():
dep.source_url, dep.checksum, actual_checksum))
+def CheckDepotToolsIsRecent():
+ gn_py_path = shutil.which('gn.py')
+ if gn_py_path is None:
+ return True # depot_tools doesn't seem to be installed in the PATH.
+ dt_dir = os.path.abspath(os.path.dirname(gn_py_path))
+ cmd = ['git', '-C', dt_dir, 'merge-base', '--is-ancestor', 'a0cf4321', 'HEAD']
+ git_ret = subprocess.call(cmd, stderr=subprocess.DEVNULL)
+ if git_ret == 0:
+ return True
+ print('\033[91mYour depot_tools revision is too old. Please run:\033[0m')
+ print('git -C %s fetch origin && git -C %s checkout -B main -t origin/main' %
+ (dt_dir, dt_dir))
+ return False
+
+
def Main():
parser = argparse.ArgumentParser()
parser.add_argument(
@@ -569,6 +617,9 @@ def Main():
print('Building the UI on Windows is unsupported')
return 1
+ if not CheckDepotToolsIsRecent():
+ return 1
+
deps = BUILD_DEPS_HOST
if not args.no_toolchain:
deps += BUILD_DEPS_TOOLCHAIN_HOST
diff --git a/tools/record_android_trace b/tools/record_android_trace
index 65f215da3..a9db452ff 100755
--- a/tools/record_android_trace
+++ b/tools/record_android_trace
@@ -33,18 +33,18 @@ import webbrowser
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/tracebox.py
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1415776,
+ 1432064,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/tracebox',
'sha256':
- '860cccef002f1a7216d301a09b97d7276b8a57c8d85ad1c3aa4697bb115ffca7',
+ '4ceb7646cd99303224ab5e7ff0a9f84c04f3c5466fff65a55dab65171ae9d482',
'platform':
'darwin',
'machine': ['x86_64']
@@ -54,11 +54,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1309272,
+ 1325704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/tracebox',
'sha256':
- '9c079ac561064c33e9bdfe2e23e92fb95c025603e545c1aae31b2bd7de0398ad',
+ '2c560fcce5e19eb692e50487af134e2078347cdb79decba0c572917860528388',
'platform':
'darwin',
'machine': ['arm64']
@@ -68,11 +68,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 2137040,
+ 2155496,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/tracebox',
'sha256':
- '9eb9ce1a14432c284fecce7886786bb2555bcb6dfb4f00a2df2885984961a5fc',
+ '10b92180bb461a7e21be3f8b3d4640430a98d0547238ce095709213b378217d2',
'platform':
'linux',
'machine': ['x86_64']
@@ -82,11 +82,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1277896,
+ 1288764,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/tracebox',
'sha256':
- '60c71b39be7e04d9d0278e36e7e4d33c32a03d6cc8a3782a9e5ed2484f3f2082',
+ 'fa28950ce2b7a9345fbb9272f2dd04d3d4eb2a87f021df25e1e649840eae60b5',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -96,11 +96,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 2065704,
+ 2082704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/tracebox',
'sha256':
- 'a8d9e9e186b5daf45ec80b975b9a3ad04cb578890beda136b821c80b9cc74995',
+ '85c371d79b8e23d22a293c29e6399dc311d891a6bd85d7eeaf2cb0179c69eb27',
'platform':
'linux',
'machine': ['aarch64']
@@ -110,44 +110,44 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1161172,
+ 1169364,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/tracebox',
'sha256':
- 'f9dac5df26d471d1cf0aff942d7249da6b4122543e003813203ef128a15f93fd'
+ '40a3f31600f02dea10e290134d5c862e0e717f4f039756889a4e72c60f1591b6'
}, {
'arch':
'android-arm64',
'file_name':
'tracebox',
'file_size':
- 1764008,
+ 1776296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/tracebox',
'sha256':
- '3b325a09b6efae0939b73d4d74e6e01e3735508ed31b774f3a21765efab95099'
+ '562505fca18b34a97687dc002aeebcbf20acef68c8a8e48bed6d618c20e07c92'
}, {
'arch':
'android-x86',
'file_name':
'tracebox',
'file_size':
- 1755052,
+ 1767340,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/tracebox',
'sha256':
- '86e31fa7e2b476187a0222ac2cf6a4ee7e5f8fb5b0e019c1349d14534343a581'
+ 'eb47eb43ba93403557dd15a61196799e945ec324d96109db2f155fb131f9996a'
}, {
'arch':
'android-x64',
'file_name':
'tracebox',
'file_size':
- 2034344,
+ 2054824,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/tracebox',
'sha256':
- '7692f6ceaa5d2eb9da42486262610a1820a9b31d46255f624407bf712eff021d'
+ 'a3ae6d108e041ba368a9770f952772f111865d4eff7c8e4e4e2f653f45017948'
}]
# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/tracebox.py
diff --git a/tools/run_buildtools_binary.py b/tools/run_buildtools_binary.py
index 6fcfe1a30..1ce25a748 100644
--- a/tools/run_buildtools_binary.py
+++ b/tools/run_buildtools_binary.py
@@ -46,7 +46,13 @@ def run_buildtools_binary(args):
cmd = args[0]
args = args[1:]
- exe_path = os.path.join(ROOT_DIR, 'buildtools', os_dir, cmd) + ext
+
+ # Some binaries have been migrated to third_party/xxx. Look into that path
+ # first (see b/261398524)
+ exe_path = os.path.join(ROOT_DIR, 'third_party', cmd, cmd) + ext
+ if not os.path.exists(exe_path):
+ exe_path = os.path.join(ROOT_DIR, 'buildtools', os_dir, cmd) + ext
+
if sys_name == 'windows':
# execl() behaves oddly on Windows: the spawned process doesn't seem to
# receive CTRL+C. Use subprocess instead.
diff --git a/tools/trace_processor b/tools/trace_processor
index 96d5fa337..1ed7c63fc 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -30,18 +30,18 @@ exec python3 - "$@" <<'#'EOF
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/trace_processor_shell.py
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACE_PROCESSOR_SHELL_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'trace_processor_shell',
'file_size':
- 8583152,
+ 8714576,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/trace_processor_shell',
'sha256':
- '35673d3546dec894b5d55147da2fad523a8f5917b42ec1c327c940b82d3ce565',
+ '9bdb89493f0f00db5d3a73166450ac2f6ee830de16415e79c5a0234990caa644',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 7303384,
+ 7286968,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/trace_processor_shell',
'sha256':
- 'a4d301cf8c0c01d328a9253d5ba78f4249333d4b04236cf8be0c7dad2a65e7e0',
+ '948536035fbe680b47b94a99d320ff459450738e4aeeb16cef18364f0023622b',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 8991600,
+ 8576688,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/trace_processor_shell',
'sha256':
- 'e8dd82c1ec73fbbf4165ab0d9cbbb750cff5bcf723a1eab51adc9382bf652361',
+ '493698c81fffcabc340c72831b175962dba5a31dfe8572a6d5af083a116af4f8',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 7117104,
+ 6125384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/trace_processor_shell',
'sha256':
- 'bbfde44ec004815a36cecdc1dbc135f815f46ac6a3989c87cb0c577510c1c8fe',
+ '53f1e27603695cf92d22519993b6eafa9c60957d9cb33bd0b300df8573b87ebb',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 8384816,
+ 8036288,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/trace_processor_shell',
'sha256':
- 'c4f9a499e8c443961725448aabc04cd7dc18cb79883f6b8b615fd8f4ed7c8c16',
+ '2a2cda222c9d5e18b638057688babb00a3a975ccd4b7dd65f26211c2cb7767f9',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,55 +107,55 @@ TRACE_PROCESSOR_SHELL_MANIFEST = [{
'file_name':
'trace_processor_shell',
'file_size':
- 5823560,
+ 5813384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/trace_processor_shell',
'sha256':
- 'ec5d23fc761021fe10a7cdb66d35590dab0216b2305f5163ace98da28b535fb8'
+ 'f3ec4c194d0b06af5b296c1c479e6b29090e6b7cc7e58fbd55ca2919a126f0ee'
}, {
'arch':
'android-arm64',
'file_name':
'trace_processor_shell',
'file_size':
- 7474864,
+ 7294768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/trace_processor_shell',
'sha256':
- 'f4877f51d0fbb8e9ead576e746a7adf7806b5cb2dffc4373a55ceeec21f615ff'
+ 'f44f47d4b873ec68b6fa4f4c69a3e5a13d58b4d9cb2ec591fa687d4480c1950b'
}, {
'arch':
'android-x86',
'file_name':
'trace_processor_shell',
'file_size':
- 8436764,
+ 8090716,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/trace_processor_shell',
'sha256':
- '68ad60af32890f903afb7cbee7cc8f0f4f4b18dea7ab077cb1d807ea80053dcb'
+ '5636d8251747376787640bc3a4894ecf3091e4bf3d38b007003e1992fc5792df'
}, {
'arch':
'android-x64',
'file_name':
'trace_processor_shell',
'file_size':
- 8781544,
+ 8359784,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/trace_processor_shell',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/trace_processor_shell',
'sha256':
- 'edf5efca4cf46ffbd3586592490b14d61758198c7d46c1bc8e083b1ab19382f5'
+ '50440fa055ab998f6cf24f9a9a7388520cc854708735521505e10291bc52f3d0'
}, {
'arch':
'windows-amd64',
'file_name':
'trace_processor_shell.exe',
'file_size':
- 8252928,
+ 8130560,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/windows-amd64/trace_processor_shell.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/windows-amd64/trace_processor_shell.exe',
'sha256':
- '323a210f857ce840c4d69dfa7f9b0a32501ffa4a856e5667a0916e3f8006a5d0',
+ '5cbcf98e29a2d989523235e11e4e0dade692a295ebf47a6c93a09a050ce9bc91',
'platform':
'win32',
'machine': ['amd64']
diff --git a/tools/tracebox b/tools/tracebox
index d788baf39..bf03fa670 100755
--- a/tools/tracebox
+++ b/tools/tracebox
@@ -30,18 +30,18 @@ exec python3 - "$@" <<'#'EOF
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/tracebox.py
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACEBOX_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'tracebox',
'file_size':
- 1415776,
+ 1432064,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/tracebox',
'sha256':
- '860cccef002f1a7216d301a09b97d7276b8a57c8d85ad1c3aa4697bb115ffca7',
+ '4ceb7646cd99303224ab5e7ff0a9f84c04f3c5466fff65a55dab65171ae9d482',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1309272,
+ 1325704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/tracebox',
'sha256':
- '9c079ac561064c33e9bdfe2e23e92fb95c025603e545c1aae31b2bd7de0398ad',
+ '2c560fcce5e19eb692e50487af134e2078347cdb79decba0c572917860528388',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 2137040,
+ 2155496,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/tracebox',
'sha256':
- '9eb9ce1a14432c284fecce7886786bb2555bcb6dfb4f00a2df2885984961a5fc',
+ '10b92180bb461a7e21be3f8b3d4640430a98d0547238ce095709213b378217d2',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1277896,
+ 1288764,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/tracebox',
'sha256':
- '60c71b39be7e04d9d0278e36e7e4d33c32a03d6cc8a3782a9e5ed2484f3f2082',
+ 'fa28950ce2b7a9345fbb9272f2dd04d3d4eb2a87f021df25e1e649840eae60b5',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 2065704,
+ 2082704,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/tracebox',
'sha256':
- 'a8d9e9e186b5daf45ec80b975b9a3ad04cb578890beda136b821c80b9cc74995',
+ '85c371d79b8e23d22a293c29e6399dc311d891a6bd85d7eeaf2cb0179c69eb27',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,44 +107,44 @@ TRACEBOX_MANIFEST = [{
'file_name':
'tracebox',
'file_size':
- 1161172,
+ 1169364,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/tracebox',
'sha256':
- 'f9dac5df26d471d1cf0aff942d7249da6b4122543e003813203ef128a15f93fd'
+ '40a3f31600f02dea10e290134d5c862e0e717f4f039756889a4e72c60f1591b6'
}, {
'arch':
'android-arm64',
'file_name':
'tracebox',
'file_size':
- 1764008,
+ 1776296,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/tracebox',
'sha256':
- '3b325a09b6efae0939b73d4d74e6e01e3735508ed31b774f3a21765efab95099'
+ '562505fca18b34a97687dc002aeebcbf20acef68c8a8e48bed6d618c20e07c92'
}, {
'arch':
'android-x86',
'file_name':
'tracebox',
'file_size':
- 1755052,
+ 1767340,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/tracebox',
'sha256':
- '86e31fa7e2b476187a0222ac2cf6a4ee7e5f8fb5b0e019c1349d14534343a581'
+ 'eb47eb43ba93403557dd15a61196799e945ec324d96109db2f155fb131f9996a'
}, {
'arch':
'android-x64',
'file_name':
'tracebox',
'file_size':
- 2034344,
+ 2054824,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/tracebox',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/tracebox',
'sha256':
- '7692f6ceaa5d2eb9da42486262610a1820a9b31d46255f624407bf712eff021d'
+ 'a3ae6d108e041ba368a9770f952772f111865d4eff7c8e4e4e2f653f45017948'
}]
# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/tracebox.py
diff --git a/tools/traceconv b/tools/traceconv
index f838c6900..9298eb373 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -30,18 +30,18 @@ exec python3 - "$@" <<'#'EOF
# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/traceconv.py
-# This file has been generated by: /usr/local/google/home/lalitm/perfetto/tools/roll-prebuilts v33.1
+# This file has been generated by: /Users/hjd/src/perfetto/tools/roll-prebuilts v34.0
TRACECONV_MANIFEST = [{
'arch':
'mac-amd64',
'file_name':
'traceconv',
'file_size':
- 7822272,
+ 7904536,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-amd64/traceconv',
'sha256':
- '2b1bae4755ee0dd7f3a8e55653f8a7c344f688ea29700064ef8211c55bb4ae9f',
+ '037f84ac943f3f4d75447c668cc49c966fe3d85eca3a455c958b24fc6a9e314a',
'platform':
'darwin',
'machine': ['x86_64']
@@ -51,11 +51,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6604056,
+ 6554600,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/mac-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/mac-arm64/traceconv',
'sha256':
- 'c0bd6d1ebe2c61ffeefbd4f01426e9b853c81daf70530be7e78c97a4d3af100c',
+ 'eda545ef4fa37fdfa1b47ced7cbbe0aa3c0df9bd161cacd7c78e6c55aef98d20',
'platform':
'darwin',
'machine': ['arm64']
@@ -65,11 +65,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 8122112,
+ 7664384,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-amd64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-amd64/traceconv',
'sha256':
- 'c4c57d8e7b435822a1437b2dc7f7154f6ff2e197deff1f9284bbd36bbedb004f',
+ '24285e6e0e873d393fa5a993bac18ec8e1ab5fae6f4e3453214e095ef36e4c45',
'platform':
'linux',
'machine': ['x86_64']
@@ -79,11 +79,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 6692016,
+ 5657944,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm/traceconv',
'sha256':
- 'da666eb9f80bcbec4c959f4adf493a59ff89e4106666fe1884291078dba0243b',
+ 'c9af3d976f849fc75e96c2c552cb14fcc9eacce6fe7c45c4a8289080b0f66706',
'platform':
'linux',
'machine': ['armv6l', 'armv7l', 'armv8l']
@@ -93,11 +93,11 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 7575344,
+ 7184224,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/linux-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/linux-arm64/traceconv',
'sha256':
- '8ca00c39c5ec7bd78576f64c4ab05e663d803b06b36fbddf968825edbe236fca',
+ 'c6dc936492d58a40cd8e0b58abc46bd479e0c1c387cd1ba29198a6c9b2000d7a',
'platform':
'linux',
'machine': ['aarch64']
@@ -107,55 +107,55 @@ TRACECONV_MANIFEST = [{
'file_name':
'traceconv',
'file_size':
- 5376396,
+ 5325260,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm/traceconv',
'sha256':
- 'b77e7f0274ba45ff32d34df347845bc996763291fcc6b2a697f56c0c9a543150'
+ '963267dcb58cdde9f61a952e5cb7f3557833209d3251e7fdcefc3b52db54f77b'
}, {
'arch':
'android-arm64',
'file_name':
'traceconv',
'file_size':
- 6793744,
+ 6572688,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-arm64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-arm64/traceconv',
'sha256':
- 'e83f3d43f8782cb57e9d3e8a3cd31826c9713da9f92bd8d8be2c48872ed423eb'
+ '87373c351fe5e947826cd957438cab8a37a352bf83b1cbbb15fe276eee9d873a'
}, {
'arch':
'android-x86',
'file_name':
'traceconv',
'file_size':
- 7694692,
+ 7303588,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x86/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x86/traceconv',
'sha256':
- 'c9ee2c3c91d6c68cb7f52a626767bde5e267f34c6ddf987ff73eec3d813c0a2c'
+ 'dfc4e714963b5ed662d29d6028ffa69e67f8cd2f9a28223f715437a260fd456f'
}, {
'arch':
'android-x64',
'file_name':
'traceconv',
'file_size':
- 7940680,
+ 7482056,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/android-x64/traceconv',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/android-x64/traceconv',
'sha256':
- 'f75122ca3e6bbe393b705c3bc5514d81c57f38bf408d857d89c4268b79a39e08'
+ '79c666c629fcffd810635270b45e58b40ed253d22650f41550057e5d8f8c49a7'
}, {
'arch':
'windows-amd64',
'file_name':
'traceconv.exe',
'file_size':
- 7239168,
+ 7072768,
'url':
- 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v33.1/windows-amd64/traceconv.exe',
+ 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v34.0/windows-amd64/traceconv.exe',
'sha256':
- '5be5d698f69d44b4baa8ae1f21955becad9d0e6774e967f923b8386744002cfe',
+ '40fac80fdeae443a924e160650c94629e6463c1fb5a4f04f4ef6e9e5e72a3965',
'platform':
'win32',
'machine': ['amd64']
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 7dc51bd84..1bd97da88 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -32,7 +32,8 @@
"pako": "^1.0.11",
"protobufjs": "^6.9.0",
"util": "^0.12.3",
- "uuid": "^9.0.0"
+ "uuid": "^9.0.0",
+ "vega-lite": "^5.9.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.1",
@@ -1569,6 +1570,11 @@
"@types/har-format": "*"
}
},
+ "node_modules/@types/clone": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@types/clone/-/clone-2.1.1.tgz",
+ "integrity": "sha512-BZIU34bSYye0j/BFcPraiDZ5ka6MJADjcDVELGf7glr9K+iE8NYVjFslJFVWzskSxkLLyCrSPScE82/UUoBSvg=="
+ },
"node_modules/@types/color-convert": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-1.9.0.tgz",
@@ -1601,6 +1607,12 @@
"resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.29.tgz",
"integrity": "sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ=="
},
+ "node_modules/@types/geojson": {
+ "version": "7946.0.4",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.4.tgz",
+ "integrity": "sha512-MHmwBtCb7OCv1DSivz2UNJXPGU/1btAWRKlqJ2saEhVJkpkvqHMMaOpKg0v4sAbDWSQekHGvPVMM8nQ+Jen03Q==",
+ "peer": true
+ },
"node_modules/@types/graceful-fs": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
@@ -2164,7 +2176,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -2173,7 +2184,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -2914,6 +2924,14 @@
"wrap-ansi": "^6.2.0"
}
},
+ "node_modules/clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -2980,6 +2998,15 @@
"node": ">= 0.8"
}
},
+ "node_modules/commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "peer": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -3093,6 +3120,229 @@
"resolved": "src/base/utils",
"link": true
},
+ "node_modules/d3-array": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.3.tgz",
+ "integrity": "sha512-JRHwbQQ84XuAESWhvIPaUV4/1UYTBOLiOPGWqgFDHZS1D5QN9c57FbH3QpEnQMYiOXNzKUQyGTZf+EVO7RT5TQ==",
+ "peer": true,
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-delaunay": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+ "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
+ "peer": true,
+ "dependencies": {
+ "delaunator": "5"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dispatch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+ "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dsv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+ "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+ "peer": true,
+ "dependencies": {
+ "commander": "7",
+ "iconv-lite": "0.6",
+ "rw": "1"
+ },
+ "bin": {
+ "csv2json": "bin/dsv2json.js",
+ "csv2tsv": "bin/dsv2dsv.js",
+ "dsv2dsv": "bin/dsv2dsv.js",
+ "dsv2json": "bin/dsv2json.js",
+ "json2csv": "bin/json2dsv.js",
+ "json2dsv": "bin/json2dsv.js",
+ "json2tsv": "bin/json2dsv.js",
+ "tsv2csv": "bin/dsv2dsv.js",
+ "tsv2json": "bin/dsv2json.js"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-force": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+ "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+ "peer": true,
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-quadtree": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz",
+ "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "2.5.0 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo-projection": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz",
+ "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==",
+ "peer": true,
+ "dependencies": {
+ "commander": "7",
+ "d3-array": "1 - 3",
+ "d3-geo": "1.12.0 - 3"
+ },
+ "bin": {
+ "geo2svg": "bin/geo2svg.js",
+ "geograticule": "bin/geograticule.js",
+ "geoproject": "bin/geoproject.js",
+ "geoquantize": "bin/geoquantize.js",
+ "geostitch": "bin/geostitch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-hierarchy": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+ "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "peer": true,
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-quadtree": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+ "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "peer": true,
+ "dependencies": {
+ "d3-path": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "peer": true,
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/data-urls": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
@@ -3236,6 +3486,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/delaunator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz",
+ "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==",
+ "peer": true,
+ "dependencies": {
+ "robust-predicates": "^3.0.0"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -3355,14 +3614,12 @@
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/encoding": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
- "dev": true,
"optional": true,
"dependencies": {
"iconv-lite": "^0.6.2"
@@ -3741,7 +3998,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true,
"engines": {
"node": ">=6"
}
@@ -4337,8 +4593,7 @@
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-glob": {
"version": "3.2.12",
@@ -4371,8 +4626,7 @@
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
@@ -4562,7 +4816,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@@ -4995,8 +5248,6 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dev": true,
- "optional": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
@@ -5115,6 +5366,15 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/ip": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
@@ -5277,7 +5537,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -6358,6 +6617,11 @@
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true
},
+ "node_modules/json-stringify-pretty-compact": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz",
+ "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA=="
+ },
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -6934,7 +7198,6 @@
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
@@ -8274,7 +8537,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8388,6 +8650,12 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/robust-predicates": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz",
+ "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==",
+ "peer": true
+ },
"node_modules/rollup": {
"version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
@@ -8491,6 +8759,12 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/rw": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
+ "peer": true
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -8523,8 +8797,7 @@
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sane": {
"version": "4.1.0",
@@ -9590,7 +9863,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -9604,7 +9876,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -9886,11 +10157,30 @@
"node": ">=8.0"
}
},
+ "node_modules/topojson-client": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz",
+ "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==",
+ "peer": true,
+ "dependencies": {
+ "commander": "2"
+ },
+ "bin": {
+ "topo2geo": "bin/topo2geo",
+ "topomerge": "bin/topomerge",
+ "topoquantize": "bin/topoquantize"
+ }
+ },
+ "node_modules/topojson-client/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "peer": true
+ },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/trim-newlines": {
"version": "3.0.1",
@@ -9910,8 +10200,7 @@
"node_modules/tslib": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
- "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
- "dev": true
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -10197,6 +10486,484 @@
"spdx-expression-parse": "^3.0.0"
}
},
+ "node_modules/vega": {
+ "version": "5.25.0",
+ "resolved": "https://registry.npmjs.org/vega/-/vega-5.25.0.tgz",
+ "integrity": "sha512-lr+uj0mhYlSN3JOKbMNp1RzZBenWp9DxJ7kR3lha58AFNCzzds7pmFa7yXPbtbaGhB7Buh/t6n+Bzk3Y0VnF5g==",
+ "peer": true,
+ "dependencies": {
+ "vega-crossfilter": "~4.1.1",
+ "vega-dataflow": "~5.7.5",
+ "vega-encode": "~4.9.2",
+ "vega-event-selector": "~3.0.1",
+ "vega-expression": "~5.1.0",
+ "vega-force": "~4.2.0",
+ "vega-format": "~1.1.1",
+ "vega-functions": "~5.13.2",
+ "vega-geo": "~4.4.1",
+ "vega-hierarchy": "~4.1.1",
+ "vega-label": "~1.2.1",
+ "vega-loader": "~4.5.1",
+ "vega-parser": "~6.2.0",
+ "vega-projection": "~1.6.0",
+ "vega-regression": "~1.2.0",
+ "vega-runtime": "~6.1.4",
+ "vega-scale": "~7.3.0",
+ "vega-scenegraph": "~4.10.2",
+ "vega-statistics": "~1.9.0",
+ "vega-time": "~2.1.1",
+ "vega-transforms": "~4.10.2",
+ "vega-typings": "~0.24.0",
+ "vega-util": "~1.17.2",
+ "vega-view": "~5.11.1",
+ "vega-view-transforms": "~4.5.9",
+ "vega-voronoi": "~4.2.1",
+ "vega-wordcloud": "~4.1.4"
+ }
+ },
+ "node_modules/vega-canvas": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/vega-canvas/-/vega-canvas-1.2.7.tgz",
+ "integrity": "sha512-OkJ9CACVcN9R5Pi9uF6MZBF06pO6qFpDYHWSKBJsdHP5o724KrsgR6UvbnXFH82FdsiTOff/HqjuaG8C7FL+9Q==",
+ "peer": true
+ },
+ "node_modules/vega-crossfilter": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/vega-crossfilter/-/vega-crossfilter-4.1.1.tgz",
+ "integrity": "sha512-yesvlMcwRwxrtAd9IYjuxWJJuAMI0sl7JvAFfYtuDkkGDtqfLXUcCzHIATqW6igVIE7tWwGxnbfvQLhLNgK44Q==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-dataflow": {
+ "version": "5.7.5",
+ "resolved": "https://registry.npmjs.org/vega-dataflow/-/vega-dataflow-5.7.5.tgz",
+ "integrity": "sha512-EdsIl6gouH67+8B0f22Owr2tKDiMPNNR8lEvJDcxmFw02nXd8juimclpLvjPQriqn6ta+3Dn5txqfD117H04YA==",
+ "peer": true,
+ "dependencies": {
+ "vega-format": "^1.1.1",
+ "vega-loader": "^4.5.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-encode": {
+ "version": "4.9.2",
+ "resolved": "https://registry.npmjs.org/vega-encode/-/vega-encode-4.9.2.tgz",
+ "integrity": "sha512-c3J0LYkgYeXQxwnYkEzL15cCFBYPRaYUon8O2SZ6O4PhH4dfFTXBzSyT8+gh8AhBd572l2yGDfxpEYA6pOqdjg==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "d3-interpolate": "^3.0.1",
+ "vega-dataflow": "^5.7.5",
+ "vega-scale": "^7.3.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-event-selector": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-3.0.1.tgz",
+ "integrity": "sha512-K5zd7s5tjr1LiOOkjGpcVls8GsH/f2CWCrWcpKy74gTCp+llCdwz0Enqo013ZlGaRNjfgD/o1caJRt3GSaec4A=="
+ },
+ "node_modules/vega-expression": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-5.1.0.tgz",
+ "integrity": "sha512-u8Rzja/cn2PEUkhQN3zUj3REwNewTA92ExrcASNKUJPCciMkHJEjESwFYuI6DWMCq4hQElQ92iosOAtwzsSTqA==",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-expression/node_modules/@types/estree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
+ "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA=="
+ },
+ "node_modules/vega-force": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/vega-force/-/vega-force-4.2.0.tgz",
+ "integrity": "sha512-aE2TlP264HXM1r3fl58AvZdKUWBNOGkIvn4EWyqeJdgO2vz46zSU7x7TzPG4ZLuo44cDRU5Ng3I1eQk23Asz6A==",
+ "peer": true,
+ "dependencies": {
+ "d3-force": "^3.0.0",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-format": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vega-format/-/vega-format-1.1.1.tgz",
+ "integrity": "sha512-Rll7YgpYbsgaAa54AmtEWrxaJqgOh5fXlvM2wewO4trb9vwM53KBv4Q/uBWCLK3LLGeBXIF6gjDt2LFuJAUtkQ==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "d3-format": "^3.1.0",
+ "d3-time-format": "^4.1.0",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-functions": {
+ "version": "5.13.2",
+ "resolved": "https://registry.npmjs.org/vega-functions/-/vega-functions-5.13.2.tgz",
+ "integrity": "sha512-YE1Xl3Qi28kw3vdXVYgKFMo20ttd3+SdKth1jUNtBDGGdrOpvPxxFhZkVqX+7FhJ5/1UkDoAYs/cZY0nRKiYgA==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "d3-color": "^3.1.0",
+ "d3-geo": "^3.1.0",
+ "vega-dataflow": "^5.7.5",
+ "vega-expression": "^5.1.0",
+ "vega-scale": "^7.3.0",
+ "vega-scenegraph": "^4.10.2",
+ "vega-selections": "^5.4.1",
+ "vega-statistics": "^1.8.1",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-geo": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/vega-geo/-/vega-geo-4.4.1.tgz",
+ "integrity": "sha512-s4WeZAL5M3ZUV27/eqSD3v0FyJz3PlP31XNSLFy4AJXHxHUeXT3qLiDHoVQnW5Om+uBCPDtTT1ROx1smGIf2aA==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "d3-color": "^3.1.0",
+ "d3-geo": "^3.1.0",
+ "vega-canvas": "^1.2.7",
+ "vega-dataflow": "^5.7.5",
+ "vega-projection": "^1.6.0",
+ "vega-statistics": "^1.8.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-hierarchy": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/vega-hierarchy/-/vega-hierarchy-4.1.1.tgz",
+ "integrity": "sha512-h5mbrDtPKHBBQ9TYbvEb/bCqmGTlUX97+4CENkyH21tJs7naza319B15KRK0NWOHuhbGhFmF8T0696tg+2c8XQ==",
+ "peer": true,
+ "dependencies": {
+ "d3-hierarchy": "^3.1.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-label": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/vega-label/-/vega-label-1.2.1.tgz",
+ "integrity": "sha512-n/ackJ5lc0Xs9PInCaGumYn2awomPjJ87EMVT47xNgk2bHmJoZV1Ve/1PUM6Eh/KauY211wPMrNp/9Im+7Ripg==",
+ "peer": true,
+ "dependencies": {
+ "vega-canvas": "^1.2.6",
+ "vega-dataflow": "^5.7.3",
+ "vega-scenegraph": "^4.9.2",
+ "vega-util": "^1.15.2"
+ }
+ },
+ "node_modules/vega-lite": {
+ "version": "5.9.0",
+ "resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-5.9.0.tgz",
+ "integrity": "sha512-VA3XDlF6nd/t46KDMfq8eNKOJKy9gpJuM+6CIl3jbWqS97jWXRWXp8DpUyDmbV+iq8n4hqNTaoPqDP/e03kifw==",
+ "dependencies": {
+ "@types/clone": "~2.1.1",
+ "clone": "~2.1.2",
+ "fast-deep-equal": "~3.1.3",
+ "fast-json-stable-stringify": "~2.1.0",
+ "json-stringify-pretty-compact": "~3.0.0",
+ "tslib": "~2.5.0",
+ "vega-event-selector": "~3.0.1",
+ "vega-expression": "~5.1.0",
+ "vega-util": "~1.17.2",
+ "yargs": "~17.7.1"
+ },
+ "bin": {
+ "vl2pdf": "bin/vl2pdf",
+ "vl2png": "bin/vl2png",
+ "vl2svg": "bin/vl2svg",
+ "vl2vg": "bin/vl2vg"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "vega": "^5.24.0"
+ }
+ },
+ "node_modules/vega-lite/node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vega-lite/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/vega-lite/node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/vega-lite/node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vega-lite/node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vega-loader": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/vega-loader/-/vega-loader-4.5.1.tgz",
+ "integrity": "sha512-qy5x32SaT0YkEujQM2yKqvLGV9XWQ2aEDSugBFTdYzu/1u4bxdUSRDREOlrJ9Km3RWIOgFiCkobPmFxo47SKuA==",
+ "peer": true,
+ "dependencies": {
+ "d3-dsv": "^3.0.1",
+ "node-fetch": "^2.6.7",
+ "topojson-client": "^3.1.0",
+ "vega-format": "^1.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-parser": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/vega-parser/-/vega-parser-6.2.0.tgz",
+ "integrity": "sha512-as+QnX8Qxe9q51L1C2sVBd+YYYctP848+zEvkBT2jlI2g30aZ6Uv7sKsq7QTL6DUbhXQKR0XQtzlanckSFdaOQ==",
+ "peer": true,
+ "dependencies": {
+ "vega-dataflow": "^5.7.5",
+ "vega-event-selector": "^3.0.1",
+ "vega-functions": "^5.13.1",
+ "vega-scale": "^7.3.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-projection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/vega-projection/-/vega-projection-1.6.0.tgz",
+ "integrity": "sha512-LGUaO/kpOEYuTlul+x+lBzyuL9qmMwP1yShdUWYLW+zXoeyGbs5OZW+NbPPwLYqJr5lpXDr/vGztFuA/6g2xvQ==",
+ "peer": true,
+ "dependencies": {
+ "d3-geo": "^3.1.0",
+ "d3-geo-projection": "^4.0.0",
+ "vega-scale": "^7.3.0"
+ }
+ },
+ "node_modules/vega-regression": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/vega-regression/-/vega-regression-1.2.0.tgz",
+ "integrity": "sha512-6TZoPlhV/280VbxACjRKqlE0Nv48z5g4CSNf1FmGGTWS1rQtElPTranSoVW4d7ET5eVQ6f9QLxNAiALptvEq+g==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "vega-dataflow": "^5.7.3",
+ "vega-statistics": "^1.9.0",
+ "vega-util": "^1.15.2"
+ }
+ },
+ "node_modules/vega-runtime": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/vega-runtime/-/vega-runtime-6.1.4.tgz",
+ "integrity": "sha512-0dDYXyFLQcxPQ2OQU0WuBVYLRZnm+/CwVu6i6N4idS7R9VXIX5581EkCh3pZ20pQ/+oaA7oJ0pR9rJgJ6rukRQ==",
+ "peer": true,
+ "dependencies": {
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-scale": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/vega-scale/-/vega-scale-7.3.0.tgz",
+ "integrity": "sha512-pMOAI2h+e1z7lsqKG+gMfR6NKN2sTcyjZbdJwntooW0uFHwjLGjMSY7kSd3nSEquF0HQ8qF7zR6gs1eRwlGimw==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "d3-interpolate": "^3.0.1",
+ "d3-scale": "^4.0.2",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-scenegraph": {
+ "version": "4.10.2",
+ "resolved": "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-4.10.2.tgz",
+ "integrity": "sha512-R8m6voDZO5+etwNMcXf45afVM3XAtokMqxuDyddRl9l1YqSJfS+3u8hpolJ50c2q6ZN20BQiJwKT1o0bB7vKkA==",
+ "peer": true,
+ "dependencies": {
+ "d3-path": "^3.1.0",
+ "d3-shape": "^3.2.0",
+ "vega-canvas": "^1.2.7",
+ "vega-loader": "^4.5.1",
+ "vega-scale": "^7.3.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-selections": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/vega-selections/-/vega-selections-5.4.1.tgz",
+ "integrity": "sha512-EtYc4DvA+wXqBg9tq+kDomSoVUPCmQfS7hUxy2qskXEed79YTimt3Hcl1e1fW226I4AVDBEqTTKebmKMzbSgAA==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "3.2.2",
+ "vega-expression": "^5.0.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-selections/node_modules/d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ==",
+ "peer": true,
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vega-statistics": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/vega-statistics/-/vega-statistics-1.9.0.tgz",
+ "integrity": "sha512-GAqS7mkatpXcMCQKWtFu1eMUKLUymjInU0O8kXshWaQrVWjPIO2lllZ1VNhdgE0qGj4oOIRRS11kzuijLshGXQ==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2"
+ }
+ },
+ "node_modules/vega-time": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/vega-time/-/vega-time-2.1.1.tgz",
+ "integrity": "sha512-z1qbgyX0Af2kQSGFbApwBbX2meenGvsoX8Nga8uyWN8VIbiySo/xqizz1KrP6NbB6R+x5egKmkjdnyNThPeEWA==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "d3-time": "^3.1.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-transforms": {
+ "version": "4.10.2",
+ "resolved": "https://registry.npmjs.org/vega-transforms/-/vega-transforms-4.10.2.tgz",
+ "integrity": "sha512-sJELfEuYQ238PRG+GOqQch8D69RYnJevYSGLsRGQD2LxNz3j+GlUX6Pid+gUEH5HJy22Q5L0vsTl2ZNhIr4teQ==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-statistics": "^1.8.1",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-typings": {
+ "version": "0.24.1",
+ "resolved": "https://registry.npmjs.org/vega-typings/-/vega-typings-0.24.1.tgz",
+ "integrity": "sha512-WNw6tDxwMsynQ9osJb3RZi3g8GZruxVgXfe8N7nbqvNOgDQkUuVjqTZiwGg5kqjmLqx09lRRlskgp/ov7lEGeg==",
+ "peer": true,
+ "dependencies": {
+ "@types/geojson": "7946.0.4",
+ "vega-event-selector": "^3.0.1",
+ "vega-expression": "^5.0.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-util": {
+ "version": "1.17.2",
+ "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-1.17.2.tgz",
+ "integrity": "sha512-omNmGiZBdjm/jnHjZlywyYqafscDdHaELHx1q96n5UOz/FlO9JO99P4B3jZg391EFG8dqhWjQilSf2JH6F1mIw=="
+ },
+ "node_modules/vega-view": {
+ "version": "5.11.1",
+ "resolved": "https://registry.npmjs.org/vega-view/-/vega-view-5.11.1.tgz",
+ "integrity": "sha512-RoWxuoEMI7xVQJhPqNeLEHCezudsf3QkVMhH5tCovBqwBADQGqq9iWyax3ZzdyX1+P3eBgm7cnLvpqtN2hU8kA==",
+ "peer": true,
+ "dependencies": {
+ "d3-array": "^3.2.2",
+ "d3-timer": "^3.0.1",
+ "vega-dataflow": "^5.7.5",
+ "vega-format": "^1.1.1",
+ "vega-functions": "^5.13.1",
+ "vega-runtime": "^6.1.4",
+ "vega-scenegraph": "^4.10.2",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-view-transforms": {
+ "version": "4.5.9",
+ "resolved": "https://registry.npmjs.org/vega-view-transforms/-/vega-view-transforms-4.5.9.tgz",
+ "integrity": "sha512-NxEq4ZD4QwWGRrl2yDLnBRXM9FgCI+vvYb3ZC2+nVDtkUxOlEIKZsMMw31op5GZpfClWLbjCT3mVvzO2xaTF+g==",
+ "peer": true,
+ "dependencies": {
+ "vega-dataflow": "^5.7.5",
+ "vega-scenegraph": "^4.10.2",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-voronoi": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/vega-voronoi/-/vega-voronoi-4.2.1.tgz",
+ "integrity": "sha512-zzi+fxU/SBad4irdLLsG3yhZgXWZezraGYVQfZFWe8kl7W/EHUk+Eqk/eetn4bDeJ6ltQskX+UXH3OP5Vh0Q0Q==",
+ "peer": true,
+ "dependencies": {
+ "d3-delaunay": "^6.0.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "node_modules/vega-wordcloud": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/vega-wordcloud/-/vega-wordcloud-4.1.4.tgz",
+ "integrity": "sha512-oeZLlnjiusLAU5vhk0IIdT5QEiJE0x6cYoGNq1th+EbwgQp153t4r026fcib9oq15glHFOzf81a8hHXHSJm1Jw==",
+ "peer": true,
+ "dependencies": {
+ "vega-canvas": "^1.2.7",
+ "vega-dataflow": "^5.7.5",
+ "vega-scale": "^7.3.0",
+ "vega-statistics": "^1.8.1",
+ "vega-util": "^1.17.1"
+ }
+ },
"node_modules/vlq": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
@@ -10237,8 +11004,7 @@
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
- "dev": true
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-encoding": {
"version": "1.0.5",
@@ -10271,7 +11037,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dev": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
@@ -11706,6 +12471,11 @@
"@types/har-format": "*"
}
},
+ "@types/clone": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@types/clone/-/clone-2.1.1.tgz",
+ "integrity": "sha512-BZIU34bSYye0j/BFcPraiDZ5ka6MJADjcDVELGf7glr9K+iE8NYVjFslJFVWzskSxkLLyCrSPScE82/UUoBSvg=="
+ },
"@types/color-convert": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-1.9.0.tgz",
@@ -11738,6 +12508,12 @@
"resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.29.tgz",
"integrity": "sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ=="
},
+ "@types/geojson": {
+ "version": "7946.0.4",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.4.tgz",
+ "integrity": "sha512-MHmwBtCb7OCv1DSivz2UNJXPGU/1btAWRKlqJ2saEhVJkpkvqHMMaOpKg0v4sAbDWSQekHGvPVMM8nQ+Jen03Q==",
+ "peer": true
+ },
"@types/graceful-fs": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
@@ -12161,14 +12937,12 @@
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -12711,6 +13485,11 @@
"wrap-ansi": "^6.2.0"
}
},
+ "clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="
+ },
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -12761,6 +13540,12 @@
"delayed-stream": "~1.0.0"
}
},
+ "commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "peer": true
+ },
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -12860,6 +13645,157 @@
"custom_utils": {
"version": "file:src/base/utils"
},
+ "d3-array": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.3.tgz",
+ "integrity": "sha512-JRHwbQQ84XuAESWhvIPaUV4/1UYTBOLiOPGWqgFDHZS1D5QN9c57FbH3QpEnQMYiOXNzKUQyGTZf+EVO7RT5TQ==",
+ "peer": true,
+ "requires": {
+ "internmap": "1 - 2"
+ }
+ },
+ "d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "peer": true
+ },
+ "d3-delaunay": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+ "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
+ "peer": true,
+ "requires": {
+ "delaunator": "5"
+ }
+ },
+ "d3-dispatch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+ "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+ "peer": true
+ },
+ "d3-dsv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+ "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+ "peer": true,
+ "requires": {
+ "commander": "7",
+ "iconv-lite": "0.6",
+ "rw": "1"
+ }
+ },
+ "d3-force": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+ "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+ "peer": true,
+ "requires": {
+ "d3-dispatch": "1 - 3",
+ "d3-quadtree": "1 - 3",
+ "d3-timer": "1 - 3"
+ }
+ },
+ "d3-format": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "peer": true
+ },
+ "d3-geo": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz",
+ "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==",
+ "peer": true,
+ "requires": {
+ "d3-array": "2.5.0 - 3"
+ }
+ },
+ "d3-geo-projection": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz",
+ "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==",
+ "peer": true,
+ "requires": {
+ "commander": "7",
+ "d3-array": "1 - 3",
+ "d3-geo": "1.12.0 - 3"
+ }
+ },
+ "d3-hierarchy": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+ "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
+ "peer": true
+ },
+ "d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "peer": true,
+ "requires": {
+ "d3-color": "1 - 3"
+ }
+ },
+ "d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "peer": true
+ },
+ "d3-quadtree": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+ "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
+ "peer": true
+ },
+ "d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "peer": true,
+ "requires": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ }
+ },
+ "d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "peer": true,
+ "requires": {
+ "d3-path": "^3.1.0"
+ }
+ },
+ "d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "peer": true,
+ "requires": {
+ "d3-array": "2 - 3"
+ }
+ },
+ "d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "peer": true,
+ "requires": {
+ "d3-time": "1 - 3"
+ }
+ },
+ "d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "peer": true
+ },
"data-urls": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
@@ -12966,6 +13902,15 @@
"isobject": "^3.0.1"
}
},
+ "delaunator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz",
+ "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==",
+ "peer": true,
+ "requires": {
+ "robust-predicates": "^3.0.0"
+ }
+ },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -13057,14 +14002,12 @@
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"encoding": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
- "dev": true,
"optional": true,
"requires": {
"iconv-lite": "^0.6.2"
@@ -13252,8 +14195,7 @@
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
"escape-string-regexp": {
"version": "4.0.0",
@@ -13707,8 +14649,7 @@
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-glob": {
"version": "3.2.12",
@@ -13737,8 +14678,7 @@
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-levenshtein": {
"version": "2.0.6",
@@ -13890,8 +14830,7 @@
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-intrinsic": {
"version": "1.2.0",
@@ -14221,8 +15160,6 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dev": true,
- "optional": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
@@ -14296,6 +15233,12 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
+ "internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "peer": true
+ },
"ip": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
@@ -14409,8 +15352,7 @@
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"is-generator-fn": {
"version": "2.1.0",
@@ -15246,6 +16188,11 @@
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true
},
+ "json-stringify-pretty-compact": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz",
+ "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA=="
+ },
"json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -15698,7 +16645,6 @@
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
"requires": {
"whatwg-url": "^5.0.0"
}
@@ -16714,8 +17660,7 @@
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
},
"require-main-filename": {
"version": "2.0.0",
@@ -16796,6 +17741,12 @@
"glob": "^7.1.3"
}
},
+ "robust-predicates": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz",
+ "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==",
+ "peer": true
+ },
"rollup": {
"version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
@@ -16868,6 +17819,12 @@
"queue-microtask": "^1.2.2"
}
},
+ "rw": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
+ "peer": true
+ },
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -16886,8 +17843,7 @@
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sane": {
"version": "4.1.0",
@@ -17764,7 +18720,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -17775,7 +18730,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
@@ -17997,11 +18951,27 @@
"is-number": "^7.0.0"
}
},
+ "topojson-client": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz",
+ "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==",
+ "peer": true,
+ "requires": {
+ "commander": "2"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "peer": true
+ }
+ }
+ },
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"trim-newlines": {
"version": "3.0.1",
@@ -18018,8 +18988,7 @@
"tslib": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
- "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
- "dev": true
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
},
"type-check": {
"version": "0.4.0",
@@ -18244,6 +19213,457 @@
"spdx-expression-parse": "^3.0.0"
}
},
+ "vega": {
+ "version": "5.25.0",
+ "resolved": "https://registry.npmjs.org/vega/-/vega-5.25.0.tgz",
+ "integrity": "sha512-lr+uj0mhYlSN3JOKbMNp1RzZBenWp9DxJ7kR3lha58AFNCzzds7pmFa7yXPbtbaGhB7Buh/t6n+Bzk3Y0VnF5g==",
+ "peer": true,
+ "requires": {
+ "vega-crossfilter": "~4.1.1",
+ "vega-dataflow": "~5.7.5",
+ "vega-encode": "~4.9.2",
+ "vega-event-selector": "~3.0.1",
+ "vega-expression": "~5.1.0",
+ "vega-force": "~4.2.0",
+ "vega-format": "~1.1.1",
+ "vega-functions": "~5.13.2",
+ "vega-geo": "~4.4.1",
+ "vega-hierarchy": "~4.1.1",
+ "vega-label": "~1.2.1",
+ "vega-loader": "~4.5.1",
+ "vega-parser": "~6.2.0",
+ "vega-projection": "~1.6.0",
+ "vega-regression": "~1.2.0",
+ "vega-runtime": "~6.1.4",
+ "vega-scale": "~7.3.0",
+ "vega-scenegraph": "~4.10.2",
+ "vega-statistics": "~1.9.0",
+ "vega-time": "~2.1.1",
+ "vega-transforms": "~4.10.2",
+ "vega-typings": "~0.24.0",
+ "vega-util": "~1.17.2",
+ "vega-view": "~5.11.1",
+ "vega-view-transforms": "~4.5.9",
+ "vega-voronoi": "~4.2.1",
+ "vega-wordcloud": "~4.1.4"
+ }
+ },
+ "vega-canvas": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/vega-canvas/-/vega-canvas-1.2.7.tgz",
+ "integrity": "sha512-OkJ9CACVcN9R5Pi9uF6MZBF06pO6qFpDYHWSKBJsdHP5o724KrsgR6UvbnXFH82FdsiTOff/HqjuaG8C7FL+9Q==",
+ "peer": true
+ },
+ "vega-crossfilter": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/vega-crossfilter/-/vega-crossfilter-4.1.1.tgz",
+ "integrity": "sha512-yesvlMcwRwxrtAd9IYjuxWJJuAMI0sl7JvAFfYtuDkkGDtqfLXUcCzHIATqW6igVIE7tWwGxnbfvQLhLNgK44Q==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-dataflow": {
+ "version": "5.7.5",
+ "resolved": "https://registry.npmjs.org/vega-dataflow/-/vega-dataflow-5.7.5.tgz",
+ "integrity": "sha512-EdsIl6gouH67+8B0f22Owr2tKDiMPNNR8lEvJDcxmFw02nXd8juimclpLvjPQriqn6ta+3Dn5txqfD117H04YA==",
+ "peer": true,
+ "requires": {
+ "vega-format": "^1.1.1",
+ "vega-loader": "^4.5.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-encode": {
+ "version": "4.9.2",
+ "resolved": "https://registry.npmjs.org/vega-encode/-/vega-encode-4.9.2.tgz",
+ "integrity": "sha512-c3J0LYkgYeXQxwnYkEzL15cCFBYPRaYUon8O2SZ6O4PhH4dfFTXBzSyT8+gh8AhBd572l2yGDfxpEYA6pOqdjg==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "d3-interpolate": "^3.0.1",
+ "vega-dataflow": "^5.7.5",
+ "vega-scale": "^7.3.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-event-selector": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-3.0.1.tgz",
+ "integrity": "sha512-K5zd7s5tjr1LiOOkjGpcVls8GsH/f2CWCrWcpKy74gTCp+llCdwz0Enqo013ZlGaRNjfgD/o1caJRt3GSaec4A=="
+ },
+ "vega-expression": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-5.1.0.tgz",
+ "integrity": "sha512-u8Rzja/cn2PEUkhQN3zUj3REwNewTA92ExrcASNKUJPCciMkHJEjESwFYuI6DWMCq4hQElQ92iosOAtwzsSTqA==",
+ "requires": {
+ "@types/estree": "^1.0.0",
+ "vega-util": "^1.17.1"
+ },
+ "dependencies": {
+ "@types/estree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
+ "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA=="
+ }
+ }
+ },
+ "vega-force": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/vega-force/-/vega-force-4.2.0.tgz",
+ "integrity": "sha512-aE2TlP264HXM1r3fl58AvZdKUWBNOGkIvn4EWyqeJdgO2vz46zSU7x7TzPG4ZLuo44cDRU5Ng3I1eQk23Asz6A==",
+ "peer": true,
+ "requires": {
+ "d3-force": "^3.0.0",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-format": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vega-format/-/vega-format-1.1.1.tgz",
+ "integrity": "sha512-Rll7YgpYbsgaAa54AmtEWrxaJqgOh5fXlvM2wewO4trb9vwM53KBv4Q/uBWCLK3LLGeBXIF6gjDt2LFuJAUtkQ==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "d3-format": "^3.1.0",
+ "d3-time-format": "^4.1.0",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-functions": {
+ "version": "5.13.2",
+ "resolved": "https://registry.npmjs.org/vega-functions/-/vega-functions-5.13.2.tgz",
+ "integrity": "sha512-YE1Xl3Qi28kw3vdXVYgKFMo20ttd3+SdKth1jUNtBDGGdrOpvPxxFhZkVqX+7FhJ5/1UkDoAYs/cZY0nRKiYgA==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "d3-color": "^3.1.0",
+ "d3-geo": "^3.1.0",
+ "vega-dataflow": "^5.7.5",
+ "vega-expression": "^5.1.0",
+ "vega-scale": "^7.3.0",
+ "vega-scenegraph": "^4.10.2",
+ "vega-selections": "^5.4.1",
+ "vega-statistics": "^1.8.1",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-geo": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/vega-geo/-/vega-geo-4.4.1.tgz",
+ "integrity": "sha512-s4WeZAL5M3ZUV27/eqSD3v0FyJz3PlP31XNSLFy4AJXHxHUeXT3qLiDHoVQnW5Om+uBCPDtTT1ROx1smGIf2aA==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "d3-color": "^3.1.0",
+ "d3-geo": "^3.1.0",
+ "vega-canvas": "^1.2.7",
+ "vega-dataflow": "^5.7.5",
+ "vega-projection": "^1.6.0",
+ "vega-statistics": "^1.8.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-hierarchy": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/vega-hierarchy/-/vega-hierarchy-4.1.1.tgz",
+ "integrity": "sha512-h5mbrDtPKHBBQ9TYbvEb/bCqmGTlUX97+4CENkyH21tJs7naza319B15KRK0NWOHuhbGhFmF8T0696tg+2c8XQ==",
+ "peer": true,
+ "requires": {
+ "d3-hierarchy": "^3.1.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-label": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/vega-label/-/vega-label-1.2.1.tgz",
+ "integrity": "sha512-n/ackJ5lc0Xs9PInCaGumYn2awomPjJ87EMVT47xNgk2bHmJoZV1Ve/1PUM6Eh/KauY211wPMrNp/9Im+7Ripg==",
+ "peer": true,
+ "requires": {
+ "vega-canvas": "^1.2.6",
+ "vega-dataflow": "^5.7.3",
+ "vega-scenegraph": "^4.9.2",
+ "vega-util": "^1.15.2"
+ }
+ },
+ "vega-lite": {
+ "version": "5.9.0",
+ "resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-5.9.0.tgz",
+ "integrity": "sha512-VA3XDlF6nd/t46KDMfq8eNKOJKy9gpJuM+6CIl3jbWqS97jWXRWXp8DpUyDmbV+iq8n4hqNTaoPqDP/e03kifw==",
+ "requires": {
+ "@types/clone": "~2.1.1",
+ "clone": "~2.1.2",
+ "fast-deep-equal": "~3.1.3",
+ "fast-json-stable-stringify": "~2.1.0",
+ "json-stringify-pretty-compact": "~3.0.0",
+ "tslib": "~2.5.0",
+ "vega-event-selector": "~3.0.1",
+ "vega-expression": "~5.1.0",
+ "vega-util": "~1.17.2",
+ "yargs": "~17.7.1"
+ },
+ "dependencies": {
+ "cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+ },
+ "yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "requires": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
+ }
+ }
+ },
+ "vega-loader": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/vega-loader/-/vega-loader-4.5.1.tgz",
+ "integrity": "sha512-qy5x32SaT0YkEujQM2yKqvLGV9XWQ2aEDSugBFTdYzu/1u4bxdUSRDREOlrJ9Km3RWIOgFiCkobPmFxo47SKuA==",
+ "peer": true,
+ "requires": {
+ "d3-dsv": "^3.0.1",
+ "node-fetch": "^2.6.7",
+ "topojson-client": "^3.1.0",
+ "vega-format": "^1.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-parser": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/vega-parser/-/vega-parser-6.2.0.tgz",
+ "integrity": "sha512-as+QnX8Qxe9q51L1C2sVBd+YYYctP848+zEvkBT2jlI2g30aZ6Uv7sKsq7QTL6DUbhXQKR0XQtzlanckSFdaOQ==",
+ "peer": true,
+ "requires": {
+ "vega-dataflow": "^5.7.5",
+ "vega-event-selector": "^3.0.1",
+ "vega-functions": "^5.13.1",
+ "vega-scale": "^7.3.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-projection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/vega-projection/-/vega-projection-1.6.0.tgz",
+ "integrity": "sha512-LGUaO/kpOEYuTlul+x+lBzyuL9qmMwP1yShdUWYLW+zXoeyGbs5OZW+NbPPwLYqJr5lpXDr/vGztFuA/6g2xvQ==",
+ "peer": true,
+ "requires": {
+ "d3-geo": "^3.1.0",
+ "d3-geo-projection": "^4.0.0",
+ "vega-scale": "^7.3.0"
+ }
+ },
+ "vega-regression": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/vega-regression/-/vega-regression-1.2.0.tgz",
+ "integrity": "sha512-6TZoPlhV/280VbxACjRKqlE0Nv48z5g4CSNf1FmGGTWS1rQtElPTranSoVW4d7ET5eVQ6f9QLxNAiALptvEq+g==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "vega-dataflow": "^5.7.3",
+ "vega-statistics": "^1.9.0",
+ "vega-util": "^1.15.2"
+ }
+ },
+ "vega-runtime": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/vega-runtime/-/vega-runtime-6.1.4.tgz",
+ "integrity": "sha512-0dDYXyFLQcxPQ2OQU0WuBVYLRZnm+/CwVu6i6N4idS7R9VXIX5581EkCh3pZ20pQ/+oaA7oJ0pR9rJgJ6rukRQ==",
+ "peer": true,
+ "requires": {
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-scale": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/vega-scale/-/vega-scale-7.3.0.tgz",
+ "integrity": "sha512-pMOAI2h+e1z7lsqKG+gMfR6NKN2sTcyjZbdJwntooW0uFHwjLGjMSY7kSd3nSEquF0HQ8qF7zR6gs1eRwlGimw==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "d3-interpolate": "^3.0.1",
+ "d3-scale": "^4.0.2",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-scenegraph": {
+ "version": "4.10.2",
+ "resolved": "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-4.10.2.tgz",
+ "integrity": "sha512-R8m6voDZO5+etwNMcXf45afVM3XAtokMqxuDyddRl9l1YqSJfS+3u8hpolJ50c2q6ZN20BQiJwKT1o0bB7vKkA==",
+ "peer": true,
+ "requires": {
+ "d3-path": "^3.1.0",
+ "d3-shape": "^3.2.0",
+ "vega-canvas": "^1.2.7",
+ "vega-loader": "^4.5.1",
+ "vega-scale": "^7.3.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-selections": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/vega-selections/-/vega-selections-5.4.1.tgz",
+ "integrity": "sha512-EtYc4DvA+wXqBg9tq+kDomSoVUPCmQfS7hUxy2qskXEed79YTimt3Hcl1e1fW226I4AVDBEqTTKebmKMzbSgAA==",
+ "peer": true,
+ "requires": {
+ "d3-array": "3.2.2",
+ "vega-expression": "^5.0.1",
+ "vega-util": "^1.17.1"
+ },
+ "dependencies": {
+ "d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ==",
+ "peer": true,
+ "requires": {
+ "internmap": "1 - 2"
+ }
+ }
+ }
+ },
+ "vega-statistics": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/vega-statistics/-/vega-statistics-1.9.0.tgz",
+ "integrity": "sha512-GAqS7mkatpXcMCQKWtFu1eMUKLUymjInU0O8kXshWaQrVWjPIO2lllZ1VNhdgE0qGj4oOIRRS11kzuijLshGXQ==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2"
+ }
+ },
+ "vega-time": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/vega-time/-/vega-time-2.1.1.tgz",
+ "integrity": "sha512-z1qbgyX0Af2kQSGFbApwBbX2meenGvsoX8Nga8uyWN8VIbiySo/xqizz1KrP6NbB6R+x5egKmkjdnyNThPeEWA==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "d3-time": "^3.1.0",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-transforms": {
+ "version": "4.10.2",
+ "resolved": "https://registry.npmjs.org/vega-transforms/-/vega-transforms-4.10.2.tgz",
+ "integrity": "sha512-sJELfEuYQ238PRG+GOqQch8D69RYnJevYSGLsRGQD2LxNz3j+GlUX6Pid+gUEH5HJy22Q5L0vsTl2ZNhIr4teQ==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-statistics": "^1.8.1",
+ "vega-time": "^2.1.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-typings": {
+ "version": "0.24.1",
+ "resolved": "https://registry.npmjs.org/vega-typings/-/vega-typings-0.24.1.tgz",
+ "integrity": "sha512-WNw6tDxwMsynQ9osJb3RZi3g8GZruxVgXfe8N7nbqvNOgDQkUuVjqTZiwGg5kqjmLqx09lRRlskgp/ov7lEGeg==",
+ "peer": true,
+ "requires": {
+ "@types/geojson": "7946.0.4",
+ "vega-event-selector": "^3.0.1",
+ "vega-expression": "^5.0.1",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-util": {
+ "version": "1.17.2",
+ "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-1.17.2.tgz",
+ "integrity": "sha512-omNmGiZBdjm/jnHjZlywyYqafscDdHaELHx1q96n5UOz/FlO9JO99P4B3jZg391EFG8dqhWjQilSf2JH6F1mIw=="
+ },
+ "vega-view": {
+ "version": "5.11.1",
+ "resolved": "https://registry.npmjs.org/vega-view/-/vega-view-5.11.1.tgz",
+ "integrity": "sha512-RoWxuoEMI7xVQJhPqNeLEHCezudsf3QkVMhH5tCovBqwBADQGqq9iWyax3ZzdyX1+P3eBgm7cnLvpqtN2hU8kA==",
+ "peer": true,
+ "requires": {
+ "d3-array": "^3.2.2",
+ "d3-timer": "^3.0.1",
+ "vega-dataflow": "^5.7.5",
+ "vega-format": "^1.1.1",
+ "vega-functions": "^5.13.1",
+ "vega-runtime": "^6.1.4",
+ "vega-scenegraph": "^4.10.2",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-view-transforms": {
+ "version": "4.5.9",
+ "resolved": "https://registry.npmjs.org/vega-view-transforms/-/vega-view-transforms-4.5.9.tgz",
+ "integrity": "sha512-NxEq4ZD4QwWGRrl2yDLnBRXM9FgCI+vvYb3ZC2+nVDtkUxOlEIKZsMMw31op5GZpfClWLbjCT3mVvzO2xaTF+g==",
+ "peer": true,
+ "requires": {
+ "vega-dataflow": "^5.7.5",
+ "vega-scenegraph": "^4.10.2",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-voronoi": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/vega-voronoi/-/vega-voronoi-4.2.1.tgz",
+ "integrity": "sha512-zzi+fxU/SBad4irdLLsG3yhZgXWZezraGYVQfZFWe8kl7W/EHUk+Eqk/eetn4bDeJ6ltQskX+UXH3OP5Vh0Q0Q==",
+ "peer": true,
+ "requires": {
+ "d3-delaunay": "^6.0.2",
+ "vega-dataflow": "^5.7.5",
+ "vega-util": "^1.17.1"
+ }
+ },
+ "vega-wordcloud": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/vega-wordcloud/-/vega-wordcloud-4.1.4.tgz",
+ "integrity": "sha512-oeZLlnjiusLAU5vhk0IIdT5QEiJE0x6cYoGNq1th+EbwgQp153t4r026fcib9oq15glHFOzf81a8hHXHSJm1Jw==",
+ "peer": true,
+ "requires": {
+ "vega-canvas": "^1.2.7",
+ "vega-dataflow": "^5.7.5",
+ "vega-scale": "^7.3.0",
+ "vega-statistics": "^1.8.1",
+ "vega-util": "^1.17.1"
+ }
+ },
"vlq": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
@@ -18280,8 +19700,7 @@
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
- "dev": true
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-encoding": {
"version": "1.0.5",
@@ -18313,7 +19732,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dev": true,
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
diff --git a/ui/package.json b/ui/package.json
index 0f4d69bb4..1257ab7b2 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -30,7 +30,8 @@
"pako": "^1.0.11",
"protobufjs": "^6.9.0",
"util": "^0.12.3",
- "uuid": "^9.0.0"
+ "uuid": "^9.0.0",
+ "vega-lite": "^5.9.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.1",
diff --git a/ui/release/channels.json b/ui/release/channels.json
index fb05de45d..09f14f427 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -2,11 +2,11 @@
"channels": [
{
"name": "stable",
- "rev": "1f0f1aa6babb0b3ff273c5102aa677b2604e9a4e"
+ "rev": "1b8de44522f33d371def110325bf31b847c1f5c4"
},
{
"name": "canary",
- "rev": "056cc57893b57b82ed411256c2bd4091641f55fb"
+ "rev": "a34bc46479e2e659532f7e208c6eba5462c26bae"
},
{
"name": "autopush",
diff --git a/ui/src/assets/common.scss b/ui/src/assets/common.scss
index 79ba00752..043542250 100644
--- a/ui/src/assets/common.scss
+++ b/ui/src/assets/common.scss
@@ -42,17 +42,14 @@
}
@mixin track_shell_title() {
- // line-height is deliberately 1px larger than font-size. Roboto seems to
- // overflow on the bottom on "g"s otherwise.
font-size: 14px;
- line-height: 15px;
max-height: 30px;
overflow: hidden;
text-align: left;
overflow-wrap: break-word;
font-family: "Roboto Condensed", sans-serif;
font-weight: 300;
- letter-spacing: -0.5px;
+ line-break: anywhere;
}
* {
@@ -388,6 +385,7 @@ $bottom-tab-padding: 10px;
width: var(--track-shell-width);
background: #fff;
border-right: 1px solid #c7d0db;
+ overflow: hidden;
&.drag {
background-color: #eee;
@@ -462,7 +460,7 @@ $bottom-tab-padding: 10px;
.scrolling-panel-container {
position: relative;
overflow-x: hidden;
- overflow-y: auto;
+ overflow-y: scroll; // Always show vertical scrollbar
flex: 1 1 auto;
will-change: transform; // Force layer creation.
display: grid;
diff --git a/ui/src/assets/details.scss b/ui/src/assets/details.scss
index 9ba93b3b9..b5c131b86 100644
--- a/ui/src/assets/details.scss
+++ b/ui/src/assets/details.scss
@@ -293,6 +293,7 @@
.details-table-multicolumn {
display: flex;
+ user-select: 'text';
}
.flow-link:hover {
diff --git a/ui/src/assets/perfetto.scss b/ui/src/assets/perfetto.scss
index 7a0057618..e4da14727 100644
--- a/ui/src/assets/perfetto.scss
+++ b/ui/src/assets/perfetto.scss
@@ -38,3 +38,4 @@
@import "widgets/spinner";
@import "widgets/tree";
@import "widgets/switch";
+@import "widgets/form";
diff --git a/ui/src/assets/record.scss b/ui/src/assets/record.scss
index e4820d8c4..187499f6e 100644
--- a/ui/src/assets/record.scss
+++ b/ui/src/assets/record.scss
@@ -399,6 +399,8 @@
line-height: 12.5px;
margin-top: -5px;
opacity: 0;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
&:hover {
diff --git a/ui/src/base/math_utils.ts b/ui/src/assets/widgets/form.scss
index f1c18165b..569df72fc 100644
--- a/ui/src/base/math_utils.ts
+++ b/ui/src/assets/widgets/form.scss
@@ -12,12 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Round a number up to the nearest stepsize.
-export function roundUpNearest(val: number, stepsize: number): number {
- return stepsize * Math.ceil(val / stepsize);
-}
+.pf-form {
+ display: grid;
+ grid-template-columns: auto auto;
+ margin: 6px;
+ row-gap: 8px;
+ column-gap: 8px;
+
+ .pf-form-button-bar {
+ grid-column: span 2;
+ margin-top: 6px;
+ display: flex;
+ justify-content: right;
+ flex-direction: row-reverse;
+ align-items: center;
+
+ .pf-button {
+ margin-right: 4px;
+ }
+ }
-// Round a number down to the nearest stepsize.
-export function roundDownNearest(val: number, stepsize: number): number {
- return stepsize * Math.floor(val / stepsize);
+ .pf-form-label {
+ font-weight: 600;
+ }
}
diff --git a/ui/src/assets/widgets/menu.scss b/ui/src/assets/widgets/menu.scss
index e161d4cab..5bc6a9f55 100644
--- a/ui/src/assets/widgets/menu.scss
+++ b/ui/src/assets/widgets/menu.scss
@@ -22,10 +22,10 @@
.pf-menu-item {
font-family: $pf-font;
- font-size: inherit;
+ font-size: 14px;
user-select: none;
text-align: left;
- padding: 6px 12px;
+ padding: 5px 10px;
white-space: nowrap;
min-width: max-content;
cursor: pointer;
diff --git a/ui/src/base/bigint_math.ts b/ui/src/base/bigint_math.ts
new file mode 100644
index 000000000..1860afedd
--- /dev/null
+++ b/ui/src/base/bigint_math.ts
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export class BigintMath {
+ static INT64_MAX: bigint = (2n ** 63n) - 1n;
+
+ // Returns the smallest integral power of 2 that is not smaller than n.
+ // If n is less than or equal to 0, returns 1.
+ static bitCeil(n: bigint): bigint {
+ let result = 1n;
+ while (result < n) {
+ result <<= 1n;
+ }
+ return result;
+ };
+
+ // Returns the largest integral power of 2 which is not greater than n.
+ // If n is less than or equal to 0, returns 1.
+ static bitFloor(n: bigint): bigint {
+ let result = 1n;
+ while ((result << 1n) <= n) {
+ result <<= 1n;
+ }
+ return result;
+ };
+
+ // Returns the largest integral multiple of step which is not larger than n.
+ // If step is less than or equal to 0, returns n.
+ static quantizeFloor(n: bigint, step: bigint): bigint {
+ step = BigintMath.max(1n, step);
+ return step * (n / step);
+ }
+
+ // Return the integral multiple of step which is closest to n.
+ // If step is less than or equal to 0, returns n.
+ static quantize(n: bigint, step: bigint): bigint {
+ step = BigintMath.max(1n, step);
+ const halfStep = step / 2n;
+ return step * ((n + halfStep) / step);
+ }
+
+ // Return the greater of a and b
+ static max(a: bigint, b: bigint): bigint {
+ return a > b ? a : b;
+ }
+
+ // Return the smaller of a and b
+ static min(a: bigint, b: bigint): bigint {
+ return a < b ? a : b;
+ }
+
+ // Returns the number of 1 bits in n
+ static popcount(n: bigint): number {
+ if (n < 0n) {
+ throw Error(`Can\'t get popcount of negative number ${n}`);
+ }
+ let count = 0;
+ while (n) {
+ if (n & 1n) {
+ ++count;
+ }
+ n >>= 1n;
+ }
+ return count;
+ }
+}
diff --git a/ui/src/base/bigint_math_unittest.ts b/ui/src/base/bigint_math_unittest.ts
new file mode 100644
index 000000000..291eb32ad
--- /dev/null
+++ b/ui/src/base/bigint_math_unittest.ts
@@ -0,0 +1,141 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {
+ BigintMath as BIM,
+} from './bigint_math';
+
+describe('BigIntMath.bitCeil', () => {
+ it('rounds powers of 2 to themselves', () => {
+ expect(BIM.bitCeil(1n)).toBe(1n);
+ expect(BIM.bitCeil(2n)).toBe(2n);
+ expect(BIM.bitCeil(4n)).toBe(4n);
+ expect(BIM.bitCeil(4294967296n)).toBe(4294967296n);
+ expect(BIM.bitCeil(2305843009213693952n)).toBe(2305843009213693952n);
+ });
+
+ it('rounds non powers of 2 up to nearest power of 2', () => {
+ expect(BIM.bitCeil(3n)).toBe(4n);
+ expect(BIM.bitCeil(11n)).toBe(16n);
+ expect(BIM.bitCeil(33n)).toBe(64n);
+ expect(BIM.bitCeil(63n)).toBe(64n);
+ expect(BIM.bitCeil(1234567890123456789n)).toBe(2305843009213693952n);
+ });
+
+ it('rounds 0 or negative values up to 1', () => {
+ expect(BIM.bitCeil(0n)).toBe(1n);
+ expect(BIM.bitCeil(-123n)).toBe(1n);
+ });
+});
+
+describe('BigIntMath.bigFloor', () => {
+ it('rounds powers of 2 to themselves', () => {
+ expect(BIM.bitFloor(1n)).toBe(1n);
+ expect(BIM.bitFloor(2n)).toBe(2n);
+ expect(BIM.bitFloor(4n)).toBe(4n);
+ expect(BIM.bitFloor(4294967296n)).toBe(4294967296n);
+ expect(BIM.bitFloor(2305843009213693952n)).toBe(2305843009213693952n);
+ });
+
+ it('rounds non powers of 2 down to nearest power of 2', () => {
+ expect(BIM.bitFloor(3n)).toBe(2n);
+ expect(BIM.bitFloor(11n)).toBe(8n);
+ expect(BIM.bitFloor(33n)).toBe(32n);
+ expect(BIM.bitFloor(63n)).toBe(32n);
+ expect(BIM.bitFloor(1234567890123456789n)).toBe(1152921504606846976n);
+ });
+
+ it('rounds 0 or negative values up to 1', () => {
+ expect(BIM.bitFloor(0n)).toBe(1n);
+ expect(BIM.bitFloor(-123n)).toBe(1n);
+ });
+});
+
+describe('quantize', () => {
+ it('should quantize a number to the nearest multiple of a stepsize', () => {
+ expect(BIM.quantizeFloor(10n, 2n)).toEqual(10n);
+ expect(BIM.quantizeFloor(11n, 2n)).toEqual(10n);
+ expect(BIM.quantizeFloor(12n, 2n)).toEqual(12n);
+ expect(BIM.quantizeFloor(13n, 2n)).toEqual(12n);
+
+ expect(BIM.quantizeFloor(9n, 4n)).toEqual(8n);
+ expect(BIM.quantizeFloor(10n, 4n)).toEqual(8n);
+ expect(BIM.quantizeFloor(11n, 4n)).toEqual(8n);
+ expect(BIM.quantizeFloor(12n, 4n)).toEqual(12n);
+ expect(BIM.quantizeFloor(13n, 4n)).toEqual(12n);
+ });
+
+ it('should return value if stepsize is smaller than 1', () => {
+ expect(BIM.quantizeFloor(123n, 0n)).toEqual(123n);
+ expect(BIM.quantizeFloor(123n, -10n)).toEqual(123n);
+ });
+});
+
+describe('quantizeRound', () => {
+ it('should quantize a number to the nearest multiple of a stepsize', () => {
+ expect(BIM.quantize(0n, 2n)).toEqual(0n);
+ expect(BIM.quantize(1n, 2n)).toEqual(2n);
+ expect(BIM.quantize(2n, 2n)).toEqual(2n);
+ expect(BIM.quantize(3n, 2n)).toEqual(4n);
+ expect(BIM.quantize(4n, 2n)).toEqual(4n);
+
+ expect(BIM.quantize(0n, 3n)).toEqual(0n);
+ expect(BIM.quantize(1n, 3n)).toEqual(0n);
+ expect(BIM.quantize(2n, 3n)).toEqual(3n);
+ expect(BIM.quantize(3n, 3n)).toEqual(3n);
+ expect(BIM.quantize(4n, 3n)).toEqual(3n);
+ expect(BIM.quantize(5n, 3n)).toEqual(6n);
+ expect(BIM.quantize(6n, 3n)).toEqual(6n);
+ });
+
+ it('should return value if stepsize is smaller than 1', () => {
+ expect(BIM.quantize(123n, 0n)).toEqual(123n);
+ expect(BIM.quantize(123n, -10n)).toEqual(123n);
+ });
+});
+
+describe('max', () => {
+ it('should return the greater of two numbers', () => {
+ expect(BIM.max(5n, 8n)).toEqual(8n);
+ expect(BIM.max(3n, 7n)).toEqual(7n);
+ expect(BIM.max(6n, 6n)).toEqual(6n);
+ expect(BIM.max(-7n, -12n)).toEqual(-7n);
+ });
+});
+
+describe('min', () => {
+ it('should return the smaller of two numbers', () => {
+ expect(BIM.min(5n, 8n)).toEqual(5n);
+ expect(BIM.min(3n, 7n)).toEqual(3n);
+ expect(BIM.min(6n, 6n)).toEqual(6n);
+ expect(BIM.min(-7n, -12n)).toEqual(-12n);
+ });
+});
+
+describe('popcount', () => {
+ it('should return the number of set bits in an integer', () => {
+ expect(BIM.popcount(0n)).toBe(0);
+ expect(BIM.popcount(1n)).toBe(1);
+ expect(BIM.popcount(2n)).toBe(1);
+ expect(BIM.popcount(3n)).toBe(2);
+ expect(BIM.popcount(4n)).toBe(1);
+ expect(BIM.popcount(5n)).toBe(2);
+ expect(BIM.popcount(3462151285050974216n)).toBe(10);
+ });
+
+ it('should throw when presented with a negative integer', () => {
+ expect(() => BIM.popcount(-1n))
+ .toThrowError('Can\'t get popcount of negative number -1');
+ });
+});
diff --git a/ui/src/base/math_utils_unittest.ts b/ui/src/base/math_utils_unittest.ts
deleted file mode 100644
index 169b793e8..000000000
--- a/ui/src/base/math_utils_unittest.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2023 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import {roundDownNearest, roundUpNearest} from './math_utils';
-
-describe('roundUpNearest()', () => {
- it('rounds decimal values up to the right step size', () => {
- expect(roundUpNearest(0.1, 0.5)).toBeCloseTo(0.5);
- expect(roundUpNearest(17.2, 0.5)).toBeCloseTo(17.5);
- });
-});
-
-describe('roundDownNearest()', () => {
- it('rounds decimal values down to the right step size', () => {
- expect(roundDownNearest(0.4, 0.5)).toBeCloseTo(0.0);
- expect(roundDownNearest(17.4, 0.5)).toBeCloseTo(17.0);
- });
-});
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index 1e602fcd7..286f82f72 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -61,7 +61,7 @@ import {
UtidToTrackSortKey,
VisibleState,
} from './state';
-import {toNs} from './time';
+import {TPDuration, TPTime} from './time';
export const DEBUG_SLICE_TRACK_KIND = 'DebugSliceTrack';
@@ -89,8 +89,8 @@ export interface PostedTrace {
}
export interface PostedScrollToRange {
- timeStart: number;
- timeEnd: number;
+ timeStart: TPTime;
+ timeEnd: TPTime;
viewPercentage?: number;
}
@@ -552,7 +552,7 @@ export const StateActions = {
addAutomaticNote(
state: StateDraft,
- args: {timestamp: number, color: string, text: string}): void {
+ args: {timestamp: TPTime, color: string, text: string}): void {
const id = generateNextId(state);
state.notes[id] = {
noteType: 'DEFAULT',
@@ -563,7 +563,7 @@ export const StateActions = {
};
},
- addNote(state: StateDraft, args: {timestamp: number, color: string}): void {
+ addNote(state: StateDraft, args: {timestamp: TPTime, color: string}): void {
const id = generateNextId(state);
state.notes[id] = {
noteType: 'DEFAULT',
@@ -606,14 +606,10 @@ export const StateActions = {
},
markArea(state: StateDraft, args: {area: Area, persistent: boolean}): void {
+ const {start, end, tracks} = args.area;
+ assertTrue(start <= end);
const areaId = generateNextId(state);
- assertTrue(args.area.endSec >= args.area.startSec);
- state.areas[areaId] = {
- id: areaId,
- startSec: args.area.startSec,
- endSec: args.area.endSec,
- tracks: args.area.tracks,
- };
+ state.areas[areaId] = {id: areaId, start, end, tracks};
const noteId = args.persistent ? generateNextId(state) : '0';
const color = args.persistent ? randomColor() : '#344596';
state.notes[noteId] = {
@@ -667,7 +663,7 @@ export const StateActions = {
selectCounter(
state: StateDraft,
- args: {leftTs: number, rightTs: number, id: number, trackId: string}):
+ args: {leftTs: TPTime, rightTs: TPTime, id: number, trackId: string}):
void {
state.currentSelection = {
kind: 'COUNTER',
@@ -680,7 +676,7 @@ export const StateActions = {
selectHeapProfile(
state: StateDraft,
- args: {id: number, upid: number, ts: number, type: ProfileType}): void {
+ args: {id: number, upid: number, ts: TPTime, type: ProfileType}): void {
state.currentSelection = {
kind: 'HEAP_PROFILE',
id: args.id,
@@ -690,8 +686,8 @@ export const StateActions = {
};
this.openFlamegraph(state, {
type: args.type,
- startNs: toNs(state.traceTime.startSec),
- endNs: args.ts,
+ start: state.traceTime.start,
+ end: args.ts,
upids: [args.upid],
viewingOption: DEFAULT_VIEWING_OPTION,
});
@@ -700,8 +696,8 @@ export const StateActions = {
selectPerfSamples(state: StateDraft, args: {
id: number,
upid: number,
- leftTs: number,
- rightTs: number,
+ leftTs: TPTime,
+ rightTs: TPTime,
type: ProfileType
}): void {
state.currentSelection = {
@@ -714,8 +710,8 @@ export const StateActions = {
};
this.openFlamegraph(state, {
type: args.type,
- startNs: args.leftTs,
- endNs: args.rightTs,
+ start: args.leftTs,
+ end: args.rightTs,
upids: [args.upid],
viewingOption: PERF_SAMPLES_KEY,
});
@@ -723,16 +719,16 @@ export const StateActions = {
openFlamegraph(state: StateDraft, args: {
upids: number[],
- startNs: number,
- endNs: number,
+ start: TPTime,
+ end: TPTime,
type: ProfileType,
viewingOption: FlamegraphStateViewingOption
}): void {
state.currentFlamegraphState = {
kind: 'FLAMEGRAPH_STATE',
upids: args.upids,
- startNs: args.startNs,
- endNs: args.endNs,
+ start: args.start,
+ end: args.end,
type: args.type,
viewingOption: args.viewingOption,
focusRegex: '',
@@ -784,16 +780,33 @@ export const StateActions = {
selectDebugSlice(state: StateDraft, args: {
id: number,
sqlTableName: string,
- startS: number,
- durationS: number,
+ start: TPTime,
+ duration: TPDuration,
trackId: string,
}): void {
state.currentSelection = {
kind: 'DEBUG_SLICE',
id: args.id,
sqlTableName: args.sqlTableName,
- startS: args.startS,
- durationS: args.durationS,
+ start: args.start,
+ duration: args.duration,
+ trackId: args.trackId,
+ };
+ },
+
+ selectTopLevelScrollSlice(state: StateDraft, args: {
+ id: number,
+ sqlTableName: string,
+ start: TPTime,
+ duration: TPTime,
+ trackId: string,
+ }): void {
+ state.currentSelection = {
+ kind: 'TOP_LEVEL_SCROLL',
+ id: args.id,
+ sqlTableName: args.sqlTableName,
+ start: args.start,
+ duration: args.duration,
trackId: args.trackId,
};
},
@@ -893,25 +906,17 @@ export const StateActions = {
},
selectArea(state: StateDraft, args: {area: Area}): void {
+ const {start, end, tracks} = args.area;
+ assertTrue(start <= end);
const areaId = generateNextId(state);
- assertTrue(args.area.endSec >= args.area.startSec);
- state.areas[areaId] = {
- id: areaId,
- startSec: args.area.startSec,
- endSec: args.area.endSec,
- tracks: args.area.tracks,
- };
+ state.areas[areaId] = {id: areaId, start, end, tracks};
state.currentSelection = {kind: 'AREA', areaId};
},
editArea(state: StateDraft, args: {area: Area, areaId: string}): void {
- assertTrue(args.area.endSec >= args.area.startSec);
- state.areas[args.areaId] = {
- id: args.areaId,
- startSec: args.area.startSec,
- endSec: args.area.endSec,
- tracks: args.area.tracks,
- };
+ const {start, end, tracks} = args.area;
+ assertTrue(start <= end);
+ state.areas[args.areaId] = {id: args.areaId, start, end, tracks};
},
reSelectArea(state: StateDraft, args: {areaId: string, noteId: string}):
@@ -1031,11 +1036,11 @@ export const StateActions = {
state.searchIndex = args.index;
},
- setHoverCursorTimestamp(state: StateDraft, args: {ts: number}) {
+ setHoverCursorTimestamp(state: StateDraft, args: {ts: TPTime}) {
state.hoverCursorTimestamp = args.ts;
},
- setHoveredNoteTimestamp(state: StateDraft, args: {ts: number}) {
+ setHoveredNoteTimestamp(state: StateDraft, args: {ts: TPTime}) {
state.hoveredNoteTimestamp = args.ts;
},
diff --git a/ui/src/common/actions_unittest.ts b/ui/src/common/actions_unittest.ts
index 6702e723c..b613777a0 100644
--- a/ui/src/common/actions_unittest.ts
+++ b/ui/src/common/actions_unittest.ts
@@ -446,9 +446,13 @@ test('perf samples open flamegraph', () => {
const state = createEmptyState();
const afterSelectingPerf = produce(state, (draft) => {
- StateActions.selectPerfSamples(
- draft,
- {id: 0, upid: 0, leftTs: 0, rightTs: 0, type: ProfileType.PERF_SAMPLE});
+ StateActions.selectPerfSamples(draft, {
+ id: 0,
+ upid: 0,
+ leftTs: 0n,
+ rightTs: 0n,
+ type: ProfileType.PERF_SAMPLE,
+ });
});
expect(assertExists(afterSelectingPerf.currentFlamegraphState).type)
@@ -460,7 +464,7 @@ test('heap profile opens flamegraph', () => {
const afterSelectingPerf = produce(state, (draft) => {
StateActions.selectHeapProfile(
- draft, {id: 0, upid: 0, ts: 0, type: ProfileType.JAVA_HEAP_GRAPH});
+ draft, {id: 0, upid: 0, ts: 0n, type: ProfileType.JAVA_HEAP_GRAPH});
});
expect(assertExists(afterSelectingPerf.currentFlamegraphState).type)
diff --git a/ui/src/common/canvas_utils.ts b/ui/src/common/canvas_utils.ts
index aef36a0dd..d086f5b6b 100644
--- a/ui/src/common/canvas_utils.ts
+++ b/ui/src/common/canvas_utils.ts
@@ -86,5 +86,11 @@ export function drawIncompleteSlice(
ctx.lineTo(x + width - 3, y + (triangleSize * 3.5));
ctx.lineTo(x + width, y + 4 * triangleSize);
ctx.lineTo(x, y + height);
+
+ const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
+ gradient.addColorStop(0.66, ctx.fillStyle as string);
+ gradient.addColorStop(1, '#FFFFFF');
+ ctx.fillStyle = gradient;
+
ctx.fill();
}
diff --git a/ui/src/common/empty_state.ts b/ui/src/common/empty_state.ts
index bd1e6b6d6..6d806a298 100644
--- a/ui/src/common/empty_state.ts
+++ b/ui/src/common/empty_state.ts
@@ -110,7 +110,7 @@ export function createEmptyState(): State {
visibleState: {
...defaultTraceTime,
lastUpdate: 0,
- resolution: 0,
+ resolution: 0n,
},
},
@@ -142,8 +142,8 @@ export function createEmptyState(): State {
sidebarVisible: true,
hoveredUtid: -1,
hoveredPid: -1,
- hoverCursorTimestamp: -1,
- hoveredNoteTimestamp: -1,
+ hoverCursorTimestamp: -1n,
+ hoveredNoteTimestamp: -1n,
highlightedSliceId: -1,
focusedFlowIdLeft: -1,
focusedFlowIdRight: -1,
diff --git a/ui/src/common/engine.ts b/ui/src/common/engine.ts
index 8b6cb465c..861601fe7 100644
--- a/ui/src/common/engine.ts
+++ b/ui/src/common/engine.ts
@@ -24,18 +24,20 @@ import {
QueryArgs,
ResetTraceProcessorArgs,
} from './protos';
-import {NUM, NUM_NULL, STR} from './query_result';
+import {LONG, LONG_NULL, NUM, STR} from './query_result';
import {
createQueryResult,
QueryError,
QueryResult,
WritableQueryResult,
} from './query_result';
-import {TimeSpan} from './time';
+import {TPTime, TPTimeSpan} from './time';
import TraceProcessorRpc = perfetto.protos.TraceProcessorRpc;
import TraceProcessorRpcStream = perfetto.protos.TraceProcessorRpcStream;
import TPM = perfetto.protos.TraceProcessorRpc.TraceProcessorMethod;
+import {Span} from '../common/time';
+import {BigintMath} from '../base/bigint_math';
export interface LoadingTracker {
beginLoading(): void;
@@ -410,38 +412,38 @@ export abstract class Engine {
return result.firstRow({cnt: NUM}).cnt;
}
- async getTraceTimeBounds(): Promise<TimeSpan> {
+ async getTraceTimeBounds(): Promise<Span<TPTime>> {
const result = await this.query(
`select start_ts as startTs, end_ts as endTs from trace_bounds`);
const bounds = result.firstRow({
- startTs: NUM,
- endTs: NUM,
+ startTs: LONG,
+ endTs: LONG,
});
- return new TimeSpan(bounds.startTs / 1e9, bounds.endTs / 1e9);
+ return new TPTimeSpan(bounds.startTs, bounds.endTs);
}
- async getTracingMetadataTimeBounds(): Promise<TimeSpan> {
+ async getTracingMetadataTimeBounds(): Promise<Span<TPTime>> {
const queryRes = await this.query(`select
name,
int_value as intValue
from metadata
where name = 'tracing_started_ns' or name = 'tracing_disabled_ns'
or name = 'all_data_source_started_ns'`);
- let startBound = -Infinity;
- let endBound = Infinity;
- const it = queryRes.iter({'name': STR, 'intValue': NUM_NULL});
+ let startBound = 0n;
+ let endBound = BigintMath.INT64_MAX;
+ const it = queryRes.iter({'name': STR, 'intValue': LONG_NULL});
for (; it.valid(); it.next()) {
const columnName = it.name;
const timestamp = it.intValue;
if (timestamp === null) continue;
if (columnName === 'tracing_disabled_ns') {
- endBound = Math.min(endBound, timestamp / 1e9);
+ endBound = BigintMath.min(endBound, timestamp);
} else {
- startBound = Math.max(startBound, timestamp / 1e9);
+ startBound = BigintMath.max(startBound, timestamp);
}
}
- return new TimeSpan(startBound, endBound);
+ return new TPTimeSpan(startBound, endBound);
}
getProxy(tag: string): EngineProxy {
diff --git a/ui/src/common/high_precision_time.ts b/ui/src/common/high_precision_time.ts
new file mode 100644
index 000000000..927b7df0c
--- /dev/null
+++ b/ui/src/common/high_precision_time.ts
@@ -0,0 +1,258 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {assertTrue} from '../base/logging';
+import {Span, TPTime} from './time';
+
+export type RoundMode = 'round'|'floor'|'ceil';
+
+// Stores a time as a bigint and an offset which is capable of:
+// - Storing and reproducing "TPTime"s without losing precision.
+// - Storing time with sub-nanosecond precision.
+// This class is immutable - each operation returns a new object.
+export class HighPrecisionTime {
+ // Time in nanoseconds == base + offset
+ // offset is kept in the range 0 <= x < 1 to avoid losing precision
+ readonly base: bigint;
+ readonly offset: number;
+
+ static get ZERO(): HighPrecisionTime {
+ return new HighPrecisionTime(0n);
+ }
+
+ constructor(base: bigint = 0n, offset: number = 0) {
+ // Normalize offset to sit in the range 0.0 <= x < 1.0
+ const offsetFloor = Math.floor(offset);
+ this.base = base + BigInt(offsetFloor);
+ this.offset = offset - offsetFloor;
+ }
+
+ static fromTPTime(timestamp: TPTime): HighPrecisionTime {
+ return new HighPrecisionTime(timestamp, 0);
+ }
+
+ static fromNanos(nanos: number|bigint) {
+ if (typeof nanos === 'number') {
+ return new HighPrecisionTime(0n, nanos);
+ } else if (typeof nanos === 'bigint') {
+ return new HighPrecisionTime(nanos);
+ } else {
+ const value: never = nanos;
+ throw new Error(`Value ${value} is neither a number nor a bigint`);
+ }
+ }
+
+ static fromSeconds(seconds: number) {
+ const nanos = seconds * 1e9;
+ const offset = nanos - Math.floor(nanos);
+ return new HighPrecisionTime(BigInt(Math.floor(nanos)), offset);
+ }
+
+ static max(a: HighPrecisionTime, b: HighPrecisionTime): HighPrecisionTime {
+ return a.isGreaterThan(b) ? a : b;
+ }
+
+ static min(a: HighPrecisionTime, b: HighPrecisionTime): HighPrecisionTime {
+ return a.isLessThan(b) ? a : b;
+ }
+
+ toTPTime(roundMode: RoundMode = 'floor'): TPTime {
+ switch (roundMode) {
+ case 'round':
+ return this.base + BigInt(Math.round(this.offset));
+ case 'floor':
+ return this.base;
+ case 'ceil':
+ return this.base + BigInt(Math.ceil(this.offset));
+ default:
+ const exhaustiveCheck: never = roundMode;
+ throw new Error(`Unhandled roundMode case: ${exhaustiveCheck}`);
+ }
+ }
+
+ get nanos(): number {
+ // WARNING: Number(bigint) can be surprisingly slow.
+ // WARNING: Precision may be lost here.
+ return Number(this.base) + this.offset;
+ }
+
+ get seconds(): number {
+ // WARNING: Number(bigint) can be surprisingly slow.
+ // WARNING: Precision may be lost here.
+ return (Number(this.base) + this.offset) / 1e9;
+ }
+
+ add(other: HighPrecisionTime): HighPrecisionTime {
+ return new HighPrecisionTime(
+ this.base + other.base, this.offset + other.offset);
+ }
+
+ addNanos(nanos: number|bigint): HighPrecisionTime {
+ return this.add(HighPrecisionTime.fromNanos(nanos));
+ }
+
+ addSeconds(seconds: number): HighPrecisionTime {
+ return new HighPrecisionTime(this.base, this.offset + seconds * 1e9);
+ }
+
+ addTPTime(ts: TPTime): HighPrecisionTime {
+ return new HighPrecisionTime(this.base + ts, this.offset);
+ }
+
+ subtract(other: HighPrecisionTime): HighPrecisionTime {
+ return new HighPrecisionTime(
+ this.base - other.base, this.offset - other.offset);
+ }
+
+ subtractTPTime(ts: TPTime): HighPrecisionTime {
+ return this.addTPTime(-ts);
+ }
+
+ subtractNanos(nanos: number|bigint): HighPrecisionTime {
+ return this.add(HighPrecisionTime.fromNanos(-nanos));
+ }
+
+ divide(divisor: number): HighPrecisionTime {
+ return this.multiply(1 / divisor);
+ }
+
+ multiply(factor: number): HighPrecisionTime {
+ const factorFloor = Math.floor(factor);
+ const newBase = this.base * BigInt(factorFloor);
+ const additionalBit = Number(this.base) * (factor - factorFloor);
+ const newOffset = factor * this.offset + additionalBit;
+ return new HighPrecisionTime(newBase, newOffset);
+ }
+
+ // Return true if other time is within some epsilon, default 1 femtosecond
+ equals(other: HighPrecisionTime, epsilon: number = 1e-6): boolean {
+ return Math.abs(this.subtract(other).nanos) < epsilon;
+ }
+
+ isLessThan(other: HighPrecisionTime): boolean {
+ if (this.base < other.base) {
+ return true;
+ } else if (this.base === other.base) {
+ return this.offset < other.offset;
+ } else {
+ return false;
+ }
+ }
+
+ isLessThanOrEqual(other: HighPrecisionTime): boolean {
+ if (this.equals(other)) {
+ return true;
+ } else {
+ return this.isLessThan(other);
+ }
+ }
+
+ isGreaterThan(other: HighPrecisionTime): boolean {
+ return !this.isLessThanOrEqual(other);
+ }
+
+ isGreaterThanOrEqual(other: HighPrecisionTime): boolean {
+ return !this.isLessThan(other);
+ }
+
+ clamp(lower: HighPrecisionTime, upper: HighPrecisionTime): HighPrecisionTime {
+ if (this.isLessThan(lower)) {
+ return lower;
+ } else if (this.isGreaterThan(upper)) {
+ return upper;
+ } else {
+ return this;
+ }
+ }
+
+ toString(): string {
+ const offsetAsString = this.offset.toString();
+ if (offsetAsString === '0') {
+ return this.base.toString();
+ } else {
+ return `${this.base}${offsetAsString.substring(1)}`;
+ }
+ }
+}
+
+export class HighPrecisionTimeSpan implements Span<HighPrecisionTime> {
+ readonly start: HighPrecisionTime;
+ readonly end: HighPrecisionTime;
+
+ constructor(start: TPTime|HighPrecisionTime, end: TPTime|HighPrecisionTime) {
+ this.start = (start instanceof HighPrecisionTime) ?
+ start :
+ HighPrecisionTime.fromTPTime(start);
+ this.end = (end instanceof HighPrecisionTime) ?
+ end :
+ HighPrecisionTime.fromTPTime(end);
+ assertTrue(
+ this.start.isLessThanOrEqual(this.end),
+ `TimeSpan start [${this.start}] cannot be greater than end [${
+ this.end}]`);
+ }
+
+ static fromTpTime(start: TPTime, end: TPTime): HighPrecisionTimeSpan {
+ return new HighPrecisionTimeSpan(
+ HighPrecisionTime.fromTPTime(start),
+ HighPrecisionTime.fromTPTime(end),
+ );
+ }
+
+ static get ZERO(): HighPrecisionTimeSpan {
+ return new HighPrecisionTimeSpan(
+ HighPrecisionTime.ZERO,
+ HighPrecisionTime.ZERO,
+ );
+ }
+
+ get duration(): HighPrecisionTime {
+ return this.end.subtract(this.start);
+ }
+
+ get midpoint(): HighPrecisionTime {
+ return this.start.add(this.end).divide(2);
+ }
+
+ equals(other: Span<HighPrecisionTime>): boolean {
+ return this.start.equals(other.start) && this.end.equals(other.end);
+ }
+
+ contains(x: HighPrecisionTime|Span<HighPrecisionTime>): boolean {
+ if (x instanceof HighPrecisionTime) {
+ return this.start.isLessThanOrEqual(x) && x.isLessThan(this.end);
+ } else {
+ return this.start.isLessThanOrEqual(x.start) &&
+ x.end.isLessThanOrEqual(this.end);
+ }
+ }
+
+ intersects(x: Span<HighPrecisionTime>): boolean {
+ return !(
+ x.end.isLessThanOrEqual(this.start) ||
+ x.start.isGreaterThanOrEqual(this.end));
+ }
+
+ add(time: HighPrecisionTime): Span<HighPrecisionTime> {
+ return new HighPrecisionTimeSpan(this.start.add(time), this.end.add(time));
+ }
+
+ // Move the start and end away from each other a certain amount
+ pad(time: HighPrecisionTime): Span<HighPrecisionTime> {
+ return new HighPrecisionTimeSpan(
+ this.start.subtract(time),
+ this.end.add(time),
+ );
+ }
+}
diff --git a/ui/src/common/high_precision_time_unittest.ts b/ui/src/common/high_precision_time_unittest.ts
new file mode 100644
index 000000000..c3a2033d9
--- /dev/null
+++ b/ui/src/common/high_precision_time_unittest.ts
@@ -0,0 +1,308 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {
+ HighPrecisionTime as HPTime,
+ HighPrecisionTimeSpan as HPTimeSpan,
+} from './high_precision_time';
+import {TPTime} from './time';
+
+// Quick 'n' dirty function to convert a string to a HPtime
+// Used to make tests more readable
+// E.g. '1.3' -> {base: 1, offset: 0.3}
+// E.g. '-0.3' -> {base: -1, offset: 0.7}
+function mkTime(time: string): HPTime {
+ const array = time.split('.');
+ if (array.length > 2) throw new Error(`Bad time format ${time}`);
+ const [base, fractions] = array;
+ const negative = time.startsWith('-');
+ const numBase = BigInt(base);
+
+ if (fractions) {
+ const numFractions = Number(`0.${fractions}`);
+ if (negative) {
+ return new HPTime(numBase - 1n, 1.0 - numFractions);
+ } else {
+ return new HPTime(numBase, numFractions);
+ }
+ } else {
+ return new HPTime(numBase);
+ }
+}
+
+function mkSpan(t1: string, t2: string): HPTimeSpan {
+ return new HPTimeSpan(mkTime(t1), mkTime(t2));
+}
+
+describe('Time', () => {
+ it('should create a new Time object with the given base and offset', () => {
+ const time = new HPTime(136n, 0.3);
+ expect(time.base).toBe(136n);
+ expect(time.offset).toBeCloseTo(0.3);
+ });
+
+ it('should normalize when offset is >= 1', () => {
+ let time = new HPTime(1n, 2.3);
+ expect(time.base).toBe(3n);
+ expect(time.offset).toBeCloseTo(0.3);
+
+ time = new HPTime(1n, 1);
+ expect(time.base).toBe(2n);
+ expect(time.offset).toBeCloseTo(0);
+ });
+
+ it('should normalize when offset is < 0', () => {
+ const time = new HPTime(1n, -0.4);
+ expect(time.base).toBe(0n);
+ expect(time.offset).toBeCloseTo(0.6);
+ });
+
+ it('should store timestamps without losing precision', () => {
+ let time = HPTime.fromTPTime(123n as TPTime);
+ expect(time.toTPTime()).toBe(123n as TPTime);
+
+ time = HPTime.fromTPTime(1152921504606846976n as TPTime);
+ expect(time.toTPTime()).toBe(1152921504606846976n as TPTime);
+ });
+
+ it('should store and manipulate timestamps without losing precision', () => {
+ let time = HPTime.fromTPTime(123n as TPTime);
+ time = time.addTPTime(456n);
+ expect(time.toTPTime()).toBe(579n);
+
+ time = HPTime.fromTPTime(2315700508990407843n as TPTime);
+ time = time.addTPTime(2315718101717517451n as TPTime);
+ expect(time.toTPTime()).toBe(4631418610707925294n);
+ });
+
+ it('should add time', () => {
+ const time1 = mkTime('1.3');
+ const time2 = mkTime('3.1');
+ const result = time1.add(time2);
+ expect(result.base).toEqual(4n);
+ expect(result.offset).toBeCloseTo(0.4);
+ });
+
+ it('should subtract time', () => {
+ const time1 = mkTime('3.1');
+ const time2 = mkTime('1.3');
+ const result = time1.subtract(time2);
+ expect(result.base).toEqual(1n);
+ expect(result.offset).toBeCloseTo(0.8);
+ });
+
+ it('should add nanoseconds', () => {
+ const time = mkTime('1.3');
+ const result = time.addNanos(0.8);
+ expect(result.base).toEqual(2n);
+ expect(result.offset).toBeCloseTo(0.1);
+ });
+
+ it('should add seconds', () => {
+ const time = mkTime('1.3');
+ const result = time.addSeconds(0.008);
+ expect(result.base).toEqual(8000001n);
+ expect(result.offset).toBeCloseTo(0.3);
+ });
+
+ it('should perform gt comparisions', () => {
+ const time = mkTime('1.2');
+ expect(time.isGreaterThanOrEqual(mkTime('0.5'))).toBeTruthy();
+ expect(time.isGreaterThanOrEqual(mkTime('1.1'))).toBeTruthy();
+ expect(time.isGreaterThanOrEqual(mkTime('1.2'))).toBeTruthy();
+ expect(time.isGreaterThanOrEqual(mkTime('1.5'))).toBeFalsy();
+ expect(time.isGreaterThanOrEqual(mkTime('5.5'))).toBeFalsy();
+ });
+
+ it('should perform gte comparisions', () => {
+ const time = mkTime('1.2');
+ expect(time.isGreaterThan(mkTime('0.5'))).toBeTruthy();
+ expect(time.isGreaterThan(mkTime('1.1'))).toBeTruthy();
+ expect(time.isGreaterThan(mkTime('1.2'))).toBeFalsy();
+ expect(time.isGreaterThan(mkTime('1.5'))).toBeFalsy();
+ expect(time.isGreaterThan(mkTime('5.5'))).toBeFalsy();
+ });
+
+ it('should perform lt comparisions', () => {
+ const time = mkTime('1.2');
+ expect(time.isLessThan(mkTime('0.5'))).toBeFalsy();
+ expect(time.isLessThan(mkTime('1.1'))).toBeFalsy();
+ expect(time.isLessThan(mkTime('1.2'))).toBeFalsy();
+ expect(time.isLessThan(mkTime('1.5'))).toBeTruthy();
+ expect(time.isLessThan(mkTime('5.5'))).toBeTruthy();
+ });
+
+ it('should perform lte comparisions', () => {
+ const time = mkTime('1.2');
+ expect(time.isLessThanOrEqual(mkTime('0.5'))).toBeFalsy();
+ expect(time.isLessThanOrEqual(mkTime('1.1'))).toBeFalsy();
+ expect(time.isLessThanOrEqual(mkTime('1.2'))).toBeTruthy();
+ expect(time.isLessThanOrEqual(mkTime('1.5'))).toBeTruthy();
+ expect(time.isLessThanOrEqual(mkTime('5.5'))).toBeTruthy();
+ });
+
+ it('should detect equality', () => {
+ const time = new HPTime(1n, 0.2);
+ expect(time.equals(new HPTime(1n, 0.2))).toBeTruthy();
+ expect(time.equals(new HPTime(0n, 1.2))).toBeTruthy();
+ expect(time.equals(new HPTime(-100n, 101.2))).toBeTruthy();
+ expect(time.equals(new HPTime(1n, 0.3))).toBeFalsy();
+ expect(time.equals(new HPTime(2n, 0.2))).toBeFalsy();
+ });
+
+ it('should clamp a time to a range', () => {
+ const time1 = mkTime('1.2');
+ const time2 = mkTime('5.4');
+ const time3 = mkTime('2.8');
+ const lower = mkTime('2.3');
+ const upper = mkTime('4.5');
+ expect(time1.clamp(lower, upper)).toEqual(lower);
+ expect(time2.clamp(lower, upper)).toEqual(upper);
+ expect(time3.clamp(lower, upper)).toEqual(time3);
+ });
+
+ it('should convert to seconds', () => {
+ expect(new HPTime(1n, .2).seconds).toBeCloseTo(0.0000000012);
+ expect(new HPTime(1000000000n, .0).seconds).toBeCloseTo(1);
+ });
+
+ it('should convert to nanos', () => {
+ expect(new HPTime(1n, .2).nanos).toBeCloseTo(1.2);
+ expect(new HPTime(1000000000n, .0).nanos).toBeCloseTo(1e9);
+ });
+
+ it('should convert to timestamps', () => {
+ expect(new HPTime(1n, .2).toTPTime('round')).toBe(1n);
+ expect(new HPTime(1n, .5).toTPTime('round')).toBe(2n);
+ expect(new HPTime(1n, .2).toTPTime('floor')).toBe(1n);
+ expect(new HPTime(1n, .5).toTPTime('floor')).toBe(1n);
+ expect(new HPTime(1n, .2).toTPTime('ceil')).toBe(2n);
+ expect(new HPTime(1n, .5).toTPTime('ceil')).toBe(2n);
+ });
+
+ it('should divide', () => {
+ let result = mkTime('1').divide(2);
+ expect(result.base).toBe(0n);
+ expect(result.offset).toBeCloseTo(0.5);
+
+ result = mkTime('1.6').divide(2);
+ expect(result.base).toBe(0n);
+ expect(result.offset).toBeCloseTo(0.8);
+
+ result = mkTime('-0.5').divide(2);
+ expect(result.base).toBe(-1n);
+ expect(result.offset).toBeCloseTo(0.75);
+
+ result = mkTime('123.1').divide(123);
+ expect(result.base).toBe(1n);
+ expect(result.offset).toBeCloseTo(0.000813, 6);
+ });
+
+ it('should multiply', () => {
+ let result = mkTime('1').multiply(2);
+ expect(result.base).toBe(2n);
+ expect(result.offset).toBeCloseTo(0);
+
+ result = mkTime('1').multiply(2.5);
+ expect(result.base).toBe(2n);
+ expect(result.offset).toBeCloseTo(0.5);
+
+ result = mkTime('-0.5').multiply(2);
+ expect(result.base).toBe(-1n);
+ expect(result.offset).toBeCloseTo(0.0);
+
+ result = mkTime('123.1').multiply(25.5);
+ expect(result.base).toBe(3139n);
+ expect(result.offset).toBeCloseTo(0.05);
+ });
+
+ it('should convert to string', () => {
+ expect(mkTime('1.3').toString()).toBe('1.3');
+ expect(mkTime('12983423847.332533').toString()).toBe('12983423847.332533');
+ expect(new HPTime(234n).toString()).toBe('234');
+ });
+});
+
+describe('HighPrecisionTimeSpan', () => {
+ it('can be constructed from HP time', () => {
+ const span = new HPTimeSpan(mkTime('10'), mkTime('20'));
+ expect(span.start).toEqual(mkTime('10'));
+ expect(span.end).toEqual(mkTime('20'));
+ });
+
+ it('can be constructed from integer time', () => {
+ const span = new HPTimeSpan(10n, 20n);
+ expect(span.start).toEqual(mkTime('10'));
+ expect(span.end).toEqual(mkTime('20'));
+ });
+
+ it('throws when start is later than end', () => {
+ expect(() => new HPTimeSpan(mkTime('0.1'), mkTime('0'))).toThrow();
+ expect(() => new HPTimeSpan(mkTime('1124.0001'), mkTime('1124'))).toThrow();
+ });
+
+ it('can calc duration', () => {
+ let dur = mkSpan('10', '20').duration;
+ expect(dur.base).toBe(10n);
+ expect(dur.offset).toBeCloseTo(0);
+
+ dur = mkSpan('10.123', '20.456').duration;
+ expect(dur.base).toBe(10n);
+ expect(dur.offset).toBeCloseTo(0.333);
+ });
+
+ it('can calc midpoint', () => {
+ let mid = mkSpan('10', '20').midpoint;
+ expect(mid.base).toBe(15n);
+ expect(mid.offset).toBeCloseTo(0);
+
+ mid = mkSpan('10.25', '16.75').midpoint;
+ expect(mid.base).toBe(13n);
+ expect(mid.offset).toBeCloseTo(0.5);
+ });
+
+ it('can be compared', () => {
+ expect(mkSpan('0.1', '34.2').equals(mkSpan('0.1', '34.2'))).toBeTruthy();
+ expect(mkSpan('0.1', '34.5').equals(mkSpan('0.1', '34.2'))).toBeFalsy();
+ expect(mkSpan('0.9', '34.2').equals(mkSpan('0.1', '34.2'))).toBeFalsy();
+ });
+
+ it('checks if span contains another span', () => {
+ const x = mkSpan('10', '20');
+
+ expect(x.contains(mkTime('9'))).toBeFalsy();
+ expect(x.contains(mkTime('10'))).toBeTruthy();
+ expect(x.contains(mkTime('15'))).toBeTruthy();
+ expect(x.contains(mkTime('20'))).toBeFalsy();
+ expect(x.contains(mkTime('21'))).toBeFalsy();
+
+ expect(x.contains(mkSpan('12', '18'))).toBeTruthy();
+ expect(x.contains(mkSpan('5', '25'))).toBeFalsy();
+ expect(x.contains(mkSpan('5', '15'))).toBeFalsy();
+ expect(x.contains(mkSpan('15', '25'))).toBeFalsy();
+ expect(x.contains(mkSpan('0', '10'))).toBeFalsy();
+ expect(x.contains(mkSpan('20', '30'))).toBeFalsy();
+ });
+
+ it('checks if span intersects another span', () => {
+ const x = mkSpan('10', '20');
+
+ expect(x.intersects(mkSpan('0', '10'))).toBeFalsy();
+ expect(x.intersects(mkSpan('5', '15'))).toBeTruthy();
+ expect(x.intersects(mkSpan('12', '18'))).toBeTruthy();
+ expect(x.intersects(mkSpan('15', '25'))).toBeTruthy();
+ expect(x.intersects(mkSpan('20', '30'))).toBeFalsy();
+ expect(x.intersects(mkSpan('5', '25'))).toBeTruthy();
+ });
+});
diff --git a/ui/src/common/internal_layout_utils.ts b/ui/src/common/internal_layout_utils.ts
new file mode 100644
index 000000000..478cd029c
--- /dev/null
+++ b/ui/src/common/internal_layout_utils.ts
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Object to facilitate generation of SELECT statement using
+// generateSqlWithInternalLayout.
+//
+// Fields:
+// @columns: a string array list of the columns to be selected from the table.
+// @layoutParams: a config of the timestamp (ts) and duration (dur) fields
+// required by the internal_layout function.
+// @sourceTable: the table in the FROM clause, source of the data.
+// @whereClause: the WHERE clause to filter data from the source table.
+// @orderByClause: the ORDER BY clause for the query data.
+interface GenerateSqlArgs {
+ columns: string[];
+ layoutParams: {ts: string, dur: string};
+ sourceTable: string;
+ whereClause?: string;
+ orderByClause?: string;
+}
+
+// Function to generate a SELECT statement utilizing the internal_layout
+// SQL function as a depth field.
+export function generateSqlWithInternalLayout(sqlArgs: GenerateSqlArgs):
+ string {
+ let sql = `SELECT ` + sqlArgs.columns.toString() + ', internal_layout(' +
+ sqlArgs.layoutParams.ts + ',' + sqlArgs.layoutParams.dur +
+ ') OVER (ORDER BY ' + sqlArgs.layoutParams.ts +
+ ' ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS depth' +
+ ' FROM ' + sqlArgs.sourceTable;
+ if (sqlArgs.whereClause !== undefined) {
+ sql += ' WHERE ' + sqlArgs.whereClause;
+ }
+ if (sqlArgs.orderByClause !== undefined) {
+ sql += ' ORDER BY ' + sqlArgs.orderByClause;
+ }
+ sql += ';';
+ return sql;
+}
diff --git a/ui/src/common/logs.ts b/ui/src/common/logs.ts
index 0fc2fae9e..04cf06599 100644
--- a/ui/src/common/logs.ts
+++ b/ui/src/common/logs.ts
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {TPTime} from './time';
+
export const LogExistsKey = 'log-exists';
export const LogBoundsKey = 'log-bounds';
export const LogEntriesKey = 'log-entries';
@@ -19,16 +21,16 @@ export const LogEntriesKey = 'log-entries';
export interface LogExists { exists: boolean; }
export interface LogBounds {
- startTs: number;
- endTs: number;
- firstRowTs: number;
- lastRowTs: number;
- total: number;
+ firstLogTs: TPTime;
+ lastLogTs: TPTime;
+ firstVisibleLogTs: TPTime;
+ lastVisibleLogTs: TPTime;
+ totalVisibleLogs: number;
}
export interface LogEntries {
offset: number;
- timestamps: number[];
+ timestamps: TPTime[];
priorities: number[];
tags: string[];
messages: string[];
diff --git a/ui/src/common/plugin_api.ts b/ui/src/common/plugin_api.ts
index fa8a9fcd8..0dc66d618 100644
--- a/ui/src/common/plugin_api.ts
+++ b/ui/src/common/plugin_api.ts
@@ -15,9 +15,12 @@
import {EngineProxy} from '../common/engine';
import {TrackControllerFactory} from '../controller/track_controller';
import {TrackCreator} from '../frontend/track';
+import {Selection} from './state';
export {EngineProxy} from '../common/engine';
export {
+ LONG,
+ LONG_NULL,
NUM,
NUM_NULL,
STR,
@@ -66,6 +69,16 @@ export interface PluginContext {
// could be registered in dev.perfetto.CounterTrack - a whole
// different plugin.
registerTrack(track: TrackCreator): void;
+
+ // Register custom functionality to specify how the plugin should handle
+ // selection changes for tracks in this plugin.
+ //
+ // Params:
+ // @onDetailsPanelSelectionChange a function that takes a Selection as its
+ // parameter and performs whatever must happen on the details panel when the
+ // selection is invoked.
+ registerOnDetailsPanelSelectionChange(
+ onDetailsPanelSelectionChange: (newSelection?: Selection) => void): void;
}
export interface PluginInfo {
diff --git a/ui/src/common/plugins.ts b/ui/src/common/plugins.ts
index aa414bc74..5898c5f4b 100644
--- a/ui/src/common/plugins.ts
+++ b/ui/src/common/plugins.ts
@@ -27,12 +27,14 @@ import {
TrackProvider,
} from './plugin_api';
import {Registry} from './registry';
+import {Selection} from './state';
// Every plugin gets its own PluginContext. This is how we keep track
// what each plugin is doing and how we can blame issues on particular
// plugins.
export class PluginContextImpl implements PluginContext {
readonly pluginId: string;
+ onDetailsPanelSelectionChange?: (newSelection?: Selection) => void;
private trackProviders: TrackProvider[];
constructor(pluginId: string) {
@@ -53,6 +55,11 @@ export class PluginContextImpl implements PluginContext {
registerTrackProvider(provider: TrackProvider) {
this.trackProviders.push(provider);
}
+
+ registerOnDetailsPanelSelectionChange(
+ onDetailsPanelSelectionChange: (newSelection?: Selection) => void) {
+ this.onDetailsPanelSelectionChange = onDetailsPanelSelectionChange;
+ }
// ==================================================================
// ==================================================================
@@ -123,6 +130,14 @@ export class PluginManager {
}
return promises;
}
+
+ onDetailsPanelSelectionChange(pluginId: string, newSelection?: Selection) {
+ const pluginContext = this.getPluginContext(pluginId);
+ if (pluginContext === undefined) return;
+ if (pluginContext.onDetailsPanelSelectionChange) {
+ pluginContext.onDetailsPanelSelectionChange(newSelection);
+ }
+ }
}
// TODO(hjd): Sort out the story for global singletons like these:
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 995f6438b..91ca35835 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -18,7 +18,10 @@ import {
PivotTree,
TableColumn,
} from '../frontend/pivot_table_types';
+import {TopLevelScrollSelection} from '../tracks/scroll_jank/scroll_track';
+
import {Direction} from './event_set';
+import {TPDuration, TPTime} from './time';
/**
* A plain js object, holding objects of type |Class| keyed by string id.
@@ -39,9 +42,9 @@ export interface OmniboxState {
}
export interface VisibleState extends Timestamped {
- startSec: number;
- endSec: number;
- resolution: number;
+ start: TPTime;
+ end: TPTime;
+ resolution: TPDuration;
}
export interface AreaSelection {
@@ -59,8 +62,8 @@ export interface AreaSelection {
export type AreaById = Area&{id: string};
export interface Area {
- startSec: number;
- endSec: number;
+ start: TPTime;
+ end: TPTime;
tracks: string[];
}
@@ -100,7 +103,8 @@ export const MAX_TIME = 180;
// 28. Add a boolean indicating if non matching log entries are hidden.
// 29. Add ftrace state. <-- Borked, state contains a non-serializable object.
// 30. Convert ftraceFilter.excludedNames from Set<string> to string[].
-export const STATE_VERSION = 30;
+// 31. Convert all timestamps to bigints.
+export const STATE_VERSION = 31;
export const SCROLLING_TRACK_GROUP = 'ScrollingTracks';
@@ -268,8 +272,8 @@ export interface PermalinkConfig {
}
export interface TraceTime {
- startSec: number;
- endSec: number;
+ start: TPTime;
+ end: TPTime;
}
export interface FrontendLocalState {
@@ -284,7 +288,7 @@ export interface Status {
export interface Note {
noteType: 'DEFAULT';
id: string;
- timestamp: number;
+ timestamp: TPTime;
color: string;
text: string;
}
@@ -311,14 +315,14 @@ export interface DebugSliceSelection {
kind: 'DEBUG_SLICE';
id: number;
sqlTableName: string;
- startS: number;
- durationS: number;
+ start: TPTime;
+ duration: TPDuration;
}
export interface CounterSelection {
kind: 'COUNTER';
- leftTs: number;
- rightTs: number;
+ leftTs: TPTime;
+ rightTs: TPTime;
id: number;
}
@@ -326,7 +330,7 @@ export interface HeapProfileSelection {
kind: 'HEAP_PROFILE';
id: number;
upid: number;
- ts: number;
+ ts: TPTime;
type: ProfileType;
}
@@ -334,16 +338,16 @@ export interface PerfSamplesSelection {
kind: 'PERF_SAMPLES';
id: number;
upid: number;
- leftTs: number;
- rightTs: number;
+ leftTs: TPTime;
+ rightTs: TPTime;
type: ProfileType;
}
export interface FlamegraphState {
kind: 'FLAMEGRAPH_STATE';
upids: number[];
- startNs: number;
- endNs: number;
+ start: TPTime;
+ end: TPTime;
type: ProfileType;
viewingOption: FlamegraphStateViewingOption;
focusRegex: string;
@@ -377,8 +381,8 @@ export interface LogSelection {
export type Selection =
(NoteSelection|SliceSelection|CounterSelection|HeapProfileSelection|
CpuProfileSampleSelection|ChromeSliceSelection|ThreadStateSelection|
- AreaSelection|PerfSamplesSelection|LogSelection|DebugSliceSelection)&
- {trackId?: string};
+ AreaSelection|PerfSamplesSelection|LogSelection|DebugSliceSelection|
+ TopLevelScrollSelection)&{trackId?: string};
export type SelectionKind = Selection['kind']; // 'THREAD_STATE' | 'SLICE' ...
export interface Pagination {
@@ -570,8 +574,8 @@ export interface State {
// Hovered and focused events
hoveredUtid: number;
hoveredPid: number;
- hoverCursorTimestamp: number;
- hoveredNoteTimestamp: number;
+ hoverCursorTimestamp: TPTime;
+ hoveredNoteTimestamp: TPTime;
highlightedSliceId: number;
focusedFlowIdLeft: number;
focusedFlowIdRight: number;
@@ -608,8 +612,8 @@ export interface State {
}
export const defaultTraceTime = {
- startSec: 0,
- endSec: 10,
+ start: 0n,
+ end: BigInt(10e9),
};
export declare type RecordMode =
@@ -661,9 +665,9 @@ export function hasActiveProbes(config: RecordConfig) {
export function getDefaultRecordingTargets(): RecordingTarget[] {
return [
- {os: 'Q', name: 'Android Q+'},
- {os: 'P', name: 'Android P'},
- {os: 'O', name: 'Android O-'},
+ {os: 'Q', name: 'Android Q+ / 10+'},
+ {os: 'P', name: 'Android P / 9'},
+ {os: 'O', name: 'Android O- / 8-'},
{os: 'C', name: 'Chrome'},
{os: 'CrOS', name: 'Chrome OS (system trace)'},
{os: 'L', name: 'Linux desktop'},
diff --git a/ui/src/common/state_unittest.ts b/ui/src/common/state_unittest.ts
index 58610dc99..9b5a064fb 100644
--- a/ui/src/common/state_unittest.ts
+++ b/ui/src/common/state_unittest.ts
@@ -14,6 +14,7 @@
import {createEmptyState} from './empty_state';
import {getContainingTrackId, PrimaryTrackSortKey, State} from './state';
+import {deserializeStateObject, serializeStateObject} from './upload_utils';
test('createEmptyState', () => {
const state: State = createEmptyState();
@@ -46,20 +47,10 @@ test('getContainingTrackId', () => {
expect(getContainingTrackId(state, 'b')).toEqual('containsB');
});
-function serializeState(state: State): string {
- return JSON.stringify(state, (key, value) => {
- return key === 'nonSerializableState' ? undefined : value;
- });
-}
-
-function deserializeState(json: string): State {
- return JSON.parse(json);
-}
-
test('state is serializable', () => {
const state: State = createEmptyState();
- const json = serializeState(state);
- const restored: State = deserializeState(json);
+ const json = serializeStateObject(state);
+ const restored: State = deserializeStateObject(json);
// Remove nonSerializableState from original
const serializableState: any = state as any;
diff --git a/ui/src/common/time.ts b/ui/src/common/time.ts
index ea5e9d8a6..5608d3f91 100644
--- a/ui/src/common/time.ts
+++ b/ui/src/common/time.ts
@@ -13,8 +13,7 @@
// limitations under the License.
import {assertTrue} from '../base/logging';
-
-const EPSILON = 0.0000000001;
+import {ColumnType} from './query_result';
// TODO(hjd): Combine with timeToCode.
export function timeToString(sec: number) {
@@ -29,6 +28,10 @@ export function timeToString(sec: number) {
return `${sign < 0 ? '-' : ''}${Math.round(n * 10) / 10} ${units[u]}`;
}
+export function tpTimeToString(time: TPTime) {
+ return timeToString(tpTimeToSeconds(time));
+}
+
export function fromNs(ns: number) {
return ns / 1e9;
}
@@ -52,6 +55,10 @@ export function formatTimestamp(sec: number) {
return parts.join('.');
}
+export function formatTPTime(time: TPTime) {
+ return formatTimestamp(tpTimeToSeconds(time));
+}
+
// TODO(hjd): Rename to formatTimestampWithUnits
// 1000000023ns -> "1s 23ns"
export function timeToCode(sec: number): string {
@@ -77,44 +84,128 @@ export function timeToCode(sec: number): string {
return result.slice(0, -1);
}
+export function tpTimeToCode(time: TPTime) {
+ return timeToCode(tpTimeToSeconds(time));
+}
+
export function currentDateHourAndMinute(): string {
const date = new Date();
return `${date.toISOString().substr(0, 10)}-${date.getHours()}-${
date.getMinutes()}`;
}
-export class TimeSpan {
- readonly start: number;
- readonly end: number;
+// Aliased "Trace Processor" time and duration types.
+// Note(stevegolton): While it might be nice to type brand these in the future,
+// for now we're going to keep things simple. We do a lot of maths with these
+// timestamps and type branding requires a lot of jumping through hoops to
+// coerse the type back to the correct format.
+export type TPTime = bigint;
+export type TPDuration = bigint;
+
+export function tpTimeFromNanos(nanos: number): TPTime {
+ return BigInt(Math.floor(nanos));
+}
+
+export function tpTimeFromSeconds(seconds: number): TPTime {
+ return BigInt(Math.floor(seconds * 1e9));
+}
+
+export function tpTimeToNanos(time: TPTime): number {
+ return Number(time);
+}
+
+export function tpTimeToMillis(time: TPTime): number {
+ return Number(time) / 1e6;
+}
+
+export function tpTimeToSeconds(time: TPTime): number {
+ return Number(time) / 1e9;
+}
+
+// Create a TPTime from an arbitrary SQL value.
+// Throws if the value cannot be reasonably converted to a bigint.
+// Assumes value is in nanoseconds.
+export function tpTimeFromSql(value: ColumnType): TPTime {
+ if (typeof value === 'bigint') {
+ return value;
+ } else if (typeof value === 'number') {
+ return tpTimeFromNanos(value);
+ } else if (value === null) {
+ return 0n;
+ } else {
+ throw Error(`Refusing to create Timestamp from unrelated type ${value}`);
+ }
+}
+
+export function tpDurationToSeconds(dur: TPDuration): number {
+ return tpTimeToSeconds(dur);
+}
+
+export function tpDurationToNanos(dur: TPDuration): number {
+ return tpTimeToSeconds(dur);
+}
+
+export function tpDurationFromNanos(nanos: number): TPDuration {
+ return tpTimeFromNanos(nanos);
+}
+
+export function tpDurationFromSql(nanos: ColumnType): TPDuration {
+ return tpTimeFromSql(nanos);
+}
+
+export interface Span<Unit, Duration = Unit> {
+ get start(): Unit;
+ get end(): Unit;
+ get duration(): Duration;
+ get midpoint(): Unit;
+ contains(span: Unit|Span<Unit, Duration>): boolean;
+ intersects(x: Span<Unit>): boolean;
+ equals(span: Span<Unit, Duration>): boolean;
+ add(offset: Duration): Span<Unit, Duration>;
+ pad(padding: Duration): Span<Unit, Duration>;
+}
- constructor(start: number, end: number) {
- assertTrue(start <= end);
+export class TPTimeSpan implements Span<TPTime, TPDuration> {
+ readonly start: TPTime;
+ readonly end: TPTime;
+
+ constructor(start: TPTime, end: TPTime) {
+ assertTrue(
+ start <= end,
+ `Span start [${start}] cannot be greater than end [${end}]`);
this.start = start;
this.end = end;
}
- clone() {
- return new TimeSpan(this.start, this.end);
+ get duration(): TPDuration {
+ return this.end - this.start;
}
- equals(other: TimeSpan): boolean {
- return Math.abs(this.start - other.start) < EPSILON &&
- Math.abs(this.end - other.end) < EPSILON;
+ get midpoint(): TPTime {
+ return (this.start + this.end) / 2n;
}
- get duration() {
- return this.end - this.start;
+ contains(x: TPTime|Span<TPTime, TPDuration>): boolean {
+ if (typeof x === 'bigint') {
+ return this.start <= x && x < this.end;
+ } else {
+ return this.start <= x.start && x.end <= this.end;
+ }
+ }
+
+ intersects(x: Span<TPTime, TPDuration>): boolean {
+ return !(x.end <= this.start || x.start >= this.end);
}
- isInBounds(sec: number) {
- return this.start <= sec && sec <= this.end;
+ equals(span: Span<TPTime, TPDuration>): boolean {
+ return this.start === span.start && this.end === span.end;
}
- add(sec: number): TimeSpan {
- return new TimeSpan(this.start + sec, this.end + sec);
+ add(x: TPTime): Span<TPTime, TPDuration> {
+ return new TPTimeSpan(this.start + x, this.end + x);
}
- contains(other: TimeSpan) {
- return this.start <= other.start && other.end <= this.end;
+ pad(padding: TPDuration): Span<TPTime, TPDuration> {
+ return new TPTimeSpan(this.start - padding, this.end + padding);
}
}
diff --git a/ui/src/common/time_unittest.ts b/ui/src/common/time_unittest.ts
index 7bfead11e..b9e6bd900 100644
--- a/ui/src/common/time_unittest.ts
+++ b/ui/src/common/time_unittest.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {TimeSpan, timeToCode} from './time';
+import {timeToCode, TPTime, TPTimeSpan} from './time';
test('seconds to code', () => {
expect(timeToCode(3)).toEqual('3s');
@@ -29,9 +29,67 @@ test('seconds to code', () => {
expect(timeToCode(0)).toEqual('0s');
});
-test('Time span equality', () => {
- expect((new TimeSpan(0, 1)).equals(new TimeSpan(0, 1))).toBe(true);
- expect((new TimeSpan(0, 1)).equals(new TimeSpan(0, 2))).toBe(false);
- expect((new TimeSpan(0, 1)).equals(new TimeSpan(0, 1 + Number.EPSILON)))
- .toBe(true);
+function mkSpan(start: TPTime, end: TPTime) {
+ return new TPTimeSpan(start, end);
+}
+
+describe('TPTimeSpan', () => {
+ it('throws when start is later than end', () => {
+ expect(() => mkSpan(1n, 0n)).toThrow();
+ });
+
+ it('can calc duration', () => {
+ expect(mkSpan(10n, 20n).duration).toBe(10n);
+ });
+
+ it('can calc midpoint', () => {
+ expect(mkSpan(10n, 20n).midpoint).toBe(15n);
+ expect(mkSpan(10n, 19n).midpoint).toBe(14n);
+ expect(mkSpan(10n, 10n).midpoint).toBe(10n);
+ });
+
+ it('can be compared', () => {
+ const x = mkSpan(10n, 20n);
+ expect(x.equals(mkSpan(10n, 20n))).toBeTruthy();
+ expect(x.equals(mkSpan(11n, 20n))).toBeFalsy();
+ expect(x.equals(mkSpan(10n, 19n))).toBeFalsy();
+ });
+
+ it('checks containment', () => {
+ const x = mkSpan(10n, 20n);
+
+ expect(x.contains(9n)).toBeFalsy();
+ expect(x.contains(10n)).toBeTruthy();
+ expect(x.contains(15n)).toBeTruthy();
+ expect(x.contains(20n)).toBeFalsy();
+ expect(x.contains(21n)).toBeFalsy();
+
+ expect(x.contains(mkSpan(12n, 18n))).toBeTruthy();
+ expect(x.contains(mkSpan(5n, 25n))).toBeFalsy();
+ expect(x.contains(mkSpan(5n, 15n))).toBeFalsy();
+ expect(x.contains(mkSpan(15n, 25n))).toBeFalsy();
+ expect(x.contains(mkSpan(0n, 10n))).toBeFalsy();
+ expect(x.contains(mkSpan(20n, 30n))).toBeFalsy();
+ });
+
+ it('checks intersection', () => {
+ const x = mkSpan(10n, 20n);
+
+ expect(x.intersects(mkSpan(0n, 10n))).toBeFalsy();
+ expect(x.intersects(mkSpan(5n, 15n))).toBeTruthy();
+ expect(x.intersects(mkSpan(12n, 18n))).toBeTruthy();
+ expect(x.intersects(mkSpan(15n, 25n))).toBeTruthy();
+ expect(x.intersects(mkSpan(20n, 30n))).toBeFalsy();
+ expect(x.intersects(mkSpan(5n, 25n))).toBeTruthy();
+ });
+
+ it('can add', () => {
+ const x = mkSpan(10n, 20n);
+ expect(x.add(5n)).toEqual(mkSpan(15n, 25n));
+ });
+
+ it('can pad', () => {
+ const x = mkSpan(10n, 20n);
+ expect(x.pad(5n)).toEqual(mkSpan(5n, 25n));
+ });
});
diff --git a/ui/src/common/track_data.ts b/ui/src/common/track_data.ts
index 9af7fff5e..a49a56d76 100644
--- a/ui/src/common/track_data.ts
+++ b/ui/src/common/track_data.ts
@@ -12,12 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {TPDuration, TPTime} from './time';
+
// TODO(hjd): Refactor into method on TrackController
export const LIMIT = 10000;
export interface TrackData {
- start: number;
- end: number;
- resolution: number;
+ start: TPTime;
+ end: TPTime;
+ resolution: TPDuration;
length: number;
}
diff --git a/ui/src/common/upload_utils.ts b/ui/src/common/upload_utils.ts
index 875b072a4..0c9792178 100644
--- a/ui/src/common/upload_utils.ts
+++ b/ui/src/common/upload_utils.ts
@@ -34,11 +34,53 @@ export async function saveTrace(trace: File|ArrayBuffer): Promise<string> {
return `https://storage.googleapis.com/${BUCKET_NAME}/${name}`;
}
-export async function saveState(stateOrConfig: State|
- RecordConfig): Promise<string> {
- const text = JSON.stringify(stateOrConfig, (key, value) => {
+// Bigint's are not serializable using JSON.stringify, so we use a special
+// object when serialising
+export type SerializedBigint = {
+ __kind: 'bigint',
+ value: string
+};
+
+// Check if a value looks like a serialized bigint
+export function isSerializedBigint(value: unknown): value is SerializedBigint {
+ if (value === null) {
+ return false;
+ }
+ if (typeof value !== 'object') {
+ return false;
+ }
+ if ('__kind' in value && 'value' in value) {
+ return value.__kind === 'bigint' && typeof value.value === 'string';
+ }
+ return false;
+}
+
+export function serializeStateObject(object: unknown): string {
+ const json = JSON.stringify(object, (key, value) => {
+ if (typeof value === 'bigint') {
+ return {
+ __kind: 'bigint',
+ value: value.toString(),
+ };
+ }
return key === 'nonSerializableState' ? undefined : value;
});
+ return json;
+}
+
+export function deserializeStateObject(json: string): any {
+ const object = JSON.parse(json, (_key, value) => {
+ if (isSerializedBigint(value)) {
+ return BigInt(value.value);
+ }
+ return value;
+ });
+ return object;
+}
+
+export async function saveState(stateOrConfig: State|
+ RecordConfig): Promise<string> {
+ const text = serializeStateObject(stateOrConfig);
const hash = await toSha256(text);
const url = 'https://www.googleapis.com/upload/storage/v1/b/' +
`${BUCKET_NAME}/o?uploadType=media` +
diff --git a/ui/src/common/upload_utils_unittest.ts b/ui/src/common/upload_utils_unittest.ts
new file mode 100644
index 000000000..4c0b8ce8d
--- /dev/null
+++ b/ui/src/common/upload_utils_unittest.ts
@@ -0,0 +1,105 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {
+ deserializeStateObject,
+ isSerializedBigint,
+ serializeStateObject,
+} from './upload_utils';
+
+describe('isSerializedBigint', () => {
+ it('should return true for a valid serialized bigint', () => {
+ const value = {
+ __kind: 'bigint',
+ value: '1234567890',
+ };
+ expect(isSerializedBigint(value)).toBeTruthy();
+ });
+
+ it('should return false for a null value', () => {
+ expect(isSerializedBigint(null)).toBeFalsy();
+ });
+
+ it('should return false for a non-object value', () => {
+ expect(isSerializedBigint(123)).toBeFalsy();
+ });
+
+ it('should return false for a non-serialized bigint value', () => {
+ const value = {
+ __kind: 'not-bigint',
+ value: '1234567890',
+ };
+ expect(isSerializedBigint(value)).toBeFalsy();
+ });
+});
+
+describe('serializeStateObject', () => {
+ it('should serialize a simple object', () => {
+ const object = {
+ a: 1,
+ b: 2,
+ c: 3,
+ };
+ const expectedJson = `{"a":1,"b":2,"c":3}`;
+ expect(serializeStateObject(object)).toEqual(expectedJson);
+ });
+
+ it('should serialize a bigint', () => {
+ const object = {
+ a: 123456789123456789n,
+ };
+ const expectedJson =
+ `{"a":{"__kind":"bigint","value":"123456789123456789"}}`;
+ expect(serializeStateObject(object)).toEqual(expectedJson);
+ });
+
+ it('should not serialize a non-serializable property', () => {
+ const object = {
+ a: 1,
+ b: 2,
+ c: 3,
+ nonSerializableState: 4,
+ };
+ const expectedJson = `{"a":1,"b":2,"c":3}`;
+ expect(serializeStateObject(object)).toEqual(expectedJson);
+ });
+});
+
+describe('deserializeStateObject', () => {
+ it('should deserialize a simple object', () => {
+ const json = `{"a":1,"b":2,"c":3}`;
+ const expectedObject = {
+ a: 1,
+ b: 2,
+ c: 3,
+ };
+ expect(deserializeStateObject(json)).toEqual(expectedObject);
+ });
+
+ it('should deserialize a bigint', () => {
+ const json = `{"a":{"__kind":"bigint","value":"123456789123456789"}}`;
+ const expectedObject = {
+ a: 123456789123456789n,
+ };
+ expect(deserializeStateObject(json)).toEqual(expectedObject);
+ });
+
+ it('should deserialize a null', () => {
+ const json = `{"a":null}`;
+ const expectedObject = {
+ a: null,
+ };
+ expect(deserializeStateObject(json)).toEqual(expectedObject);
+ });
+});
diff --git a/ui/src/controller/aggregation/counter_aggregation_controller.ts b/ui/src/controller/aggregation/counter_aggregation_controller.ts
index dd7f14aad..e632f8e29 100644
--- a/ui/src/controller/aggregation/counter_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/counter_aggregation_controller.ts
@@ -15,7 +15,7 @@
import {ColumnDef} from '../../common/aggregation_data';
import {Engine} from '../../common/engine';
import {Area, Sorting} from '../../common/state';
-import {toNs} from '../../common/time';
+import {tpDurationToSeconds} from '../../common/time';
import {globals} from '../../frontend/globals';
import {Config, COUNTER_TRACK_KIND} from '../../tracks/counter';
@@ -38,21 +38,22 @@ export class CounterAggregationController extends AggregationController {
}
}
if (ids.length === 0) return false;
+ const duration = area.end - area.start;
+ const durationSec = tpDurationToSeconds(duration);
const query = `create view ${this.kind} as select
name,
count(1) as count,
- round(sum(weighted_value)/${
- toNs(area.endSec) - toNs(area.startSec)}, 2) as avg_value,
+ round(sum(weighted_value)/${duration}, 2) as avg_value,
last as last_value,
first as first_value,
max(last) - min(first) as delta_value,
- round((max(last) - min(first))/${area.endSec - area.startSec}, 2) as rate,
+ round((max(last) - min(first))/${durationSec}, 2) as rate,
min(value) as min_value,
max(value) as max_value
from
(select *,
- (min(ts + dur, ${toNs(area.endSec)}) - max(ts,${toNs(area.startSec)}))
+ (min(ts + dur, ${area.end}) - max(ts,${area.start}))
* value as weighted_value,
first_value(value) over
(partition by track_id order by ts) as first,
@@ -61,8 +62,8 @@ export class CounterAggregationController extends AggregationController {
range between unbounded preceding and unbounded following) as last
from experimental_counter_dur
where track_id in (${ids})
- and ts + dur >= ${toNs(area.startSec)} and
- ts <= ${toNs(area.endSec)})
+ and ts + dur >= ${area.start} and
+ ts <= ${area.end})
join counter_track
on track_id = counter_track.id
group by track_id`;
diff --git a/ui/src/controller/aggregation/cpu_aggregation_controller.ts b/ui/src/controller/aggregation/cpu_aggregation_controller.ts
index 94d3950a0..452ca758f 100644
--- a/ui/src/controller/aggregation/cpu_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/cpu_aggregation_controller.ts
@@ -15,7 +15,6 @@
import {ColumnDef} from '../../common/aggregation_data';
import {Engine} from '../../common/engine';
import {Area, Sorting} from '../../common/state';
-import {toNs} from '../../common/time';
import {globals} from '../../frontend/globals';
import {Config, CPU_SLICE_TRACK_KIND} from '../../tracks/cpu_slices';
@@ -46,8 +45,8 @@ export class CpuAggregationController extends AggregationController {
JOIN thread_state USING(utid)
WHERE cpu IN (${selectedCpus}) AND
state = "Running" AND
- thread_state.ts + thread_state.dur > ${toNs(area.startSec)} AND
- thread_state.ts < ${toNs(area.endSec)} group by utid`;
+ thread_state.ts + thread_state.dur > ${area.start} AND
+ thread_state.ts < ${area.end} group by utid`;
await engine.query(query);
return true;
diff --git a/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts b/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts
index b28e49656..fc24d1ed6 100644
--- a/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/cpu_by_process_aggregation_controller.ts
@@ -15,7 +15,6 @@
import {ColumnDef} from '../../common/aggregation_data';
import {Engine} from '../../common/engine';
import {Area, Sorting} from '../../common/state';
-import {toNs} from '../../common/time';
import {globals} from '../../frontend/globals';
import {Config, CPU_SLICE_TRACK_KIND} from '../../tracks/cpu_slices';
@@ -45,8 +44,8 @@ export class CpuByProcessAggregationController extends AggregationController {
JOIN thread_state USING(utid)
WHERE cpu IN (${selectedCpus}) AND
state = "Running" AND
- thread_state.ts + thread_state.dur > ${toNs(area.startSec)} AND
- thread_state.ts < ${toNs(area.endSec)} group by upid`;
+ thread_state.ts + thread_state.dur > ${area.start} AND
+ thread_state.ts < ${area.end} group by upid`;
await engine.query(query);
return true;
diff --git a/ui/src/controller/aggregation/frame_aggregation_controller.ts b/ui/src/controller/aggregation/frame_aggregation_controller.ts
index 97e1f86f0..a22a83dbd 100644
--- a/ui/src/controller/aggregation/frame_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/frame_aggregation_controller.ts
@@ -15,7 +15,6 @@
import {ColumnDef} from '../../common/aggregation_data';
import {Engine} from '../../common/engine';
import {Area, Sorting} from '../../common/state';
-import {toNs} from '../../common/time';
import {globals} from '../../frontend/globals';
import {
ACTUAL_FRAMES_SLICE_TRACK_KIND,
@@ -48,8 +47,8 @@ export class FrameAggregationController extends AggregationController {
MAX(dur) as maxDur
FROM actual_frame_timeline_slice
WHERE track_id IN (${selectedSqlTrackIds}) AND
- ts + dur > ${toNs(area.startSec)} AND
- ts < ${toNs(area.endSec)} group by jank_type`;
+ ts + dur > ${area.start} AND
+ ts < ${area.end} group by jank_type`;
await engine.query(query);
return true;
diff --git a/ui/src/controller/aggregation/slice_aggregation_controller.ts b/ui/src/controller/aggregation/slice_aggregation_controller.ts
index ebb80007b..8dcaccc0f 100644
--- a/ui/src/controller/aggregation/slice_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/slice_aggregation_controller.ts
@@ -15,7 +15,6 @@
import {ColumnDef} from '../../common/aggregation_data';
import {Engine} from '../../common/engine';
import {Area, Sorting} from '../../common/state';
-import {toNs} from '../../common/time';
import {globals} from '../../frontend/globals';
import {
ASYNC_SLICE_TRACK_KIND,
@@ -64,8 +63,8 @@ export class SliceAggregationController extends AggregationController {
count(1) as occurrences
FROM slices
WHERE track_id IN (${selectedTrackIds}) AND
- ts + dur > ${toNs(area.startSec)} AND
- ts < ${toNs(area.endSec)} group by name`;
+ ts + dur > ${area.start} AND
+ ts < ${area.end} group by name`;
await engine.query(query);
return true;
diff --git a/ui/src/controller/aggregation/thread_aggregation_controller.ts b/ui/src/controller/aggregation/thread_aggregation_controller.ts
index ddfadaea0..6e288d5dd 100644
--- a/ui/src/controller/aggregation/thread_aggregation_controller.ts
+++ b/ui/src/controller/aggregation/thread_aggregation_controller.ts
@@ -17,7 +17,6 @@ import {Engine} from '../../common/engine';
import {NUM, NUM_NULL, STR_NULL} from '../../common/query_result';
import {Area, Sorting} from '../../common/state';
import {translateState} from '../../common/thread_state';
-import {toNs} from '../../common/time';
import {globals} from '../../frontend/globals';
import {
Config,
@@ -60,8 +59,8 @@ export class ThreadAggregationController extends AggregationController {
JOIN thread USING(upid)
JOIN thread_state USING(utid)
WHERE utid IN (${this.utids}) AND
- thread_state.ts + thread_state.dur > ${toNs(area.startSec)} AND
- thread_state.ts < ${toNs(area.endSec)}
+ thread_state.ts + thread_state.dur > ${area.start} AND
+ thread_state.ts < ${area.end}
GROUP BY utid, concat_state
`;
@@ -78,8 +77,8 @@ export class ThreadAggregationController extends AggregationController {
JOIN thread USING(upid)
JOIN thread_state USING(utid)
WHERE utid IN (${this.utids}) AND thread_state.ts + thread_state.dur > ${
- toNs(area.startSec)} AND
- thread_state.ts < ${toNs(area.endSec)}
+ area.start} AND
+ thread_state.ts < ${area.end}
GROUP BY state, io_wait`;
const result = await engine.query(query);
diff --git a/ui/src/controller/area_selection_handler.ts b/ui/src/controller/area_selection_handler.ts
index b1d1c7e71..32dcb11bb 100644
--- a/ui/src/controller/area_selection_handler.ts
+++ b/ui/src/controller/area_selection_handler.ts
@@ -36,10 +36,10 @@ export class AreaSelectionHandler {
// where `a ||= b` is formatted to `a || = b`, by inserting a space which
// breaks the operator.
// Therefore, we are using the pattern `a = a || b` instead.
- hasAreaChanged = hasAreaChanged ||
- selectedArea.startSec !== this.previousArea.startSec;
hasAreaChanged =
- hasAreaChanged || selectedArea.endSec !== this.previousArea.endSec;
+ hasAreaChanged || selectedArea.start !== this.previousArea.start;
+ hasAreaChanged =
+ hasAreaChanged || selectedArea.end !== this.previousArea.end;
hasAreaChanged = hasAreaChanged ||
selectedArea.tracks.length !== this.previousArea.tracks.length;
for (let i = 0; i < selectedArea.tracks.length; ++i) {
diff --git a/ui/src/controller/area_selection_handler_unittest.ts b/ui/src/controller/area_selection_handler_unittest.ts
index c5a27c032..caac6780e 100644
--- a/ui/src/controller/area_selection_handler_unittest.ts
+++ b/ui/src/controller/area_selection_handler_unittest.ts
@@ -20,7 +20,7 @@ import {AreaSelectionHandler} from './area_selection_handler';
test('validAreaAfterUndefinedArea', () => {
const areaId = '0';
- const latestArea: AreaById = {startSec: 0, endSec: 1, tracks: [], id: areaId};
+ const latestArea: AreaById = {start: 0n, end: 1n, tracks: [], id: areaId};
globals.state = createEmptyState();
globals.state.currentSelection = {kind: 'AREA', areaId};
globals.state.areas[areaId] = latestArea;
@@ -35,7 +35,7 @@ test('validAreaAfterUndefinedArea', () => {
test('UndefinedAreaAfterValidArea', () => {
const previousAreaId = '0';
const previous:
- AreaById = {startSec: 0, endSec: 1, tracks: [], id: previousAreaId};
+ AreaById = {start: 0n, end: 1n, tracks: [], id: previousAreaId};
globals.state = createEmptyState();
globals.state.currentSelection = {
kind: 'AREA',
@@ -71,7 +71,7 @@ test('UndefinedAreaAfterUndefinedArea', () => {
test('validAreaAfterValidArea', () => {
const previousAreaId = '0';
const previous:
- AreaById = {startSec: 0, endSec: 1, tracks: [], id: previousAreaId};
+ AreaById = {start: 0n, end: 1n, tracks: [], id: previousAreaId};
globals.state = createEmptyState();
globals.state.currentSelection = {
kind: 'AREA',
@@ -82,8 +82,7 @@ test('validAreaAfterValidArea', () => {
areaSelectionHandler.getAreaChange();
const currentAreaId = '1';
- const current:
- AreaById = {startSec: 1, endSec: 2, tracks: [], id: currentAreaId};
+ const current: AreaById = {start: 1n, end: 2n, tracks: [], id: currentAreaId};
globals.state.currentSelection = {
kind: 'AREA',
areaId: currentAreaId,
@@ -98,7 +97,7 @@ test('validAreaAfterValidArea', () => {
test('sameAreaSelected', () => {
const previousAreaId = '0';
const previous:
- AreaById = {startSec: 0, endSec: 1, tracks: [], id: previousAreaId};
+ AreaById = {start: 0n, end: 1n, tracks: [], id: previousAreaId};
globals.state = createEmptyState();
globals.state.currentSelection = {
kind: 'AREA',
@@ -109,8 +108,7 @@ test('sameAreaSelected', () => {
areaSelectionHandler.getAreaChange();
const currentAreaId = '0';
- const current:
- AreaById = {startSec: 0, endSec: 1, tracks: [], id: currentAreaId};
+ const current: AreaById = {start: 0n, end: 1n, tracks: [], id: currentAreaId};
globals.state.currentSelection = {
kind: 'AREA',
areaId: currentAreaId,
@@ -128,7 +126,7 @@ test('NonAreaSelectionAfterUndefinedArea', () => {
areaSelectionHandler.getAreaChange();
globals.state
- .currentSelection = {kind: 'COUNTER', leftTs: 0, rightTs: 0, id: 1};
+ .currentSelection = {kind: 'COUNTER', leftTs: 0n, rightTs: 0n, id: 1};
const [hasAreaChanged, selectedArea] = areaSelectionHandler.getAreaChange();
expect(hasAreaChanged).toEqual(false);
diff --git a/ui/src/controller/flamegraph_controller.ts b/ui/src/controller/flamegraph_controller.ts
index e94531dbe..31a74c369 100644
--- a/ui/src/controller/flamegraph_controller.ts
+++ b/ui/src/controller/flamegraph_controller.ts
@@ -27,7 +27,7 @@ import {
} from '../common/flamegraph_util';
import {NUM, STR} from '../common/query_result';
import {CallsiteInfo, FlamegraphState, ProfileType} from '../common/state';
-import {toNs} from '../common/time';
+import {tpDurationToSeconds, TPTime} from '../common/time';
import {FlamegraphDetails, globals} from '../frontend/globals';
import {publishFlamegraphDetails} from '../frontend/publish';
import {
@@ -145,8 +145,8 @@ export class FlamegraphController extends Controller<'main'> {
}
globals.dispatch(Actions.openFlamegraph({
upids,
- startNs: toNs(area.startSec),
- endNs: toNs(area.endSec),
+ start: area.start,
+ end: area.end,
type: ProfileType.PERF_SAMPLE,
viewingOption: PERF_SAMPLES_KEY,
}));
@@ -169,8 +169,8 @@ export class FlamegraphController extends Controller<'main'> {
const selectedFlamegraphState = {...selection};
const flamegraphMetadata = await this.getFlamegraphMetadata(
selection.type,
- selectedFlamegraphState.startNs,
- selectedFlamegraphState.endNs,
+ selectedFlamegraphState.start,
+ selectedFlamegraphState.end,
selectedFlamegraphState.upids);
if (flamegraphMetadata !== undefined) {
Object.assign(this.flamegraphDetails, flamegraphMetadata);
@@ -192,7 +192,7 @@ export class FlamegraphController extends Controller<'main'> {
selectedFlamegraphState.expandedCallsite.totalSize;
const key = `${selectedFlamegraphState.upids};${
- selectedFlamegraphState.startNs};${selectedFlamegraphState.endNs}`;
+ selectedFlamegraphState.start};${selectedFlamegraphState.end}`;
try {
const flamegraphData = await this.getFlamegraphData(
@@ -200,15 +200,15 @@ export class FlamegraphController extends Controller<'main'> {
selectedFlamegraphState.viewingOption ?
selectedFlamegraphState.viewingOption :
DEFAULT_VIEWING_OPTION,
- selection.startNs,
- selection.endNs,
+ selection.start,
+ selection.end,
selectedFlamegraphState.upids,
selectedFlamegraphState.type,
selectedFlamegraphState.focusRegex);
if (flamegraphData !== undefined && selection &&
selection.kind === selectedFlamegraphState.kind &&
- selection.startNs === selectedFlamegraphState.startNs &&
- selection.endNs === selectedFlamegraphState.endNs) {
+ selection.start === selectedFlamegraphState.start &&
+ selection.end === selectedFlamegraphState.end) {
const expandedFlamegraphData =
expandCallsites(flamegraphData, expandedId);
this.prepareAndMergeCallsites(
@@ -230,8 +230,8 @@ export class FlamegraphController extends Controller<'main'> {
private shouldRequestData(selection: FlamegraphState) {
return selection.kind === 'FLAMEGRAPH_STATE' &&
(this.lastSelectedFlamegraphState === undefined ||
- (this.lastSelectedFlamegraphState.startNs !== selection.startNs ||
- this.lastSelectedFlamegraphState.endNs !== selection.endNs ||
+ (this.lastSelectedFlamegraphState.start !== selection.start ||
+ this.lastSelectedFlamegraphState.end !== selection.end ||
this.lastSelectedFlamegraphState.type !== selection.type ||
!FlamegraphController.areArraysEqual(
this.lastSelectedFlamegraphState.upids, selection.upids) ||
@@ -267,7 +267,7 @@ export class FlamegraphController extends Controller<'main'> {
}
async getFlamegraphData(
- baseKey: string, viewingOption: string, startNs: number, endNs: number,
+ baseKey: string, viewingOption: string, start: TPTime, end: TPTime,
upids: number[], type: ProfileType,
focusRegex: string): Promise<CallsiteInfo[]> {
let currentData: CallsiteInfo[];
@@ -280,8 +280,8 @@ export class FlamegraphController extends Controller<'main'> {
// Collecting data for drawing flamegraph for selected profile.
// Data needs to be in following format:
// id, name, parent_id, depth, total_size
- const tableName = await this.prepareViewsAndTables(
- startNs, endNs, upids, type, focusRegex);
+ const tableName =
+ await this.prepareViewsAndTables(start, end, upids, type, focusRegex);
currentData = await this.getFlamegraphDataFromTables(
tableName, viewingOption, focusRegex);
this.flamegraphDatasets.set(key, currentData);
@@ -413,7 +413,7 @@ export class FlamegraphController extends Controller<'main'> {
}
private async prepareViewsAndTables(
- startNs: number, endNs: number, upids: number[], type: ProfileType,
+ start: TPTime, end: TPTime, upids: number[], type: ProfileType,
focusRegex: string): Promise<string> {
// Creating unique names for views so we can reuse and not delete them
// for each marker.
@@ -437,8 +437,8 @@ export class FlamegraphController extends Controller<'main'> {
cumulative_alloc_size, cumulative_count, cumulative_alloc_count,
size, alloc_size, count, alloc_count, source_file, line_number
from experimental_flamegraph
- where profile_type = '${flamegraphType}' and ${startNs} <= ts and
- ts <= ${endNs} and ${upidConditional}
+ where profile_type = '${flamegraphType}' and ${start} <= ts and
+ ts <= ${end} and ${upidConditional}
${focusRegexConditional}`);
}
return this.cache.getTableName(
@@ -447,7 +447,7 @@ export class FlamegraphController extends Controller<'main'> {
size, alloc_size, count, alloc_count, source_file, line_number
from experimental_flamegraph
where profile_type = '${flamegraphType}'
- and ts = ${endNs}
+ and ts = ${end}
and upid = ${upids[0]}
${focusRegexConditional}`);
}
@@ -455,7 +455,8 @@ export class FlamegraphController extends Controller<'main'> {
getMinSizeDisplayed(flamegraphData: CallsiteInfo[], rootSize?: number):
number {
const timeState = globals.state.frontendLocalState.visibleState;
- let width = (timeState.endSec - timeState.startSec) / timeState.resolution;
+ const dur = globals.stateVisibleTime().duration;
+ let width = tpDurationToSeconds(dur / timeState.resolution);
// TODO(168048193): Remove screen size hack:
width = Math.max(width, 800);
if (rootSize === undefined) {
@@ -465,11 +466,12 @@ export class FlamegraphController extends Controller<'main'> {
}
async getFlamegraphMetadata(
- type: ProfileType, startNs: number, endNs: number, upids: number[]) {
+ type: ProfileType, start: TPTime, end: TPTime,
+ upids: number[]): Promise<FlamegraphDetails|undefined> {
// Don't do anything if selection of the marker stayed the same.
if ((this.lastSelectedFlamegraphState !== undefined &&
- ((this.lastSelectedFlamegraphState.startNs === startNs &&
- this.lastSelectedFlamegraphState.endNs === endNs &&
+ ((this.lastSelectedFlamegraphState.start === start &&
+ this.lastSelectedFlamegraphState.end === end &&
FlamegraphController.areArraysEqual(
this.lastSelectedFlamegraphState.upids, upids))))) {
return undefined;
@@ -486,7 +488,7 @@ export class FlamegraphController extends Controller<'main'> {
for (let i = 0; it.valid(); ++i, it.next()) {
pids.push(it.pid);
}
- return {startNs, durNs: endNs - startNs, pids, upids, type};
+ return {start, dur: end - start, pids, upids, type};
}
private static areArraysEqual(a: number[], b: number[]) {
diff --git a/ui/src/controller/flow_events_controller.ts b/ui/src/controller/flow_events_controller.ts
index d89b514ff..07125e125 100644
--- a/ui/src/controller/flow_events_controller.ts
+++ b/ui/src/controller/flow_events_controller.ts
@@ -16,7 +16,7 @@ import {Engine} from '../common/engine';
import {featureFlags} from '../common/feature_flags';
import {NUM, STR_NULL} from '../common/query_result';
import {Area} from '../common/state';
-import {fromNs, toNs} from '../common/time';
+import {fromNs} from '../common/time';
import {Flow, globals} from '../frontend/globals';
import {publishConnectedFlows, publishSelectedFlows} from '../frontend/publish';
import {
@@ -241,8 +241,8 @@ export class FlowEventsController extends Controller<'main'> {
const area = globals.state.areas[areaId];
if (this.lastSelectedKind === 'AREA' && this.lastSelectedArea &&
this.lastSelectedArea.tracks.join(',') === area.tracks.join(',') &&
- this.lastSelectedArea.endSec === area.endSec &&
- this.lastSelectedArea.startSec === area.startSec) {
+ this.lastSelectedArea.end === area.end &&
+ this.lastSelectedArea.start === area.start) {
return;
}
@@ -268,8 +268,8 @@ export class FlowEventsController extends Controller<'main'> {
const tracks = `(${trackIds.join(',')})`;
- const startNs = toNs(area.startSec);
- const endNs = toNs(area.endSec);
+ const startNs = area.start;
+ const endNs = area.end;
const query = `
select
diff --git a/ui/src/controller/ftrace_controller.ts b/ui/src/controller/ftrace_controller.ts
index 132eda20e..a071ec542 100644
--- a/ui/src/controller/ftrace_controller.ts
+++ b/ui/src/controller/ftrace_controller.ts
@@ -12,13 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {FtraceFilterState} from 'src/common/state';
-
import {Engine} from '../common/engine';
-import {NUM, STR, STR_NULL} from '../common/query_result';
-import {TimeSpan, toNsCeil, toNsFloor} from '../common/time';
-import {FtraceEvent, globals as frontendGlobals} from '../frontend/globals';
-import {globals} from '../frontend/globals';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../common/high_precision_time';
+import {LONG, NUM, STR, STR_NULL} from '../common/query_result';
+import {FtraceFilterState, Pagination} from '../common/state';
+import {Span} from '../common/time';
+import {FtraceEvent, globals} from '../frontend/globals';
import {publishFtracePanelData} from '../frontend/publish';
import {ratelimit} from '../frontend/rate_limiters';
@@ -34,30 +36,12 @@ interface RetVal {
numEvents: number;
}
-function cloneFtraceFilterState(other: FtraceFilterState): FtraceFilterState {
- return {
- excludedNames: [...other.excludedNames],
- };
-}
-
-function ftraceFilterStateEq(
- a: FtraceFilterState, b: FtraceFilterState): boolean {
- if (a.excludedNames === b.excludedNames) return true;
- if (a.excludedNames.length !== b.excludedNames.length) return false;
-
- for (let i = 0; i < a.excludedNames.length; ++i) {
- if (a.excludedNames[i] !== b.excludedNames[i]) return false;
- }
-
- return true;
-}
-
export class FtraceController extends Controller<'main'> {
private engine: Engine;
- private oldSpan: TimeSpan = new TimeSpan(0, 0);
- private oldFtraceFilter: FtraceFilterState = {
- excludedNames: [],
- };
+ private oldSpan: Span<HighPrecisionTime> = HighPrecisionTimeSpan.ZERO;
+ private oldFtraceFilter?: FtraceFilterState;
+ private oldPagination?: Pagination;
+
constructor({engine}: FtraceControllerArgs) {
super('main');
this.engine = engine;
@@ -65,44 +49,38 @@ export class FtraceController extends Controller<'main'> {
run() {
if (this.shouldUpdate()) {
- this.updateEverything();
+ this.oldSpan = globals.frontendLocalState.visibleWindowTime;
+ this.oldFtraceFilter = globals.state.ftraceFilter;
+ this.oldPagination = globals.state.ftracePagination;
+ if (globals.state.ftracePagination.count > 0) {
+ this.lookupFtraceEventsRateLimited();
+ }
}
}
- private updateEverything = ratelimit(() => {
+ private lookupFtraceEventsRateLimited = ratelimit(() => {
const {offset, count} = globals.state.ftracePagination;
- this.oldSpan = frontendGlobals.frontendLocalState.visibleWindowTime;
- this.oldFtraceFilter =
- cloneFtraceFilterState(frontendGlobals.state.ftraceFilter);
- this.lookupFtraceEvents(offset, count).then(({events,
- offset,
- numEvents}: RetVal) => {
+ // The formatter doesn't like formatted chained methods :(
+ const promise = this.lookupFtraceEvents(offset, count);
+ promise.then(({events, offset, numEvents}: RetVal) => {
publishFtracePanelData({events, offset, numEvents});
});
}, 250);
private shouldUpdate(): boolean {
- if (this.oldSpan != frontendGlobals.frontendLocalState.visibleWindowTime) {
- // The visible window has changed, definitely update
- return true;
- }
-
- const globalPanelData = frontendGlobals.ftracePanelData;
- if (!globalPanelData) {
- // No state has been written yet, so we definitely need to update
+ // Has the visible window moved?
+ const visibleWindow = globals.frontendLocalState.visibleWindowTime;
+ if (!this.oldSpan.equals(visibleWindow)) {
return true;
}
- // Work out whether we've scrolled near our rendered bounds
- const {offset, count} = globals.state.ftracePagination;
- if (offset != globalPanelData.offset ||
- count != globalPanelData.events.length) {
+ // Has the pagination changed?
+ if (this.oldPagination !== globals.state.ftracePagination) {
return true;
}
- // Work out of the ftrace filter has changed
- const filter = frontendGlobals.state.ftraceFilter;
- if (!ftraceFilterStateEq(this.oldFtraceFilter, filter)) {
+ // Has the filter changed?
+ if (this.oldFtraceFilter !== globals.state.ftraceFilter) {
return true;
}
@@ -110,16 +88,21 @@ export class FtraceController extends Controller<'main'> {
}
async lookupFtraceEvents(offset: number, count: number): Promise<RetVal> {
- const appState = frontendGlobals.state;
- const frontendState = frontendGlobals.frontendLocalState;
+ const appState = globals.state;
+ const frontendState = globals.frontendLocalState;
const {start, end} = frontendState.visibleWindowTime;
- const startNs = toNsFloor(start);
- const endNs = toNsCeil(end);
+ const startNs = start.nanos;
+ const endNs = end.nanos;
const excludeList = appState.ftraceFilter.excludedNames;
const excludeListSql = excludeList.map((s) => `'${s}'`).join(',');
+ // TODO(stevegolton): This query can be slow when traces are huge.
+ // The number of events is only used for correctly sizing the panel's
+ // scroll container so that the scrollbar works as if the panel were fully
+ // populated.
+ // Perhaps we could work out some UX that doesn't need this.
let queryRes = await this.engine.query(`
select count(id) as numEvents
from ftrace_event
@@ -152,7 +135,7 @@ export class FtraceController extends Controller<'main'> {
const it = queryRes.iter(
{
id: NUM,
- ts: NUM,
+ ts: LONG,
name: STR,
cpu: NUM,
thread: STR_NULL,
diff --git a/ui/src/controller/logs_controller.ts b/ui/src/controller/logs_controller.ts
index d8f9b3a96..c931ce0dc 100644
--- a/ui/src/controller/logs_controller.ts
+++ b/ui/src/controller/logs_controller.ts
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../base/bigint_math';
import {Engine} from '../common/engine';
import {
LogBounds,
@@ -20,62 +21,61 @@ import {
LogEntriesKey,
LogExistsKey,
} from '../common/logs';
-import {NUM, STR} from '../common/query_result';
+import {LONG, LONG_NULL, NUM, STR} from '../common/query_result';
import {escapeGlob, escapeQuery} from '../common/query_utils';
import {LogFilteringCriteria} from '../common/state';
-import {fromNs, TimeSpan, toNsCeil, toNsFloor} from '../common/time';
+import {Span} from '../common/time';
+import {
+ TPTime,
+ TPTimeSpan,
+} from '../common/time';
import {globals} from '../frontend/globals';
import {publishTrackData} from '../frontend/publish';
import {Controller} from './controller';
async function updateLogBounds(
- engine: Engine, span: TimeSpan): Promise<LogBounds> {
- const vizStartNs = toNsFloor(span.start);
- const vizEndNs = toNsCeil(span.end);
-
- const countResult = await engine.query(`select
- ifnull(min(ts), 0) as minTs,
- ifnull(max(ts), 0) as maxTs,
- count(ts) as countTs
- from filtered_logs
- where ts >= ${vizStartNs}
- and ts <= ${vizEndNs}`);
-
- const countRow = countResult.firstRow({minTs: NUM, maxTs: NUM, countTs: NUM});
-
- const firstRowNs = countRow.minTs;
- const lastRowNs = countRow.maxTs;
- const total = countRow.countTs;
-
- const minResult = await engine.query(`
- select ifnull(max(ts), 0) as maxTs from filtered_logs where ts < ${
- vizStartNs}`);
- const startNs = minResult.firstRow({maxTs: NUM}).maxTs;
-
- const maxResult = await engine.query(`
- select ifnull(min(ts), 0) as minTs from filtered_logs where ts > ${
- vizEndNs}`);
- const endNs = maxResult.firstRow({minTs: NUM}).minTs;
-
- const startTs = startNs ? fromNs(startNs) : 0;
- const endTs = endNs ? fromNs(endNs) : Number.MAX_SAFE_INTEGER;
- const firstRowTs = firstRowNs ? fromNs(firstRowNs) : endTs;
- const lastRowTs = lastRowNs ? fromNs(lastRowNs) : startTs;
- return {
- startTs,
- endTs,
- firstRowTs,
- lastRowTs,
- total,
+ engine: Engine, span: Span<TPTime>): Promise<LogBounds> {
+ const vizStartNs = span.start;
+ const vizEndNs = span.end;
+
+ const vizFilter = `ts between ${vizStartNs} and ${vizEndNs}`;
+
+ const result = await engine.query(`select
+ min(ts) as minTs,
+ max(ts) as maxTs,
+ min(case when ${vizFilter} then ts end) as minVizTs,
+ max(case when ${vizFilter} then ts end) as maxVizTs,
+ count(case when ${vizFilter} then ts end) as countTs
+ from filtered_logs`);
+
+ const data = result.firstRow({
+ minTs: LONG_NULL,
+ maxTs: LONG_NULL,
+ minVizTs: LONG_NULL,
+ maxVizTs: LONG_NULL,
+ countTs: NUM,
+ });
+
+ const firstLogTs = data.minTs ?? 0n;
+ const lastLogTs = data.maxTs ?? BigintMath.INT64_MAX;
+
+ const bounds: LogBounds = {
+ firstLogTs,
+ lastLogTs,
+ firstVisibleLogTs: data.minVizTs ?? firstLogTs,
+ lastVisibleLogTs: data.maxVizTs ?? lastLogTs,
+ totalVisibleLogs: data.countTs,
};
+
+ return bounds;
}
async function updateLogEntries(
- engine: Engine, span: TimeSpan, pagination: Pagination):
+ engine: Engine, span: Span<TPTime>, pagination: Pagination):
Promise<LogEntries> {
- const vizStartNs = toNsFloor(span.start);
- const vizEndNs = toNsCeil(span.end);
+ const vizStartNs = span.start;
+ const vizEndNs = span.end;
const vizSqlBounds = `ts >= ${vizStartNs} and ts <= ${vizEndNs}`;
const rowsResult = await engine.query(`
@@ -101,7 +101,7 @@ async function updateLogEntries(
const processName = [];
const it = rowsResult.iter({
- ts: NUM,
+ ts: LONG,
prio: NUM,
tag: STR,
msg: STR,
@@ -179,7 +179,7 @@ export interface LogsControllerArgs {
*/
export class LogsController extends Controller<'main'> {
private engine: Engine;
- private span: TimeSpan;
+ private span: Span<TPTime>;
private pagination: Pagination;
private hasLogs = false;
private logFilteringCriteria?: LogFilteringCriteria;
@@ -189,7 +189,7 @@ export class LogsController extends Controller<'main'> {
constructor(args: LogsControllerArgs) {
super('main');
this.engine = args.engine;
- this.span = new TimeSpan(0, 10);
+ this.span = new TPTimeSpan(0n, BigInt(10e9));
this.pagination = new Pagination(0, 0);
this.hasAnyLogs().then((exists) => {
this.hasLogs = exists;
@@ -226,8 +226,7 @@ export class LogsController extends Controller<'main'> {
}
private async updateLogTracks() {
- const traceTime = globals.state.frontendLocalState.visibleState;
- const newSpan = new TimeSpan(traceTime.startSec, traceTime.endSec);
+ const newSpan = globals.stateVisibleTime();
const oldSpan = this.span;
const pagination = globals.state.logsPagination;
diff --git a/ui/src/controller/permalink_controller.ts b/ui/src/controller/permalink_controller.ts
index a382a406d..ad58b27ae 100644
--- a/ui/src/controller/permalink_controller.ts
+++ b/ui/src/controller/permalink_controller.ts
@@ -26,6 +26,7 @@ import {STATE_VERSION} from '../common/state';
import {
BUCKET_NAME,
buggyToSha256,
+ deserializeStateObject,
saveState,
saveTrace,
toSha256,
@@ -195,7 +196,7 @@ export class PermalinkController extends Controller<'main'> {
}
const text = await response.text();
const stateHash = await toSha256(text);
- const state = JSON.parse(text);
+ const state = deserializeStateObject(text);
if (stateHash !== id) {
// Old permalinks incorrectly dropped some digits from the
// hexdigest of the SHA256. We don't want to invalidate those
diff --git a/ui/src/controller/record_controller.ts b/ui/src/controller/record_controller.ts
index 598c85e97..5982af5c1 100644
--- a/ui/src/controller/record_controller.ts
+++ b/ui/src/controller/record_controller.ts
@@ -128,7 +128,8 @@ export function toPbtxt(configBuffer: Uint8Array): string {
return value.startsWith('MEMINFO_') || value.startsWith('VMSTAT_') ||
value.startsWith('STAT_') || value.startsWith('LID_') ||
value.startsWith('BATTERY_COUNTER_') || value === 'DISCARD' ||
- value === 'RING_BUFFER';
+ value === 'RING_BUFFER' || value === 'BACKGROUND' ||
+ value === 'USER_INITIATED';
}
// Since javascript doesn't have 64 bit numbers when converting protos to
// json the proto library encodes them as strings. This is lossy since
@@ -139,9 +140,10 @@ export function toPbtxt(configBuffer: Uint8Array): string {
function is64BitNumber(key: string): boolean {
return [
'maxFileSizeBytes',
+ 'pid',
'samplingIntervalBytes',
'shmemSizeBytes',
- 'pid',
+ 'timestampUnitMultiplier',
].includes(key);
}
function* message(msg: {}, indent: number): IterableIterator<string> {
diff --git a/ui/src/controller/search_controller.ts b/ui/src/controller/search_controller.ts
index d1df094d2..c5968c278 100644
--- a/ui/src/controller/search_controller.ts
+++ b/ui/src/controller/search_controller.ts
@@ -12,13 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../base/bigint_math';
import {sqliteString} from '../base/string_utils';
import {Engine} from '../common/engine';
import {NUM, STR} from '../common/query_result';
import {escapeSearchQuery} from '../common/query_utils';
import {CurrentSearchResults, SearchSummary} from '../common/search_data';
-import {TimeSpan} from '../common/time';
-import {toNs} from '../common/time';
+import {Span} from '../common/time';
+import {
+ TPDuration,
+ TPTime,
+ TPTimeSpan,
+} from '../common/time';
import {globals} from '../frontend/globals';
import {publishSearch, publishSearchResult} from '../frontend/publish';
@@ -30,8 +35,8 @@ export interface SearchControllerArgs {
export class SearchController extends Controller<'main'> {
private engine: Engine;
- private previousSpan: TimeSpan;
- private previousResolution: number;
+ private previousSpan: Span<TPTime>;
+ private previousResolution: TPDuration;
private previousSearch: string;
private updateInProgress: boolean;
private setupInProgress: boolean;
@@ -39,11 +44,11 @@ export class SearchController extends Controller<'main'> {
constructor(args: SearchControllerArgs) {
super('main');
this.engine = args.engine;
- this.previousSpan = new TimeSpan(0, 1);
+ this.previousSpan = new TPTimeSpan(0n, 1n);
this.previousSearch = '';
this.updateInProgress = false;
this.setupInProgress = true;
- this.previousResolution = 1;
+ this.previousResolution = 1n;
this.setup().finally(() => {
this.setupInProgress = false;
this.run();
@@ -70,9 +75,9 @@ export class SearchController extends Controller<'main'> {
omniboxState.mode === 'COMMAND') {
return;
}
- const newSpan = new TimeSpan(visibleState.startSec, visibleState.endSec);
+ const newSpan = globals.stateVisibleTime();
const newSearch = omniboxState.omnibox;
- let newResolution = visibleState.resolution;
+ const newResolution = visibleState.resolution;
if (this.previousSpan.contains(newSpan) &&
this.previousResolution === newResolution &&
newSearch === this.previousSearch) {
@@ -83,9 +88,8 @@ export class SearchController extends Controller<'main'> {
// TODO(hjd): We should restrict this to the start of the trace but
// that is not easily available here.
// N.B. Timestamps can be negative.
- const start = newSpan.start - newSpan.duration;
- const end = newSpan.end + newSpan.duration;
- this.previousSpan = new TimeSpan(start, end);
+ const {start, end} = newSpan.pad(newSpan.duration);
+ this.previousSpan = new TPTimeSpan(start, end);
this.previousResolution = newResolution;
this.previousSearch = newSearch;
if (newSearch === '' || newSearch.length < 4) {
@@ -105,25 +109,12 @@ export class SearchController extends Controller<'main'> {
return;
}
- let startNs = toNs(newSpan.start);
- let endNs = toNs(newSpan.end);
-
- // TODO(hjd): We shouldn't need to be so defensive here:
- if (!Number.isFinite(startNs)) {
- startNs = 0;
- }
- if (!Number.isFinite(endNs)) {
- endNs = 1;
- }
- if (!Number.isFinite(newResolution)) {
- newResolution = 1;
- }
-
this.updateInProgress = true;
- const computeSummary = this.update(newSearch, startNs, endNs, newResolution)
- .then((summary) => {
- publishSearch(summary);
- });
+ const computeSummary =
+ this.update(newSearch, newSpan.start, newSpan.end, newResolution)
+ .then((summary) => {
+ publishSearch(summary);
+ });
const computeResults =
this.specificSearch(newSearch).then((searchResults) => {
@@ -140,15 +131,14 @@ export class SearchController extends Controller<'main'> {
onDestroy() {}
private async update(
- search: string, startNs: number, endNs: number,
- resolution: number): Promise<SearchSummary> {
- const quantumNs = Math.round(resolution * 10 * 1e9);
-
+ search: string, startNs: TPTime, endNs: TPTime,
+ resolution: TPDuration): Promise<SearchSummary> {
const searchLiteral = escapeSearchQuery(search);
- startNs = Math.floor(startNs / quantumNs) * quantumNs;
+ const quantumNs = resolution * 10n;
+ startNs = BigintMath.quantizeFloor(startNs, quantumNs);
- const windowDur = Math.max(endNs - startNs, 1);
+ const windowDur = BigintMath.max(endNs - startNs, 1n);
await this.query(`update search_summary_window set
window_start=${startNs},
window_dur=${windowDur},
diff --git a/ui/src/controller/selection_controller.ts b/ui/src/controller/selection_controller.ts
index 66cf3d005..b5a390769 100644
--- a/ui/src/controller/selection_controller.ts
+++ b/ui/src/controller/selection_controller.ts
@@ -16,14 +16,23 @@ import {assertTrue} from '../base/logging';
import {Arg, Args} from '../common/arg_types';
import {Engine} from '../common/engine';
import {
+ LONG,
NUM,
NUM_NULL,
STR,
STR_NULL,
} from '../common/query_result';
import {ChromeSliceSelection} from '../common/state';
-import {fromNs, toNs} from '../common/time';
-import {SliceDetails, ThreadStateDetails} from '../frontend/globals';
+import {
+ tpDurationFromSql,
+ TPTime,
+ tpTimeFromSql,
+} from '../common/time';
+import {
+ CounterDetails,
+ SliceDetails,
+ ThreadStateDetails,
+} from '../frontend/globals';
import {globals} from '../frontend/globals';
import {
publishCounterDetails,
@@ -176,10 +185,10 @@ export class SelectionController extends Controller<'main'> {
case 'id':
break;
case 'ts':
- ts = fromNs(Number(v)) - globals.state.traceTime.startSec;
+ ts = tpTimeFromSql(v);
break;
case 'thread_ts':
- threadTs = fromNs(Number(v));
+ threadTs = tpTimeFromSql(v);
break;
case 'absTime':
if (v) absTime = `${v}`;
@@ -188,10 +197,10 @@ export class SelectionController extends Controller<'main'> {
name = `${v}`;
break;
case 'dur':
- dur = fromNs(Number(v));
+ dur = tpDurationFromSql(v);
break;
case 'thread_dur':
- threadDur = fromNs(Number(v));
+ threadDur = tpDurationFromSql(v);
break;
case 'category':
case 'cat':
@@ -326,13 +335,13 @@ export class SelectionController extends Controller<'main'> {
const selection = globals.state.currentSelection;
if (result.numRows() > 0 && selection) {
const row = result.firstRow({
- ts: NUM,
- dur: NUM,
+ ts: LONG,
+ dur: LONG,
});
- const ts = row.ts;
- const timeFromStart = fromNs(ts) - globals.state.traceTime.startSec;
- const dur = fromNs(row.dur);
- const selected: ThreadStateDetails = {ts: timeFromStart, dur};
+ const selected: ThreadStateDetails = {
+ ts: row.ts,
+ dur: row.dur,
+ };
publishThreadStateDetails(selected);
}
}
@@ -353,8 +362,8 @@ export class SelectionController extends Controller<'main'> {
const selection = globals.state.currentSelection;
if (result.numRows() > 0 && selection) {
const row = result.firstRow({
- ts: NUM,
- dur: NUM,
+ ts: LONG,
+ dur: LONG,
priority: NUM,
endState: STR_NULL,
utid: NUM,
@@ -362,15 +371,14 @@ export class SelectionController extends Controller<'main'> {
threadStateId: NUM_NULL,
});
const ts = row.ts;
- const timeFromStart = fromNs(ts) - globals.state.traceTime.startSec;
- const dur = fromNs(row.dur);
+ const dur = row.dur;
const priority = row.priority;
const endState = row.endState;
const utid = row.utid;
const cpu = row.cpu;
const threadStateId = row.threadStateId || undefined;
const selected: SliceDetails = {
- ts: timeFromStart,
+ ts,
dur,
priority,
endState,
@@ -391,7 +399,8 @@ export class SelectionController extends Controller<'main'> {
}
}
- async counterDetails(ts: number, rightTs: number, id: number) {
+ async counterDetails(ts: TPTime, rightTs: TPTime, id: number):
+ Promise<CounterDetails> {
const counter = await this.args.engine.query(
`SELECT value, track_id as trackId FROM counter WHERE id = ${id}`);
const row = counter.iter({
@@ -407,17 +416,15 @@ export class SelectionController extends Controller<'main'> {
IFNULL(value, 0) as value
FROM counter WHERE ts < ${ts} and track_id = ${trackId}`);
const previousValue = previous.firstRow({value: NUM}).value;
- const endTs =
- rightTs !== -1 ? rightTs : toNs(globals.state.traceTime.endSec);
+ const endTs = rightTs !== -1n ? rightTs : globals.state.traceTime.end;
const delta = value - previousValue;
const duration = endTs - ts;
- const startTime = fromNs(ts) - globals.state.traceTime.startSec;
const uiTrackId = globals.state.uiTrackIdByTraceTrackId[trackId];
const name = uiTrackId ? globals.state.tracks[uiTrackId].name : undefined;
- return {startTime, value, delta, duration, name};
+ return {startTime: ts, value, delta, duration, name};
}
- async schedulingDetails(ts: number, utid: number|Long) {
+ async schedulingDetails(ts: TPTime, utid: number|Long) {
// Find the ts of the first wakeup before the current slice.
const wakeResult = await this.args.engine.query(`
select ts, waker_utid as wakerUtid
@@ -430,7 +437,7 @@ export class SelectionController extends Controller<'main'> {
return undefined;
}
- const wakeFirstRow = wakeResult.firstRow({ts: NUM, wakerUtid: NUM_NULL});
+ const wakeFirstRow = wakeResult.firstRow({ts: LONG, wakerUtid: NUM_NULL});
const wakeupTs = wakeFirstRow.ts;
const wakerUtid = wakeFirstRow.wakerUtid;
if (wakerUtid === null) {
@@ -449,7 +456,7 @@ export class SelectionController extends Controller<'main'> {
// If this is the first sched slice for this utid or if the wakeup found
// was after the previous slice then we know the wakeup was for this slice.
if (prevSchedResult.numRows() !== 0 &&
- wakeupTs < prevSchedResult.firstRow({ts: NUM}).ts) {
+ wakeupTs < prevSchedResult.firstRow({ts: LONG}).ts) {
return undefined;
}
@@ -468,7 +475,7 @@ export class SelectionController extends Controller<'main'> {
}
const wakerRow = wakerResult.firstRow({cpu: NUM});
- return {wakeupTs: fromNs(wakeupTs), wakerUtid, wakerCpu: wakerRow.cpu};
+ return {wakeupTs, wakerUtid, wakerCpu: wakerRow.cpu};
}
async computeThreadDetails(utid: number):
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index f57105d2d..f0e2d02b0 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../base/bigint_math';
import {assertExists, assertTrue} from '../base/logging';
import {
Actions,
@@ -20,15 +21,30 @@ import {
import {cacheTrace} from '../common/cache_manager';
import {Engine} from '../common/engine';
import {featureFlags, Flag, PERF_SAMPLE_FLAG} from '../common/feature_flags';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../common/high_precision_time';
import {HttpRpcEngine} from '../common/http_rpc_engine';
import {
getEnabledMetatracingCategories,
isMetatracingEnabled,
} from '../common/metatracing';
-import {NUM, NUM_NULL, QueryError, STR, STR_NULL} from '../common/query_result';
+import {
+ LONG,
+ NUM,
+ NUM_NULL,
+ QueryError,
+ STR,
+ STR_NULL,
+} from '../common/query_result';
import {onSelectionChanged} from '../common/selection_observer';
import {defaultTraceTime, EngineMode, ProfileType} from '../common/state';
-import {TimeSpan, toNs, toNsCeil, toNsFloor} from '../common/time';
+import {Span} from '../common/time';
+import {
+ TPTime,
+ TPTimeSpan,
+} from '../common/time';
import {resetEngineWorker, WasmEngineProxy} from '../common/wasm_engine_proxy';
import {BottomTabList} from '../frontend/bottom_tab';
import {
@@ -39,6 +55,7 @@ import {
} from '../frontend/globals';
import {showModal} from '../frontend/modal';
import {
+ clearOverviewData,
publishFtraceCounters,
publishMetricError,
publishOverviewData,
@@ -113,7 +130,6 @@ const METRICS = [
'android_dma_heap',
'android_surfaceflinger',
'android_batt',
- 'android_camera',
'android_other_traces',
'chrome_dropped_frames',
'chrome_long_latency',
@@ -416,11 +432,11 @@ export class TraceController extends Controller<States> {
const traceUuid = await this.cacheCurrentTrace();
const traceTime = await this.engine.getTraceTimeBounds();
- const startSec = traceTime.start;
- const endSec = traceTime.end;
+ const start = traceTime.start;
+ const end = traceTime.end;
const traceTimeState = {
- startSec,
- endSec,
+ start,
+ end,
};
const shownJsonWarning =
@@ -453,16 +469,16 @@ export class TraceController extends Controller<States> {
Actions.setTraceTime(traceTimeState),
];
- const [startVisibleTime, endVisibleTime] =
- await computeVisibleTime(startSec, endSec, isJsonTrace, this.engine);
+ const visibleTimeSpan = await computeVisibleTime(
+ traceTime.start, traceTime.end, isJsonTrace, this.engine);
// We don't know the resolution at this point. However this will be
// replaced in 50ms so a guess is fine.
- const resolution = (endVisibleTime - startVisibleTime) / 1000;
+ const resolution = visibleTimeSpan.duration.divide(1000).toTPTime();
actions.push(Actions.setVisibleTraceTime({
- startSec: startVisibleTime,
- endSec: endVisibleTime,
+ start: visibleTimeSpan.start.toTPTime(),
+ end: visibleTimeSpan.end.toTPTime(),
lastUpdate: Date.now() / 1000,
- resolution,
+ resolution: BigintMath.max(resolution, 1n),
}));
globals.dispatchMultiple(actions);
@@ -486,7 +502,7 @@ export class TraceController extends Controller<States> {
// Pull out the counts ftrace events by name
const query = `select
name,
- count(*) as cnt
+ count(name) as cnt
from ftrace_event
group by name
order by cnt desc`;
@@ -540,8 +556,8 @@ export class TraceController extends Controller<States> {
if (profile.numRows() !== 1) return;
const row = profile.firstRow({upid: NUM});
const upid = row.upid;
- const leftTs = toNs(globals.state.traceTime.startSec);
- const rightTs = toNs(globals.state.traceTime.endSec);
+ const leftTs = globals.state.traceTime.start;
+ const rightTs = globals.state.traceTime.end;
globals.dispatch(Actions.selectPerfSamples(
{id: 0, upid, leftTs, rightTs, type: ProfileType.PERF_SAMPLE}));
}
@@ -560,7 +576,7 @@ export class TraceController extends Controller<States> {
order by ts limit 1`;
const profile = await assertExists(this.engine).query(query);
if (profile.numRows() !== 1) return;
- const row = profile.firstRow({ts: NUM, type: STR, upid: NUM});
+ const row = profile.firstRow({ts: LONG, type: STR, upid: NUM});
const ts = row.ts;
const type = profileType(row.type);
const upid = row.upid;
@@ -610,31 +626,32 @@ export class TraceController extends Controller<States> {
publishThreads(threads);
}
- private async loadTimelineOverview(traceTime: TimeSpan) {
+ private async loadTimelineOverview(trace: Span<TPTime>) {
+ clearOverviewData();
+
const engine = assertExists<Engine>(this.engine);
- const numSteps = 100;
- const stepSec = traceTime.duration / numSteps;
+ const stepSize = BigintMath.max(1n, trace.duration / 100n);
let hasSchedOverview = false;
- for (let step = 0; step < numSteps; step++) {
+ for (let start = trace.start; start < trace.end; start += stepSize) {
+ const progress = start - trace.start;
+ const ratio = Number(progress) / Number(trace.duration);
this.updateStatus(
- 'Loading overview ' +
- `${Math.round((step + 1) / numSteps * 1000) / 10}%`);
- const startSec = traceTime.start + step * stepSec;
- const startNs = toNsFloor(startSec);
- const endSec = startSec + stepSec;
- const endNs = toNsCeil(endSec);
+ 'Loading overview ' +
+ `${Math.round(ratio * 100)}%`);
+ const end = start + stepSize;
// Sched overview.
const schedResult = await engine.query(
- `select sum(dur)/${stepSec}/1e9 as load, cpu from sched ` +
- `where ts >= ${startNs} and ts < ${endNs} and utid != 0 ` +
- 'group by cpu order by cpu');
+ `select cast(sum(dur) as float)/${
+ stepSize} as load, cpu from sched ` +
+ `where ts >= ${start} and ts < ${end} and utid != 0 ` +
+ 'group by cpu order by cpu');
const schedData: {[key: string]: QuantizedLoad} = {};
const it = schedResult.iter({load: NUM, cpu: NUM});
for (; it.valid(); it.next()) {
const load = it.load;
const cpu = it.cpu;
- schedData[cpu] = {startSec, endSec, load};
+ schedData[cpu] = {start, end, load};
hasSchedOverview = true;
}
publishOverviewData(schedData);
@@ -645,16 +662,15 @@ export class TraceController extends Controller<States> {
}
// Slices overview.
- const traceStartNs = toNs(traceTime.start);
- const stepSecNs = toNs(stepSec);
const sliceResult = await engine.query(`select
bucket,
upid,
- ifnull(sum(utid_sum) / cast(${stepSecNs} as float), 0) as load
+ ifnull(sum(utid_sum) / cast(${stepSize} as float), 0) as load
from thread
inner join (
select
- ifnull(cast((ts - ${traceStartNs})/${stepSecNs} as int), 0) as bucket,
+ ifnull(cast((ts - ${trace.start})/${
+ stepSize} as int), 0) as bucket,
sum(dur) as utid_sum,
utid
from slice
@@ -665,21 +681,21 @@ export class TraceController extends Controller<States> {
group by bucket, upid`);
const slicesData: {[key: string]: QuantizedLoad[]} = {};
- const it = sliceResult.iter({bucket: NUM, upid: NUM, load: NUM});
+ const it = sliceResult.iter({bucket: LONG, upid: NUM, load: NUM});
for (; it.valid(); it.next()) {
const bucket = it.bucket;
const upid = it.upid;
const load = it.load;
- const startSec = traceTime.start + stepSec * bucket;
- const endSec = startSec + stepSec;
+ const start = trace.start + stepSize * bucket;
+ const end = start + stepSize;
const upidStr = upid.toString();
let loadArray = slicesData[upidStr];
if (loadArray === undefined) {
loadArray = slicesData[upidStr] = [];
}
- loadArray.push({startSec, endSec, load});
+ loadArray.push({start, end, load});
}
publishOverviewData(slicesData);
}
@@ -890,48 +906,48 @@ export class TraceController extends Controller<States> {
}
}
-async function computeTraceReliableRangeStart(engine: Engine): Promise<number> {
+async function computeTraceReliableRangeStart(engine: Engine): Promise<TPTime> {
const result =
await engine.query(`SELECT RUN_METRIC('chrome/chrome_reliable_range.sql');
SELECT start FROM chrome_reliable_range`);
- const bounds = result.firstRow({start: NUM});
- return bounds.start / 1e9;
+ const bounds = result.firstRow({start: LONG});
+ return bounds.start;
}
async function computeVisibleTime(
- traceStartSec: number,
- traceEndSec: number,
- isJsonTrace: boolean,
- engine: Engine): Promise<[number, number]> {
+ traceStart: TPTime, traceEnd: TPTime, isJsonTrace: boolean, engine: Engine):
+ Promise<Span<HighPrecisionTime>> {
// if we have non-default visible state, update the visible time to it
- const previousVisibleState = globals.state.frontendLocalState.visibleState;
- if (!(previousVisibleState.startSec === defaultTraceTime.startSec &&
- previousVisibleState.endSec === defaultTraceTime.endSec) &&
- (previousVisibleState.startSec >= traceStartSec &&
- previousVisibleState.endSec <= traceEndSec)) {
- return [previousVisibleState.startSec, previousVisibleState.endSec];
+ const previousVisibleState = globals.stateVisibleTime();
+ const defaultTraceSpan =
+ new TPTimeSpan(defaultTraceTime.start, defaultTraceTime.end);
+ if (!(previousVisibleState.start === defaultTraceSpan.start &&
+ previousVisibleState.end === defaultTraceSpan.end) &&
+ (previousVisibleState.start >= traceStart &&
+ previousVisibleState.end <= traceEnd)) {
+ return HighPrecisionTimeSpan.fromTpTime(
+ previousVisibleState.start, previousVisibleState.end);
}
// initialise visible time to the trace time bounds
- let visibleStartSec = traceStartSec;
- let visibleEndSec = traceEndSec;
+ let visibleStartSec = traceStart;
+ let visibleEndSec = traceEnd;
// compare start and end with metadata computed by the trace processor
const mdTime = await engine.getTracingMetadataTimeBounds();
// make sure the bounds hold
- if (Math.max(visibleStartSec, mdTime.start) <
- Math.min(visibleEndSec, mdTime.end)) {
- visibleStartSec =
- Math.max(visibleStartSec, mdTime.start);
- visibleEndSec = Math.min(visibleEndSec, mdTime.end);
+ if (BigintMath.max(visibleStartSec, mdTime.start) <
+ BigintMath.min(visibleEndSec, mdTime.end)) {
+ visibleStartSec = BigintMath.max(visibleStartSec, mdTime.start);
+ visibleEndSec = BigintMath.min(visibleEndSec, mdTime.end);
}
// Trace Processor doesn't support the reliable range feature for JSON
// traces.
if (!isJsonTrace && ENABLE_CHROME_RELIABLE_RANGE_ZOOM_FLAG.get()) {
const reliableRangeStart = await computeTraceReliableRangeStart(engine);
- visibleStartSec = Math.max(visibleStartSec, reliableRangeStart);
+ visibleStartSec = BigintMath.max(visibleStartSec, reliableRangeStart);
}
- return [visibleStartSec, visibleEndSec];
+ return HighPrecisionTimeSpan.fromTpTime(visibleStartSec, visibleEndSec);
}
diff --git a/ui/src/controller/track_controller.ts b/ui/src/controller/track_controller.ts
index 46d1f1f26..73b98969e 100644
--- a/ui/src/controller/track_controller.ts
+++ b/ui/src/controller/track_controller.ts
@@ -12,11 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../base/bigint_math';
import {assertExists, assertTrue} from '../base/logging';
import {Engine} from '../common/engine';
import {Registry} from '../common/registry';
import {TraceTime, TrackState} from '../common/state';
-import {fromNs, toNs} from '../common/time';
+import {
+ TPDuration,
+ TPTime,
+ tpTimeFromSeconds,
+ TPTimeSpan,
+} from '../common/time';
import {LIMIT, TrackData} from '../common/track_data';
import {globals} from '../frontend/globals';
import {publishTrackData} from '../frontend/publish';
@@ -70,7 +76,7 @@ export abstract class TrackController<
// Must be overridden by the track implementation. Is invoked when the track
// frontend runs out of cached data. The derived track controller is expected
// to publish new track data in response to this call.
- abstract onBoundsChange(start: number, end: number, resolution: number):
+ abstract onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data>;
get trackState(): TrackState {
@@ -129,6 +135,7 @@ export abstract class TrackController<
}
shouldRequestData(traceTime: TraceTime): boolean {
+ const tspan = new TPTimeSpan(traceTime.start, traceTime.end);
if (this.data === undefined) return true;
if (this.shouldReload()) return true;
@@ -137,15 +144,14 @@ export abstract class TrackController<
if (atLimit) {
// We request more data than the window, so add window duration to find
// the previous window.
- const prevWindowStart =
- this.data.start + (traceTime.startSec - traceTime.endSec);
- return traceTime.startSec !== prevWindowStart;
+ const prevWindowStart = this.data.start + tspan.duration;
+ return tspan.start !== prevWindowStart;
}
// Otherwise request more data only when out of range of current data or
// resolution has changed.
- const inRange = traceTime.startSec >= this.data.start &&
- traceTime.endSec <= this.data.end;
+ const inRange =
+ tspan.start >= this.data.start && tspan.end <= this.data.end;
return !inRange ||
this.data.resolution !==
globals.state.frontendLocalState.visibleState.resolution;
@@ -162,8 +168,7 @@ export abstract class TrackController<
return undefined;
}
- const bounds = globals.state.traceTime;
- const traceDurNs = toNs(bounds.endSec - bounds.startSec);
+ const traceDuration = globals.stateTraceTime().duration;
// For large traces, going through the raw table in the most zoomed-out
// states can be very expensive as this can involve going through O(millions
@@ -198,7 +203,7 @@ export abstract class TrackController<
// Compute the outermost bucket size. This acts as a starting point for
// computing the cached size.
const outermostResolutionLevel =
- Math.ceil(Math.log2(traceDurNs / approxWidthPx));
+ Math.ceil(Math.log2(traceDuration.nanos / approxWidthPx));
const outermostBucketNs = Math.pow(2, outermostResolutionLevel);
// This constant decides how many resolution levels down from our outermost
@@ -232,11 +237,11 @@ export abstract class TrackController<
run() {
const visibleState = globals.state.frontendLocalState.visibleState;
- if (visibleState === undefined || visibleState.resolution === undefined ||
- visibleState.resolution === Infinity) {
+ if (visibleState === undefined) {
return;
}
- const dur = visibleState.endSec - visibleState.startSec;
+ const visibleTimeSpan = globals.stateVisibleTime();
+ const dur = visibleTimeSpan.duration;
if (globals.state.visibleTracks.includes(this.trackId) &&
this.shouldRequestData(visibleState)) {
if (this.requestingData) {
@@ -253,16 +258,14 @@ export abstract class TrackController<
.then(() => {
this.isSetup = true;
let resolution = visibleState.resolution;
- // TODO(hjd): We shouldn't have to be so defensive here.
- if (Math.log2(toNs(resolution)) % 1 !== 0) {
- // resolution is in pixels per second so 1000 means
- // 1px = 1ms.
- resolution =
- fromNs(Math.pow(2, Math.floor(Math.log2(toNs(1000)))));
+
+ if (BigintMath.popcount(resolution) !== 1) {
+ resolution = BigintMath.bitFloor(tpTimeFromSeconds(1000));
}
+
return this.onBoundsChange(
- visibleState.startSec - dur,
- visibleState.endSec + dur,
+ visibleTimeSpan.start - dur,
+ visibleTimeSpan.end + dur,
resolution);
})
.then((data) => {
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index 241e24865..488240082 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -25,6 +25,7 @@ import {Engine, EngineProxy} from '../common/engine';
import {featureFlags, PERF_SAMPLE_FLAG} from '../common/feature_flags';
import {pluginManager} from '../common/plugins';
import {
+ LONG_NULL,
NUM,
NUM_NULL,
STR,
@@ -61,6 +62,12 @@ import {
PROCESS_SCHEDULING_TRACK_KIND,
} from '../tracks/process_scheduling';
import {PROCESS_SUMMARY_TRACK} from '../tracks/process_summary';
+import {
+ ENABLE_SCROLL_JANK_PLUGIN_V2,
+ INPUT_LATENCY_TRACK,
+} from '../tracks/scroll_jank';
+import {addLatenciesTrack} from '../tracks/scroll_jank/event_latency_track';
+import {addTopLevelScrollTrack} from '../tracks/scroll_jank/scroll_track';
import {THREAD_STATE_TRACK_KIND} from '../tracks/thread_state';
const TRACKS_V2_FLAG = featureFlags.register({
@@ -207,6 +214,25 @@ class TrackDecider {
}
}
+ async addScrollJankTracks(engine: Engine): Promise<void> {
+ const topLevelScrolls = addTopLevelScrollTrack(engine);
+ const topLevelScrollsResult = await topLevelScrolls;
+ let originalLength = this.tracksToAdd.length;
+ this.tracksToAdd.length += topLevelScrollsResult.tracksToAdd.length;
+ for (let i = 0; i < topLevelScrollsResult.tracksToAdd.length; ++i) {
+ this.tracksToAdd[i + originalLength] =
+ topLevelScrollsResult.tracksToAdd[i];
+ }
+
+ originalLength = this.tracksToAdd.length;
+ const eventLatencies = addLatenciesTrack(engine);
+ const eventLatencyResult = await eventLatencies;
+ this.tracksToAdd.length += eventLatencyResult.tracksToAdd.length;
+ for (let i = 0; i < eventLatencyResult.tracksToAdd.length; ++i) {
+ this.tracksToAdd[i + originalLength] = eventLatencyResult.tracksToAdd[i];
+ }
+ }
+
async addCpuFreqTracks(engine: EngineProxy): Promise<void> {
const cpus = await this.engine.getCpus();
@@ -265,20 +291,21 @@ class TrackDecider {
async addGlobalAsyncTracks(engine: EngineProxy): Promise<void> {
const rawGlobalAsyncTracks = await engine.query(`
- with global_tracks as materialized (
+ with tracks_with_slices as materialized (
+ select distinct track_id
+ from slice
+ ),
+ global_tracks as (
select
track.parent_id as parent_id,
track.id as track_id,
- track.name as name,
- count(1) cnt
+ track.name as name
from track
- join slice on slice.track_id = track.id
+ join tracks_with_slices on tracks_with_slices.track_id = track.id
where
track.type = "track"
or track.type = "gpu_track"
or track.type = "cpu_track"
- group by track_id
- having cnt > 0
),
global_tracks_grouped as (
select
@@ -308,6 +335,7 @@ class TrackDecider {
});
const parentIdToGroupId = new Map<number, string>();
+ let scrollJankRendered = false;
for (; it.valid(); it.next()) {
const kind = ASYNC_SLICE_TRACK_KIND;
@@ -352,6 +380,13 @@ class TrackDecider {
}
}
+ if (ENABLE_SCROLL_JANK_PLUGIN_V2.get() && !scrollJankRendered &&
+ name.includes(INPUT_LATENCY_TRACK)) {
+ // This ensures that the scroll jank tracks render above the tracks
+ // for GestureScrollUpdate.
+ await this.addScrollJankTracks(this.engine);
+ scrollJankRendered = true;
+ }
const track = {
engineId: this.engineId,
kind,
@@ -405,45 +440,6 @@ class TrackDecider {
}
}
- async addGlobalCounterTracks(engine: EngineProxy): Promise<void> {
- // Add global or GPU counter tracks that are not bound to any pid/tid.
- const globalCounters = await engine.query(`
- select name, id
- from (
- select name, id
- from counter_track
- where type = 'counter_track'
- union
- select name, id
- from gpu_counter_track
- where name != 'gpufreq'
- )
- order by name
- `);
-
- const it = globalCounters.iter({
- name: STR,
- id: NUM,
- });
-
- for (; it.valid(); it.next()) {
- const name = it.name;
- const trackId = it.id;
- this.tracksToAdd.push({
- engineId: this.engineId,
- kind: COUNTER_TRACK_KIND,
- name,
- trackSortKey: PrimaryTrackSortKey.COUNTER_TRACK,
- trackGroup: SCROLLING_TRACK_GROUP,
- config: {
- name,
- trackId,
- scale: getCounterScale(name),
- },
- });
- }
- }
-
async addCpuPerfCounterTracks(engine: EngineProxy): Promise<void> {
// Perf counter tracks are bound to CPUs, follow the scheduling and
// frequency track naming convention ("Cpu N ...").
@@ -720,15 +716,12 @@ class TrackDecider {
}
async addFtraceTrack(engine: EngineProxy): Promise<void> {
- const query = `select
- cpu,
- count(*) as cnt
+ const query = `select distinct cpu
from ftrace_event
- where cpu + 1 > 1 or utid + 1 > 1
- group by cpu`;
+ where cpu + 1 > 1 or utid + 1 > 1`;
const result = await engine.query(query);
- const it = result.iter({cpu: NUM, cnt: NUM});
+ const it = result.iter({cpu: NUM});
let groupUuid = undefined;
let summaryTrackId = undefined;
@@ -1000,9 +993,9 @@ class TrackDecider {
upid: NUM_NULL,
tid: NUM_NULL,
threadName: STR_NULL,
- startTs: NUM_NULL,
+ startTs: LONG_NULL,
trackId: NUM,
- endTs: NUM_NULL,
+ endTs: LONG_NULL,
});
for (; it.valid(); it.next()) {
const utid = it.utid;
@@ -1317,8 +1310,8 @@ class TrackDecider {
upid: NUM,
pid: NUM_NULL,
processName: STR_NULL,
- startTs: NUM_NULL,
- endTs: NUM_NULL,
+ startTs: LONG_NULL,
+ endTs: LONG_NULL,
});
for (let i = 0; it.valid(); ++i, it.next()) {
const pid = it.pid;
diff --git a/ui/src/frontend/aggregation_panel.ts b/ui/src/frontend/aggregation_panel.ts
index ddcb6baf5..6bd642269 100644
--- a/ui/src/frontend/aggregation_panel.ts
+++ b/ui/src/frontend/aggregation_panel.ts
@@ -22,6 +22,7 @@ import {
} from '../common/aggregation_data';
import {colorForState, textColorForState} from '../common/colorizer';
import {translateState} from '../common/thread_state';
+import {tpTimeToMillis} from '../common/time';
import {globals} from './globals';
import {Panel} from './panel';
@@ -111,7 +112,8 @@ export class AggregationPanel extends Panel<AggregationPanelAttrs> {
const selection = globals.state.currentSelection;
if (selection === null || selection.kind !== 'AREA') return undefined;
const selectedArea = globals.state.areas[selection.areaId];
- const rangeDurationMs = (selectedArea.endSec - selectedArea.startSec) * 1e3;
+ const rangeDurationMs =
+ tpTimeToMillis(selectedArea.end - selectedArea.start);
return m('.time-range', `Selected range: ${rangeDurationMs.toFixed(6)} ms`);
}
diff --git a/ui/src/frontend/base_slice_track.ts b/ui/src/frontend/base_slice_track.ts
index ac3cad07b..77c6e6d9a 100644
--- a/ui/src/frontend/base_slice_track.ts
+++ b/ui/src/frontend/base_slice_track.ts
@@ -22,7 +22,12 @@ import {
} from '../common/colorizer';
import {NUM} from '../common/query_result';
import {Selection, SelectionKind} from '../common/state';
-import {fromNs, toNs} from '../common/time';
+import {
+ fromNs,
+ tpDurationFromNanos,
+ TPTime,
+ tpTimeFromNanos,
+} from '../common/time';
import {checkerboardExcept} from './checkerboard';
import {globals} from './globals';
@@ -45,7 +50,7 @@ const DEFAULT_SLICE_COLOR = UNEXPECTED_PINK_COLOR;
// Exposed and standalone to allow for testing without making this
// visible to subclasses.
function filterVisibleSlices<S extends Slice>(
- slices: S[], startS: number, endS: number): S[] {
+ slices: S[], start: TPTime, end: TPTime): S[] {
// Here we aim to reduce the number of slices we have to draw
// by ignoring those that are not visible. A slice is visible iff:
// slice.start + slice.duration >= start && slice.start <= end
@@ -89,7 +94,7 @@ function filterVisibleSlices<S extends Slice>(
// For all slice in slices: slice.startS > endS (e.g. all slices are to the
// right). Since the slices are sorted by startS we can check this easily:
const maybeFirstSlice: S|undefined = slices[0];
- if (maybeFirstSlice && maybeFirstSlice.startS > endS) {
+ if (maybeFirstSlice && maybeFirstSlice.start > end) {
return [];
}
// It's not possible to easily check the analogous edge case where all slices
@@ -108,15 +113,15 @@ function filterVisibleSlices<S extends Slice>(
let endIdx = slices.length;
for (; startIdx < endIdx; ++startIdx) {
const slice = slices[startIdx];
- const sliceEndS = slice.startS + slice.durationS;
- if (sliceEndS >= startS && slice.startS <= endS) {
+ const sliceEndS = slice.start + slice.duration;
+ if (sliceEndS >= start && slice.start <= end) {
break;
}
}
for (; startIdx < endIdx; --endIdx) {
const slice = slices[endIdx - 1];
- const sliceEndS = slice.startS + slice.durationS;
- if (sliceEndS >= startS && slice.startS <= endS) {
+ const sliceEndS = slice.start + slice.duration;
+ if (sliceEndS >= start && slice.start <= end) {
break;
}
}
@@ -181,7 +186,7 @@ export abstract class BaseSliceTrack<T extends BaseSliceTrackTypes =
private cache: TrackCache<Array<CastInternal<T['slice']>>> =
new TrackCache(5);
- private readonly tableName: string;
+ protected readonly tableName: string;
private maxDurNs = 0;
private sqlState: 'UNINITIALIZED'|'INITIALIZING'|'QUERY_PENDING'|
'QUERY_DONE' = 'UNINITIALIZED';
@@ -272,13 +277,16 @@ export abstract class BaseSliceTrack<T extends BaseSliceTrackTypes =
renderCanvas(ctx: CanvasRenderingContext2D): void {
// TODO(hjd): fonts and colors should come from the CSS and not hardcoded
// here.
- const timeScale = globals.frontendLocalState.timeScale;
- const vizTime = globals.frontendLocalState.visibleWindowTime;
+ const {
+ visibleTimeScale: timeScale,
+ visibleWindowTime: vizTime,
+ } = globals.frontendLocalState;
{
- const windowSizePx = Math.max(1, timeScale.endPx - timeScale.startPx);
- const rawStartNs = toNs(vizTime.start);
- const rawEndNs = toNs(vizTime.end);
+ const windowSizePx = Math.max(1, timeScale.pxSpan.delta);
+ // TODO(stevegolton): Keep these guys as bigints
+ const rawStartNs = vizTime.start.nanos;
+ const rawEndNs = vizTime.end.nanos;
const rawSlicesKey = CacheKey.create(rawStartNs, rawEndNs, windowSizePx);
// If the visible time range is outside the cached area, requests
@@ -298,7 +306,8 @@ export abstract class BaseSliceTrack<T extends BaseSliceTrackTypes =
// Filter only the visible slices. |this.slices| will have more slices than
// needed because maybeRequestData() over-fetches to handle small pan/zooms.
// We don't want to waste time drawing slices that are off screen.
- const vizSlices = this.getVisibleSlicesInternal(vizTime.start, vizTime.end);
+ const vizSlices = this.getVisibleSlicesInternal(
+ vizTime.start.toTPTime('floor'), vizTime.end.toTPTime('ceil'));
let selection = globals.state.currentSelection;
@@ -321,15 +330,15 @@ export abstract class BaseSliceTrack<T extends BaseSliceTrackTypes =
// pxEnd is the last visible pixel in the visible viewport. Drawing
// anything < 0 or > pxEnd doesn't produce any visible effect as it goes
// beyond the visible portion of the canvas.
- const pxEnd = Math.floor(timeScale.timeToPx(vizTime.end));
+ const pxEnd = Math.floor(timeScale.hpTimeToPx(vizTime.end));
for (const slice of vizSlices) {
// Compute the basic geometry for any visible slice, even if only
// partially visible. This might end up with a negative x if the
// slice starts before the visible time or with a width that overflows
// pxEnd.
- slice.x = timeScale.timeToPx(slice.startS);
- slice.w = timeScale.deltaTimeToPx(slice.durationS);
+ slice.x = timeScale.tpTimeToPx(slice.start);
+ slice.w = timeScale.durationToPx(slice.duration);
if (slice.flags & SLICE_FLAGS_INSTANT) {
// In the case of an instant slice, set the slice geometry on the
// bounding box that will contain the chevron.
@@ -429,10 +438,10 @@ export abstract class BaseSliceTrack<T extends BaseSliceTrackTypes =
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(vizTime.start),
- timeScale.timeToPx(vizTime.end),
- timeScale.timeToPx(fromNs(this.slicesKey.startNs)),
- timeScale.timeToPx(fromNs(this.slicesKey.endNs)));
+ timeScale.hpTimeToPx(vizTime.start),
+ timeScale.hpTimeToPx(vizTime.end),
+ timeScale.secondsToPx(fromNs(this.slicesKey.startNs)),
+ timeScale.secondsToPx(fromNs(this.slicesKey.endNs)));
// TODO(hjd): Remove this.
// The only thing this does is drawing the sched latency arrow. We should
@@ -623,8 +632,8 @@ export abstract class BaseSliceTrack<T extends BaseSliceTrackTypes =
return {
id: row.id,
- startS: fromNs(startNsQ),
- durationS: fromNs(endNsQ - startNsQ),
+ start: tpTimeFromNanos(startNsQ),
+ duration: tpDurationFromNanos(endNsQ - startNsQ),
flags,
depth: row.depth,
title: '',
@@ -701,10 +710,10 @@ export abstract class BaseSliceTrack<T extends BaseSliceTrackTypes =
return true;
}
- private getVisibleSlicesInternal(startS: number, endS: number):
+ private getVisibleSlicesInternal(start: TPTime, end: TPTime):
Array<CastInternal<T['slice']>> {
return filterVisibleSlices<CastInternal<T['slice']>>(
- this.slices, startS, endS);
+ this.slices, start, end);
}
private updateSliceAndTrackHeight() {
diff --git a/ui/src/frontend/base_slice_track_unittest.ts b/ui/src/frontend/base_slice_track_unittest.ts
index 7dd109dee..e9202a2a7 100644
--- a/ui/src/frontend/base_slice_track_unittest.ts
+++ b/ui/src/frontend/base_slice_track_unittest.ts
@@ -19,11 +19,11 @@ import {
} from './base_slice_track';
import {Slice} from './slice';
-function slice(startS: number, durationS: number): Slice {
+function slice(start: number, duration: number): Slice {
return {
id: 42,
- startS,
- durationS,
+ start: BigInt(start),
+ duration: BigInt(duration),
depth: 0,
flags: 0,
title: '',
@@ -36,24 +36,24 @@ function slice(startS: number, durationS: number): Slice {
const s = slice;
test('filterVisibleSlices', () => {
- expect(filterVisibleSlices([], 0, 100)).toEqual([]);
- expect(filterVisibleSlices([s(10, 80)], 0, 100)).toEqual([s(10, 80)]);
- expect(filterVisibleSlices([s(0, 20)], 10, 100)).toEqual([s(0, 20)]);
- expect(filterVisibleSlices([s(0, 10)], 10, 100)).toEqual([s(0, 10)]);
- expect(filterVisibleSlices([s(100, 10)], 10, 100)).toEqual([s(100, 10)]);
- expect(filterVisibleSlices([s(10, 0)], 10, 100)).toEqual([s(10, 0)]);
- expect(filterVisibleSlices([s(100, 0)], 10, 100)).toEqual([s(100, 0)]);
- expect(filterVisibleSlices([s(0, 5)], 10, 90)).toEqual([]);
- expect(filterVisibleSlices([s(95, 5)], 10, 90)).toEqual([]);
- expect(filterVisibleSlices([s(0, 5), s(95, 5)], 10, 90)).toEqual([]);
+ expect(filterVisibleSlices([], 0n, 100n)).toEqual([]);
+ expect(filterVisibleSlices([s(10, 80)], 0n, 100n)).toEqual([s(10, 80)]);
+ expect(filterVisibleSlices([s(0, 20)], 10n, 100n)).toEqual([s(0, 20)]);
+ expect(filterVisibleSlices([s(0, 10)], 10n, 100n)).toEqual([s(0, 10)]);
+ expect(filterVisibleSlices([s(100, 10)], 10n, 100n)).toEqual([s(100, 10)]);
+ expect(filterVisibleSlices([s(10, 0)], 10n, 100n)).toEqual([s(10, 0)]);
+ expect(filterVisibleSlices([s(100, 0)], 10n, 100n)).toEqual([s(100, 0)]);
+ expect(filterVisibleSlices([s(0, 5)], 10n, 90n)).toEqual([]);
+ expect(filterVisibleSlices([s(95, 5)], 10n, 90n)).toEqual([]);
+ expect(filterVisibleSlices([s(0, 5), s(95, 5)], 10n, 90n)).toEqual([]);
expect(filterVisibleSlices(
[
s(0, 5),
s(50, 0),
s(95, 5),
],
- 10,
- 90))
+ 10n,
+ 90n))
.toEqual([
s(50, 0),
]);
@@ -63,8 +63,8 @@ test('filterVisibleSlices', () => {
s(1, 9),
s(6, 3),
],
- 10,
- 90))
+ 10n,
+ 90n))
.toContainEqual(s(1, 9));
expect(filterVisibleSlices(
[
@@ -73,16 +73,16 @@ test('filterVisibleSlices', () => {
s(6, 3),
s(50, 0),
],
- 10,
- 90))
+ 10n,
+ 90n))
.toContainEqual(s(1, 9));
expect(filterVisibleSlices(
[
s(85, 10),
s(100, 10),
],
- 10,
- 90))
+ 10n,
+ 90n))
.toEqual([
s(85, 10),
]);
@@ -91,8 +91,8 @@ test('filterVisibleSlices', () => {
s(0, 100),
],
- 10,
- 90))
+ 10n,
+ 90n))
.toEqual([
s(0, 100),
]);
@@ -109,7 +109,7 @@ test('filterVisibleSlices', () => {
s(8, 1),
s(9, 1),
],
- 10,
- 90))
+ 10n,
+ 90n))
.toContainEqual(s(5, 10));
});
diff --git a/ui/src/frontend/chrome_slice_panel.ts b/ui/src/frontend/chrome_slice_panel.ts
index 6c982cfe9..50e3d1cd2 100644
--- a/ui/src/frontend/chrome_slice_panel.ts
+++ b/ui/src/frontend/chrome_slice_panel.ts
@@ -17,7 +17,9 @@ import m from 'mithril';
import {sqliteString} from '../base/string_utils';
import {Actions} from '../common/actions';
import {Arg, ArgsTree, isArgTreeArray, isArgTreeMap} from '../common/arg_types';
-import {timeToCode} from '../common/time';
+import {EngineProxy} from '../common/engine';
+import {runQuery} from '../common/queries';
+import {timeToCode, tpDurationToSeconds, tpTimeToCode} from '../common/time';
import {FlowPoint, globals, SliceDetails} from './globals';
import {PanelSize} from './panel';
@@ -54,6 +56,29 @@ const ITEMS: ContextMenuItem[] = [
),
},
{
+ name: 'Binder call names',
+ shouldDisplay: () => true,
+ getAction: (slice: SliceDetails) => {
+ const engine = getEngine();
+ if (engine === undefined) return;
+ runQuery(`SELECT IMPORT('android.binder');`, engine)
+ .then(
+ () => runQueryInNewTab(
+ `
+ SELECT s.ts, s.dur, tx.aidl_name AS name, s.id
+ FROM android_sync_binder_metrics_by_txn tx
+ JOIN slice s ON tx.binder_txn_id = s.id
+ JOIN thread_track ON s.track_id = thread_track.id
+ JOIN thread USING (utid)
+ JOIN process USING (upid)
+ WHERE aidl_name IS NOT NULL
+ AND pid = ${slice.pid}
+ AND tid = ${slice.tid}`,
+ `Binder names (${slice.processName}:${slice.tid})`,
+ ));
+ },
+ },
+ {
name: 'Lock graph',
shouldDisplay: (slice: SliceDetails) => slice.id !== undefined,
getAction: (slice: SliceDetails) => runQueryInNewTab(
@@ -110,6 +135,15 @@ function getSliceContextMenuItems(slice: SliceDetails): PopupMenuItem[] {
});
}
+function getEngine(): EngineProxy|undefined {
+ const engineId = globals.getCurrentEngine()?.id;
+ if (engineId === undefined) {
+ return undefined;
+ }
+ const engine = globals.engines.get(engineId)?.getProxy('SlicePanel');
+ return engine;
+}
+
// Table row contents is one of two things:
// 1. Key-value pair
interface TableRow {
@@ -261,7 +295,9 @@ export class ChromeSliceDetailsPanel extends SlicePanel {
!sliceInfo.category || sliceInfo.category === '[NULL]' ?
'N/A' :
sliceInfo.category);
- defaultBuilder.add('Start time', timeToCode(sliceInfo.ts));
+ defaultBuilder.add(
+ 'Start time',
+ tpTimeToCode(sliceInfo.ts - globals.state.traceTime.start));
if (sliceInfo.absTime !== undefined) {
defaultBuilder.add('Absolute Time', sliceInfo.absTime);
}
@@ -271,9 +307,11 @@ export class ChromeSliceDetailsPanel extends SlicePanel {
sliceInfo.threadDur !== undefined) {
// If we have valid thread duration, also display a percentage of
// |threadDur| compared to |dur|.
- const threadDurFractionSuffix = sliceInfo.threadDur === -1 ?
+ const ratio = tpDurationToSeconds(sliceInfo.threadDur) /
+ tpDurationToSeconds(sliceInfo.dur);
+ const threadDurFractionSuffix = sliceInfo.threadDur === -1n ?
'' :
- ` (${(sliceInfo.threadDur / sliceInfo.dur * 100).toFixed(2)}%)`;
+ ` (${(ratio * 100).toFixed(2)}%)`;
defaultBuilder.add(
'Thread duration',
this.computeDuration(sliceInfo.threadTs, sliceInfo.threadDur) +
diff --git a/ui/src/frontend/counter_panel.ts b/ui/src/frontend/counter_panel.ts
index 99d384174..42377735f 100644
--- a/ui/src/frontend/counter_panel.ts
+++ b/ui/src/frontend/counter_panel.ts
@@ -14,8 +14,7 @@
import m from 'mithril';
-import {fromNs, timeToCode} from '../common/time';
-
+import {tpTimeToCode} from '../common/time';
import {globals} from './globals';
import {Panel} from './panel';
@@ -37,7 +36,11 @@ export class CounterDetailsPanel extends Panel<CounterDetailsPanelAttrs> {
m('tr', m('th', `Name`), m('td', `${counterInfo.name}`)),
m('tr',
m('th', `Start time`),
- m('td', `${timeToCode(counterInfo.startTime)}`)),
+ m('td',
+ `${
+ tpTimeToCode(
+ counterInfo.startTime -
+ globals.state.traceTime.start)}`)),
m('tr',
m('th', `Value`),
m('td', `${counterInfo.value.toLocaleString()}`)),
@@ -46,7 +49,7 @@ export class CounterDetailsPanel extends Panel<CounterDetailsPanelAttrs> {
m('td', `${counterInfo.delta.toLocaleString()}`)),
m('tr',
m('th', `Duration`),
- m('td', `${timeToCode(fromNs(counterInfo.duration))}`)),
+ m('td', `${tpTimeToCode(counterInfo.duration)}`)),
])],
));
} else {
diff --git a/ui/src/frontend/debug.ts b/ui/src/frontend/debug.ts
index fae7a832f..7e9c9e523 100644
--- a/ui/src/frontend/debug.ts
+++ b/ui/src/frontend/debug.ts
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {produce} from 'immer';
import m from 'mithril';
import {Actions} from '../common/actions';
@@ -19,12 +20,14 @@ import {getSchema} from '../common/schema';
import {globals} from './globals';
+
declare global {
interface Window {
m: typeof m;
getSchema: typeof getSchema;
globals: typeof globals;
Actions: typeof Actions;
+ produce: typeof produce;
}
}
@@ -33,4 +36,5 @@ export function registerDebugGlobals() {
window.m = m;
window.globals = globals;
window.Actions = Actions;
+ window.produce = produce;
}
diff --git a/ui/src/frontend/details_panel.ts b/ui/src/frontend/details_panel.ts
index 6e5a985f1..e3a75859e 100644
--- a/ui/src/frontend/details_panel.ts
+++ b/ui/src/frontend/details_panel.ts
@@ -17,9 +17,12 @@ import m from 'mithril';
import {Actions} from '../common/actions';
import {isEmptyData} from '../common/aggregation_data';
import {LogExists, LogExistsKey} from '../common/logs';
+import {pluginManager} from '../common/plugins';
import {addSelectionChangeObserver} from '../common/selection_observer';
import {Selection} from '../common/state';
import {DebugSliceDetailsTab} from '../tracks/debug/details_tab';
+import {SCROLL_JANK_PLUGIN_ID} from '../tracks/scroll_jank';
+import {TOP_LEVEL_SCROLL_KIND} from '../tracks/scroll_jank/scroll_track';
import {AggregationPanel} from './aggregation_panel';
import {ChromeSliceDetailsPanel} from './chrome_slice_panel';
@@ -45,6 +48,8 @@ const UP_ICON = 'keyboard_arrow_up';
const DOWN_ICON = 'keyboard_arrow_down';
const DRAG_HANDLE_HEIGHT_PX = 28;
+export const CURRENT_SELECTION_TAG = 'current_selection';
+
function getDetailsHeight() {
// This needs to be a function instead of a const to ensure the CSS constants
// have been initialized by the time we perform this calculation;
@@ -178,7 +183,7 @@ class DragHandle implements m.ClassComponent<DragHandleAttrs> {
}
function handleSelectionChange(newSelection?: Selection, _?: Selection): void {
- const currentSelectionTag = 'current_selection';
+ const currentSelectionTag = CURRENT_SELECTION_TAG;
const bottomTabList = globals.bottomTabList;
if (!bottomTabList) return;
if (newSelection === undefined) {
@@ -225,6 +230,10 @@ function handleSelectionChange(newSelection?: Selection, _?: Selection): void {
},
});
break;
+ case TOP_LEVEL_SCROLL_KIND:
+ pluginManager.onDetailsPanelSelectionChange(
+ SCROLL_JANK_PLUGIN_ID, newSelection);
+ break;
default:
bottomTabList.closeTabByTag(currentSelectionTag);
}
diff --git a/ui/src/frontend/drag/border_drag_strategy.ts b/ui/src/frontend/drag/border_drag_strategy.ts
index df450fc2d..564ffc3fb 100644
--- a/ui/src/frontend/drag/border_drag_strategy.ts
+++ b/ui/src/frontend/drag/border_drag_strategy.ts
@@ -12,28 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {TimeScale} from '../time_scale';
-
import {DragStrategy} from './drag_strategy';
export class BorderDragStrategy extends DragStrategy {
private moveStart = false;
- constructor(timeScale: TimeScale, private pixelBounds: [number, number]) {
- super(timeScale);
+ constructor(map: TimeScale, private pixelBounds: [number, number]) {
+ super(map);
}
onDrag(x: number) {
- let tStart =
- this.timeScale.pxToTime(this.moveStart ? x : this.pixelBounds[0]);
- let tEnd =
- this.timeScale.pxToTime(!this.moveStart ? x : this.pixelBounds[1]);
- if (tStart > tEnd) {
+ let tStart = this.map.pxToHpTime(this.moveStart ? x : this.pixelBounds[0]);
+ let tEnd = this.map.pxToHpTime(!this.moveStart ? x : this.pixelBounds[1]);
+ if (tStart.isGreaterThan(tEnd)) {
this.moveStart = !this.moveStart;
[tEnd, tStart] = [tStart, tEnd];
}
super.updateGlobals(tStart, tEnd);
- this.pixelBounds =
- [this.timeScale.timeToPx(tStart), this.timeScale.timeToPx(tEnd)];
+ this.pixelBounds = [
+ this.map.hpTimeToPx(tStart),
+ this.map.hpTimeToPx(tEnd),
+ ];
}
onDragStart(x: number) {
diff --git a/ui/src/frontend/drag/drag_strategy.ts b/ui/src/frontend/drag/drag_strategy.ts
index 289684987..afb83e138 100644
--- a/ui/src/frontend/drag/drag_strategy.ts
+++ b/ui/src/frontend/drag/drag_strategy.ts
@@ -11,19 +11,22 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-import {TimeSpan} from '../../common/time';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../../common/high_precision_time';
import {globals} from '../globals';
import {TimeScale} from '../time_scale';
export abstract class DragStrategy {
- constructor(protected timeScale: TimeScale) {}
+ constructor(protected map: TimeScale) {}
abstract onDrag(x: number): void;
abstract onDragStart(x: number): void;
- protected updateGlobals(tStart: number, tEnd: number) {
- const vizTime = new TimeSpan(tStart, tEnd);
+ protected updateGlobals(tStart: HighPrecisionTime, tEnd: HighPrecisionTime) {
+ const vizTime = new HighPrecisionTimeSpan(tStart, tEnd);
globals.frontendLocalState.updateVisibleTime(vizTime);
globals.rafScheduler.scheduleRedraw();
}
diff --git a/ui/src/frontend/drag/inner_drag_strategy.ts b/ui/src/frontend/drag/inner_drag_strategy.ts
index 2af1b391f..7be7f7bc0 100644
--- a/ui/src/frontend/drag/inner_drag_strategy.ts
+++ b/ui/src/frontend/drag/inner_drag_strategy.ts
@@ -23,8 +23,8 @@ export class InnerDragStrategy extends DragStrategy {
onDrag(x: number) {
const move = x - this.dragStartPx;
- const tStart = this.timeScale.pxToTime(this.pixelBounds[0] + move);
- const tEnd = this.timeScale.pxToTime(this.pixelBounds[1] + move);
+ const tStart = this.map.pxToHpTime(this.pixelBounds[0] + move);
+ const tEnd = this.map.pxToHpTime(this.pixelBounds[1] + move);
super.updateGlobals(tStart, tEnd);
}
diff --git a/ui/src/frontend/drag/outer_drag_strategy.ts b/ui/src/frontend/drag/outer_drag_strategy.ts
index 648b50d4b..f8269fcf0 100644
--- a/ui/src/frontend/drag/outer_drag_strategy.ts
+++ b/ui/src/frontend/drag/outer_drag_strategy.ts
@@ -11,16 +11,19 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+import {
+ HighPrecisionTime,
+} from '../../common/high_precision_time';
import {DragStrategy} from './drag_strategy';
export class OuterDragStrategy extends DragStrategy {
private dragStartPx = 0;
onDrag(x: number) {
- const dragBeginTime = this.timeScale.pxToTime(this.dragStartPx);
- const dragEndTime = this.timeScale.pxToTime(x);
- const tStart = Math.min(dragBeginTime, dragEndTime);
- const tEnd = Math.max(dragBeginTime, dragEndTime);
+ const dragBeginTime = this.map.pxToHpTime(this.dragStartPx);
+ const dragEndTime = this.map.pxToHpTime(x);
+ const tStart = HighPrecisionTime.min(dragBeginTime, dragEndTime);
+ const tEnd = HighPrecisionTime.max(dragBeginTime, dragEndTime);
super.updateGlobals(tStart, tEnd);
}
diff --git a/ui/src/frontend/drag_gesture_handler.ts b/ui/src/frontend/drag_gesture_handler.ts
index 30c0a3855..4c547aa42 100644
--- a/ui/src/frontend/drag_gesture_handler.ts
+++ b/ui/src/frontend/drag_gesture_handler.ts
@@ -33,8 +33,6 @@ export class DragGestureHandler {
document.body.addEventListener('mousemove', this.boundOnMouseMove);
document.body.addEventListener('mouseup', this.boundOnMouseUp);
this.pendingMouseDownEvent = e;
- // Prevent interactions with other DragGestureHandlers and event listeners
- e.stopPropagation();
}
// We don't start the drag gesture on mouse down, instead we wait until
@@ -60,17 +58,15 @@ export class DragGestureHandler {
this.onDrag(
e.clientX - this.clientRect!.left, e.clientY - this.clientRect!.top);
}
- e.stopPropagation();
}
- private onMouseUp(e: MouseEvent) {
+ private onMouseUp(_e: MouseEvent) {
this._isDragging = false;
document.body.removeEventListener('mousemove', this.boundOnMouseMove);
document.body.removeEventListener('mouseup', this.boundOnMouseUp);
if (!this.pendingMouseDownEvent) {
this.onDragFinished();
}
- e.stopPropagation();
}
get isDragging() {
diff --git a/ui/src/frontend/flamegraph_panel.ts b/ui/src/frontend/flamegraph_panel.ts
index b8246b3c3..0ac5f7930 100644
--- a/ui/src/frontend/flamegraph_panel.ts
+++ b/ui/src/frontend/flamegraph_panel.ts
@@ -28,10 +28,9 @@ import {
FlamegraphStateViewingOption,
ProfileType,
} from '../common/state';
-import {timeToCode} from '../common/time';
+import {tpTimeToCode} from '../common/time';
import {profileType} from '../controller/flamegraph_controller';
-import {PerfettoMouseEvent} from './events';
import {Flamegraph, NodeRendering} from './flamegraph';
import {globals} from './globals';
import {Modal, ModalDefinition} from './modal';
@@ -41,6 +40,7 @@ import {Router} from './router';
import {getCurrentTrace} from './sidebar';
import {convertTraceToPprofAndDownload} from './trace_converter';
import {Button} from './widgets/button';
+import {findRef} from './widgets/utils';
interface FlamegraphDetailsPanelAttrs {}
@@ -64,23 +64,24 @@ const RENDER_OBJ_COUNT: NodeRendering = {
export class FlamegraphDetailsPanel extends Panel<FlamegraphDetailsPanelAttrs> {
private profileType?: ProfileType = undefined;
- private ts = 0;
+ private ts = 0n;
private pids: number[] = [];
private flamegraph: Flamegraph = new Flamegraph([]);
private focusRegex = '';
private updateFocusRegexDebounced = debounce(() => {
this.updateFocusRegex();
}, 20);
+ private canvas?: HTMLCanvasElement;
view() {
const flamegraphDetails = globals.flamegraphDetails;
if (flamegraphDetails && flamegraphDetails.type !== undefined &&
- flamegraphDetails.startNs !== undefined &&
- flamegraphDetails.durNs !== undefined &&
+ flamegraphDetails.start !== undefined &&
+ flamegraphDetails.dur !== undefined &&
flamegraphDetails.pids !== undefined &&
flamegraphDetails.upids !== undefined) {
this.profileType = profileType(flamegraphDetails.type);
- this.ts = flamegraphDetails.startNs + flamegraphDetails.durNs;
+ this.ts = flamegraphDetails.start + flamegraphDetails.dur;
this.pids = flamegraphDetails.pids;
if (flamegraphDetails.flamegraph) {
this.flamegraph.updateDataIfChanged(
@@ -91,25 +92,6 @@ export class FlamegraphDetailsPanel extends Panel<FlamegraphDetailsPanelAttrs> {
0;
return m(
'.details-panel',
- {
- onclick: (e: PerfettoMouseEvent) => {
- if (this.flamegraph !== undefined) {
- this.onMouseClick({y: e.layerY, x: e.layerX});
- }
- return false;
- },
- onmousemove: (e: PerfettoMouseEvent) => {
- if (this.flamegraph !== undefined) {
- this.onMouseMove({y: e.layerY, x: e.layerX});
- globals.rafScheduler.scheduleRedraw();
- }
- },
- onmouseout: () => {
- if (this.flamegraph !== undefined) {
- this.onMouseOut();
- }
- },
- },
this.maybeShowModal(flamegraphDetails.graphIncomplete),
m('.details-panel-heading.flamegraph-profile',
{onclick: (e: MouseEvent) => e.stopPropagation()},
@@ -126,7 +108,7 @@ export class FlamegraphDetailsPanel extends Panel<FlamegraphDetailsPanelAttrs> {
toSelectedCallsite(
flamegraphDetails.expandedCallsite)}`),
m('div.time',
- `Snapshot time: ${timeToCode(flamegraphDetails.durNs)}`),
+ `Snapshot time: ${tpTimeToCode(flamegraphDetails.dur)}`),
m('input[type=text][placeholder=Focus]', {
oninput: (e: Event) => {
const target = (e.target as HTMLInputElement);
@@ -146,7 +128,20 @@ export class FlamegraphDetailsPanel extends Panel<FlamegraphDetailsPanelAttrs> {
}),
]),
]),
- m(`div[style=height:${height}px]`),
+ m(`canvas[ref=canvas]`, {
+ style: `height:${height}px; width:100%`,
+ onmousemove: (e: MouseEvent) => {
+ const {offsetX, offsetY} = e;
+ this.onMouseMove({x: offsetX, y: offsetY});
+ },
+ onmouseout: () => {
+ this.onMouseOut();
+ },
+ onclick: (e: MouseEvent) => {
+ const {offsetX, offsetY} = e;
+ this.onMouseClick({x: offsetX, y: offsetY});
+ },
+ }),
);
} else {
return m(
@@ -256,7 +251,53 @@ export class FlamegraphDetailsPanel extends Panel<FlamegraphDetailsPanelAttrs> {
this.nodeRendering(), flamegraphData, data.expandedCallsite);
}
- renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
+ oncreate({dom}: m.CVnodeDOM<FlamegraphDetailsPanelAttrs>) {
+ this.canvas = FlamegraphDetailsPanel.findCanvasElement(dom);
+ // TODO(stevegolton): If we truely want to be standalone, then we shouldn't
+ // rely on someone else calling the rafScheduler when the window is resized,
+ // but it's good enough for now as we know the ViewerPage will do it.
+ globals.rafScheduler.addRedrawCallback(this.rafRedrawCallback);
+ }
+
+ onupdate({dom}: m.CVnodeDOM<FlamegraphDetailsPanelAttrs>) {
+ this.canvas = FlamegraphDetailsPanel.findCanvasElement(dom);
+ }
+
+ onremove(_vnode: m.CVnodeDOM<FlamegraphDetailsPanelAttrs>) {
+ globals.rafScheduler.removeRedrawCallback(this.rafRedrawCallback);
+ }
+
+ private static findCanvasElement(dom: Element): HTMLCanvasElement|undefined {
+ const canvas = findRef(dom, 'canvas');
+ if (canvas && canvas instanceof HTMLCanvasElement) {
+ return canvas;
+ } else {
+ return undefined;
+ }
+ }
+
+ private rafRedrawCallback = () => {
+ if (this.canvas) {
+ const canvas = this.canvas;
+ canvas.width = canvas.offsetWidth * devicePixelRatio;
+ canvas.height = canvas.offsetHeight * devicePixelRatio;
+ const ctx = canvas.getContext('2d');
+ if (ctx) {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.save();
+ ctx.scale(devicePixelRatio, devicePixelRatio);
+ const {offsetWidth: width, offsetHeight: height} = canvas;
+ this.renderLocalCanvas(ctx, {width, height});
+ ctx.restore();
+ }
+ }
+ };
+
+ renderCanvas() {
+ // No-op
+ }
+
+ private renderLocalCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
this.changeFlamegraphData();
const current = globals.state.currentFlamegraphState;
if (current === null) return;
@@ -265,22 +306,24 @@ export class FlamegraphDetailsPanel extends Panel<FlamegraphDetailsPanelAttrs> {
current.viewingOption === ALLOC_SPACE_MEMORY_ALLOCATED_KEY ?
'B' :
'';
- this.flamegraph.draw(ctx, size.width, size.height, 0, HEADER_HEIGHT, unit);
+ this.flamegraph.draw(ctx, size.width, size.height, 0, 0, unit);
}
- onMouseClick({x, y}: {x: number, y: number}): boolean {
+ private onMouseClick({x, y}: {x: number, y: number}): boolean {
const expandedCallsite = this.flamegraph.onMouseClick({x, y});
globals.dispatch(Actions.expandFlamegraphState({expandedCallsite}));
return true;
}
- onMouseMove({x, y}: {x: number, y: number}): boolean {
+ private onMouseMove({x, y}: {x: number, y: number}): boolean {
this.flamegraph.onMouseMove({x, y});
+ globals.rafScheduler.scheduleFullRedraw();
return true;
}
- onMouseOut() {
+ private onMouseOut() {
this.flamegraph.onMouseOut();
+ globals.rafScheduler.scheduleFullRedraw();
}
private static selectViewingOptions(profileType: ProfileType) {
diff --git a/ui/src/frontend/flow_events_renderer.ts b/ui/src/frontend/flow_events_renderer.ts
index 909dcb7f3..fdb91e0e1 100644
--- a/ui/src/frontend/flow_events_renderer.ts
+++ b/ui/src/frontend/flow_events_renderer.ts
@@ -140,7 +140,7 @@ export class FlowEventsRenderer {
}
private getXCoordinate(ts: number): number {
- return globals.frontendLocalState.timeScale.timeToPx(ts);
+ return globals.frontendLocalState.visibleTimeScale.secondsToPx(ts);
}
private getSliceRect(args: FlowEventsRendererArgs, point: FlowPoint):
diff --git a/ui/src/frontend/frontend_local_state.ts b/ui/src/frontend/frontend_local_state.ts
index b24f69a33..f4d95ca42 100644
--- a/ui/src/frontend/frontend_local_state.ts
+++ b/ui/src/frontend/frontend_local_state.ts
@@ -14,6 +14,10 @@
import {assertTrue} from '../base/logging';
import {Actions} from '../common/actions';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../common/high_precision_time';
import {HttpRpcState} from '../common/http_rpc_engine';
import {
Area,
@@ -21,11 +25,15 @@ import {
Timestamped,
VisibleState,
} from '../common/state';
-import {TimeSpan} from '../common/time';
+import {Span} from '../common/time';
+import {
+ TPTime,
+ TPTimeSpan,
+} from '../common/time';
import {globals} from './globals';
import {ratelimit} from './rate_limiters';
-import {TimeScale} from './time_scale';
+import {PxSpan, TimeScale} from './time_scale';
interface Range {
start?: number;
@@ -42,10 +50,6 @@ function chooseLatest<T extends Timestamped>(current: T, next: T): T {
return current;
}
-function capBetween(t: number, start: number, end: number) {
- return Math.min(Math.max(t, start), end);
-}
-
// Calculate the space a scrollbar takes up so that we can subtract it from
// the canvas width.
function calculateScrollbarWidth() {
@@ -60,13 +64,99 @@ function calculateScrollbarWidth() {
return width;
}
+export class TimeWindow {
+ private readonly MIN_DURATION_NS = 10;
+ private _start: HighPrecisionTime = new HighPrecisionTime();
+ private _durationNanos: number = 10e9;
+
+ private get _end(): HighPrecisionTime {
+ return this._start.addNanos(this._durationNanos);
+ }
+
+ update(span: Span<HighPrecisionTime>) {
+ this._start = span.start;
+ this._durationNanos = Math.max(this.MIN_DURATION_NS, span.duration.nanos);
+ this.preventClip();
+ }
+
+ // Pan the window by certain number of seconds
+ pan(offset: HighPrecisionTime) {
+ this._start = this._start.add(offset);
+ this.preventClip();
+ }
+
+ // Zoom in or out a bit centered on a specific offset from the root
+ // Offset represents the center of the zoom as a normalized value between 0
+ // and 1 where 0 is the start of the time window and 1 is the end
+ zoom(ratio: number, offset: number) {
+ // TODO(stevegolton): Handle case where trace time < MIN_DURATION_NS
+
+ const traceDuration = globals.stateTraceTime().duration;
+ const minDuration = Math.min(this.MIN_DURATION_NS, traceDuration.nanos);
+ const newDurationNanos = Math.max(this._durationNanos * ratio, minDuration);
+ // Delta between new and old duration
+ // +ve if new duration is shorter than old duration
+ const durationDeltaNanos = this._durationNanos - newDurationNanos;
+ // If offset is 0, don't move the start at all
+ // If offset if 1, move the start by the amount the duration has changed
+ // If new duration is shorter - move start to right
+ // If new duration is longer - move start to left
+ this._start = this._start.addNanos(durationDeltaNanos * offset);
+ this._durationNanos = newDurationNanos;
+ this.preventClip();
+ }
+
+ createTimeScale(startPx: number, endPx: number): TimeScale {
+ return new TimeScale(
+ this._start, this._durationNanos, new PxSpan(startPx, endPx));
+ }
+
+ // Get timespan covering entire range of the window
+ get timeSpan(): HighPrecisionTimeSpan {
+ return new HighPrecisionTimeSpan(this._start, this._end);
+ }
+
+ get timestampSpan(): Span<TPTime> {
+ return new TPTimeSpan(this.earliest, this.latest);
+ }
+
+ get earliest(): TPTime {
+ return this._start.toTPTime('floor');
+ }
+
+ get latest(): TPTime {
+ return this._start.addNanos(this._durationNanos).toTPTime('ceil');
+ }
+
+ // Limit the zoom and pan
+ private preventClip() {
+ const traceTimeSpan = globals.stateTraceTime();
+ const traceDurationNanos = traceTimeSpan.duration.nanos;
+
+ if (this._durationNanos > traceDurationNanos) {
+ this._start = traceTimeSpan.start;
+ this._durationNanos = traceDurationNanos;
+ }
+
+ if (this._start.isLessThan(traceTimeSpan.start)) {
+ this._start = traceTimeSpan.start;
+ }
+
+ const end = this._start.addNanos(this._durationNanos);
+ if (end.isGreaterThan(traceTimeSpan.end)) {
+ this._start = traceTimeSpan.end.subtractNanos(this._durationNanos);
+ }
+ }
+}
+
/**
* State that is shared between several frontend components, but not the
* controller. This state is updated at 60fps.
*/
export class FrontendLocalState {
- visibleWindowTime = new TimeSpan(0, 10);
- timeScale = new TimeScale(this.visibleWindowTime, [0, 0]);
+ visibleWindow = new TimeWindow();
+ startPx: number = 0;
+ endPx: number = 0;
showPanningHint = false;
showCookieConsent = false;
visibleTracks = new Set<string>();
@@ -82,9 +172,9 @@ export class FrontendLocalState {
private _visibleState: VisibleState = {
lastUpdate: 0,
- startSec: 0,
- endSec: 10,
- resolution: 1,
+ start: 0n,
+ end: BigInt(10e9),
+ resolution: 1n,
};
private _selectedArea?: Area;
@@ -125,6 +215,16 @@ export class FrontendLocalState {
}
}
+ zoomVisibleWindow(ratio: number, centerPoint: number) {
+ this.visibleWindow.zoom(ratio, centerPoint);
+ this.kickUpdateLocalState();
+ }
+
+ panVisibleWindow(delta: HighPrecisionTime) {
+ this.visibleWindow.pan(delta);
+ this.kickUpdateLocalState();
+ }
+
mergeState(state: FrontendState): void {
// This is unfortunately subtle. This class mutates this._visibleState.
// Since we may not mutate |state| (in order to make immer's immutable
@@ -137,17 +237,22 @@ export class FrontendLocalState {
this._visibleState = chooseLatest(this._visibleState, state.visibleState);
const visibleStateWasUpdated = previousVisibleState !== this._visibleState;
if (visibleStateWasUpdated) {
- this.updateLocalTime(
- new TimeSpan(this._visibleState.startSec, this._visibleState.endSec));
+ this.updateLocalTime(new HighPrecisionTimeSpan(
+ HighPrecisionTime.fromTPTime(this._visibleState.start),
+ HighPrecisionTime.fromTPTime(this._visibleState.end),
+ ));
}
}
+ // Set the highlight box to draw
selectArea(
- startSec: number, endSec: number,
+ start: TPTime, end: TPTime,
tracks = this._selectedArea ? this._selectedArea.tracks : []) {
- assertTrue(endSec >= startSec);
+ assertTrue(
+ end >= start,
+ `Impossible select area: start [${start}] >= end [${end}]`);
this.showPanningHint = true;
- this._selectedArea = {startSec, endSec, tracks},
+ this._selectedArea = {start, end, tracks},
globals.rafScheduler.scheduleFullRedraw();
}
@@ -164,12 +269,11 @@ export class FrontendLocalState {
globals.dispatch(Actions.setVisibleTraceTime(this._visibleState));
}, 50);
- private updateLocalTime(ts: TimeSpan) {
- const traceTime = globals.state.traceTime;
- const startSec = capBetween(ts.start, traceTime.startSec, traceTime.endSec);
- const endSec = capBetween(ts.end, traceTime.startSec, traceTime.endSec);
- this.visibleWindowTime = new TimeSpan(startSec, endSec);
- this.timeScale.setTimeBounds(this.visibleWindowTime);
+ private updateLocalTime(ts: Span<HighPrecisionTime>) {
+ const traceBounds = globals.stateTraceTime();
+ const start = ts.start.clamp(traceBounds.start, traceBounds.end);
+ const end = ts.end.clamp(traceBounds.start, traceBounds.end);
+ this.visibleWindow.update(new HighPrecisionTimeSpan(start, end));
this.updateResolution();
}
@@ -179,17 +283,17 @@ export class FrontendLocalState {
this.ratelimitedUpdateVisible();
}
- updateVisibleTime(ts: TimeSpan) {
- this.updateLocalTime(ts);
+ private kickUpdateLocalState() {
this._visibleState.lastUpdate = Date.now() / 1000;
- this._visibleState.startSec = this.visibleWindowTime.start;
- this._visibleState.endSec = this.visibleWindowTime.end;
+ this._visibleState.start = this.visibleWindowTime.start.toTPTime();
+ this._visibleState.end = this.visibleWindowTime.end.toTPTime();
this._visibleState.resolution = globals.getCurResolution();
this.ratelimitedUpdateVisible();
}
- getVisibleStateBounds(): [number, number] {
- return [this.visibleWindowTime.start, this.visibleWindowTime.end];
+ updateVisibleTime(ts: Span<HighPrecisionTime>) {
+ this.updateLocalTime(ts);
+ this.kickUpdateLocalState();
}
// Whenever start/end px of the timeScale is changed, update
@@ -200,7 +304,28 @@ export class FrontendLocalState {
pxStart = Math.max(0, pxStart);
pxEnd = Math.max(0, pxEnd);
if (pxStart === pxEnd) pxEnd = pxStart + 1;
- this.timeScale.setLimitsPx(pxStart, pxEnd);
+ this.startPx = pxStart;
+ this.endPx = pxEnd;
this.updateResolution();
}
+
+ // Get the time scale for the visible window
+ get visibleTimeScale(): TimeScale {
+ return this.visibleWindow.createTimeScale(this.startPx, this.endPx);
+ }
+
+ // Produces a TimeScale object for this time window provided start and end px
+ getTimeScale(startPx: number, endPx: number): TimeScale {
+ return this.visibleWindow.createTimeScale(startPx, endPx);
+ }
+
+ // Get the bounds of the window in pixels
+ get windowSpan(): PxSpan {
+ return new PxSpan(this.startPx, this.endPx);
+ }
+
+ // Get the bounds of the visible time window as a time span
+ get visibleWindowTime(): Span<HighPrecisionTime> {
+ return this.visibleWindow.timeSpan;
+ }
}
diff --git a/ui/src/frontend/ftrace_panel.ts b/ui/src/frontend/ftrace_panel.ts
index 29d020764..e45b5fe7e 100644
--- a/ui/src/frontend/ftrace_panel.ts
+++ b/ui/src/frontend/ftrace_panel.ts
@@ -18,7 +18,7 @@ import {StringListPatch} from 'src/common/state';
import {assertExists} from '../base/logging';
import {Actions} from '../common/actions';
import {colorForString} from '../common/colorizer';
-import {formatTimestamp} from '../common/time';
+import {formatTPTime, TPTime} from '../common/time';
import {globals} from './globals';
import {Panel} from './panel';
@@ -105,6 +105,11 @@ export class FtracePanel extends Panel<{}> {
onremove({dom}: m.CVnodeDOM) {
const sc = this.scrollContainer(dom);
sc.removeEventListener('scroll', this.onScroll);
+
+ globals.dispatch(Actions.updateFtracePagination({
+ offset: 0,
+ count: 0,
+ }));
}
onScroll = (e: Event) => {
@@ -112,12 +117,12 @@ export class FtracePanel extends Panel<{}> {
this.recomputeVisibleRowsAndUpdate(scrollContainer);
};
- onRowOver(ts: number) {
+ onRowOver(ts: TPTime) {
globals.dispatch(Actions.setHoverCursorTimestamp({ts}));
}
onRowOut() {
- globals.dispatch(Actions.setHoverCursorTimestamp({ts: -1}));
+ globals.dispatch(Actions.setHoverCursorTimestamp({ts: -1n}));
}
private renderRowsLabel() {
@@ -183,8 +188,7 @@ export class FtracePanel extends Panel<{}> {
for (let i = 0; i < events.length; i++) {
const {ts, name, cpu, process, args} = events[i];
- const timestamp =
- formatTimestamp(ts / 1e9 - globals.state.traceTime.startSec);
+ const timestamp = formatTPTime(ts - globals.state.traceTime.start);
const rank = i + offset;
@@ -199,7 +203,7 @@ export class FtracePanel extends Panel<{}> {
`.row`,
{
style: {top: `${(rank + 1.0) * ROW_H}px`},
- onmouseover: this.onRowOver.bind(this, ts / 1e9),
+ onmouseover: this.onRowOver.bind(this, ts),
onmouseout: this.onRowOut.bind(this),
},
m('.cell', timestamp),
diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts
index 0ca10a077..79ca58a96 100644
--- a/ui/src/frontend/globals.ts
+++ b/ui/src/frontend/globals.ts
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../base/bigint_math';
import {assertExists} from '../base/logging';
import {Actions, DeferredAction} from '../common/actions';
import {AggregateData} from '../common/aggregation_data';
@@ -22,10 +23,19 @@ import {
} from '../common/conversion_jobs';
import {createEmptyState} from '../common/empty_state';
import {Engine} from '../common/engine';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../common/high_precision_time';
import {MetricResult} from '../common/metric_data';
import {CurrentSearchResults, SearchSummary} from '../common/search_data';
import {CallsiteInfo, EngineConfig, ProfileType, State} from '../common/state';
-import {fromNs, toNs} from '../common/time';
+import {Span, tpTimeFromSeconds} from '../common/time';
+import {
+ TPDuration,
+ TPTime,
+ TPTimeSpan,
+} from '../common/time';
import {Analytics, initAnalytics} from './analytics';
import {BottomTabList} from './bottom_tab';
@@ -33,6 +43,7 @@ import {FrontendLocalState} from './frontend_local_state';
import {RafScheduler} from './raf_scheduler';
import {Router} from './router';
import {ServiceWorkerController} from './service_worker_controller';
+import {PxSpan, TimeScale} from './time_scale';
type Dispatch = (action: DeferredAction) => void;
type TrackDataStore = Map<string, {}>;
@@ -41,18 +52,18 @@ type AggregateDataStore = Map<string, AggregateData>;
type Description = Map<string, string>;
export interface SliceDetails {
- ts?: number;
+ ts?: TPTime;
absTime?: string;
- dur?: number;
- threadTs?: number;
- threadDur?: number;
+ dur?: TPDuration;
+ threadTs?: TPTime;
+ threadDur?: TPDuration;
priority?: number;
endState?: string|null;
cpu?: number;
id?: number;
threadStateId?: number;
utid?: number;
- wakeupTs?: number;
+ wakeupTs?: TPTime;
wakerUtid?: number;
wakerCpu?: number;
category?: string;
@@ -104,23 +115,23 @@ export interface Flow {
}
export interface CounterDetails {
- startTime?: number;
+ startTime?: TPTime;
value?: number;
delta?: number;
- duration?: number;
+ duration?: TPDuration;
name?: string;
}
export interface ThreadStateDetails {
- ts?: number;
- dur?: number;
+ ts?: TPTime;
+ dur?: TPDuration;
}
export interface FlamegraphDetails {
type?: ProfileType;
id?: number;
- startNs?: number;
- durNs?: number;
+ start?: TPTime;
+ dur?: TPDuration;
pids?: number[];
upids?: number[];
flamegraph?: CallsiteInfo[];
@@ -143,8 +154,8 @@ export interface CpuProfileDetails {
}
export interface QuantizedLoad {
- startSec: number;
- endSec: number;
+ start: TPTime;
+ end: TPTime;
load: number;
}
type OverviewStore = Map<string, QuantizedLoad[]>;
@@ -161,7 +172,7 @@ type ThreadMap = Map<number, ThreadDesc>;
export interface FtraceEvent {
id: number;
- ts: number;
+ ts: TPTime;
name: string;
cpu: number;
thread: string|null;
@@ -530,7 +541,7 @@ class Globals {
this.aggregateDataStore.set(kind, data);
}
- getCurResolution() {
+ getCurResolution(): TPDuration {
// Truncate the resolution to the closest power of 2 (in nanosecond space).
// We choose to work in ns space because resolution is consumed be track
// controllers for quantization and they rely on resolution to be a power
@@ -541,24 +552,18 @@ class Globals {
// levels. Logic: each zoom level represents a delta of 0.1 * (visible
// window span). Therefore, zooming out by six levels is 1.1^6 ~= 2.
// Similarily, zooming in six levels is 0.9^6 ~= 0.5.
- const pxToSec = this.frontendLocalState.timeScale.deltaPxToDuration(1);
+ const timeScale = this.frontendLocalState.visibleTimeScale;
// TODO(b/186265930): Remove once fixed:
- if (!isFinite(pxToSec)) {
- // Resolution is in pixels per second so 1000 means 1px = 1ms.
- console.error(`b/186265930: Bad pxToSec suppressed ${pxToSec}`);
- return fromNs(Math.pow(2, Math.floor(Math.log2(toNs(1000)))));
+ if (timeScale.pxSpan.delta === 0) {
+ console.error(`b/186265930: Bad pxToSec suppressed`);
+ return BigintMath.bitFloor(tpTimeFromSeconds(1000));
}
- const pxToNs = Math.max(toNs(pxToSec), 1);
- const resolution = fromNs(Math.pow(2, Math.floor(Math.log2(pxToNs))));
- const log2 = Math.log2(toNs(resolution));
- if (log2 % 1 !== 0) {
- throw new Error(`Resolution should be a power of two.
- pxToSec: ${pxToSec},
- pxToNs: ${pxToNs},
- resolution: ${resolution},
- log2: ${Math.log2(toNs(resolution))}`);
- }
- return resolution;
+
+ const timePerPx = HighPrecisionTime.max(
+ timeScale.pxDeltaToDuration(1), new HighPrecisionTime(1n));
+
+ const resolutionBig = BigintMath.bitFloor(timePerPx.toTPTime());
+ return resolutionBig;
}
getCurrentEngine(): EngineConfig|undefined {
@@ -637,6 +642,30 @@ class Globals {
shutdown() {
this._rafScheduler!.shutdown();
}
+
+ // Get a timescale that covers the entire trace
+ getTraceTimeScale(pxSpan: PxSpan): TimeScale {
+ const {start, end} = this.state.traceTime;
+ const traceTime = HighPrecisionTimeSpan.fromTpTime(start, end);
+ return new TimeScale(traceTime.start, traceTime.duration.nanos, pxSpan);
+ }
+
+ // Get the trace time bounds
+ stateTraceTime(): Span<HighPrecisionTime> {
+ const {start, end} = this.state.traceTime;
+ return HighPrecisionTimeSpan.fromTpTime(start, end);
+ }
+
+ stateTraceTimeTP(): Span<TPTime> {
+ const {start, end} = this.state.traceTime;
+ return new TPTimeSpan(start, end);
+ }
+
+ // Get the state version of the visible time bounds
+ stateVisibleTime(): Span<TPTime> {
+ const {start, end} = this.state.frontendLocalState.visibleState;
+ return new TPTimeSpan(start, end);
+ }
}
export const globals = new Globals();
diff --git a/ui/src/frontend/gridline_helper.ts b/ui/src/frontend/gridline_helper.ts
index 1c9dbfec8..6581c8121 100644
--- a/ui/src/frontend/gridline_helper.ts
+++ b/ui/src/frontend/gridline_helper.ts
@@ -13,49 +13,91 @@
// limitations under the License.
import {assertTrue} from '../base/logging';
-import {roundDownNearest} from '../base/math_utils';
+import {Span, tpDurationToSeconds} from '../common/time';
+import {TPDuration, TPTime, TPTimeSpan} from '../common/time';
+
import {TRACK_BORDER_COLOR, TRACK_SHELL_WIDTH} from './css_constants';
import {globals} from './globals';
import {TimeScale} from './time_scale';
-// Returns the optimal step size (in seconds) and tick pattern of ticks within
-// the step. The returned step size has two properties: (1) It is 1, 2, or 5,
-// multiplied by some integer power of 10. (2) It is maximised given the
-// constraint: |range| / stepSize <= |maxNumberOfSteps|.
-export function getStepSize(
- range: number, maxNumberOfSteps: number): [number, string] {
- // First, get the largest possible power of 10 that is smaller than the
- // desired step size, and use it as our initial step size.
- // For example, if the range is 2345ms and the desired steps is 10, then the
- // minimum step size is 234.5ms so the step size will initialise to 100.
- const minStepSize = range / maxNumberOfSteps;
- const zeros = Math.floor(Math.log10(minStepSize));
- const initialStepSize = Math.pow(10, zeros);
-
- // We know that |initialStepSize| is a power of 10, and
- // initialStepSize <= desiredStepSize <= 10 * initialStepSize. There are four
- // possible candidates for final step size: 1, 2, 5 or 10 * initialStepSize.
- // For our example above, this would result in a step size of 500ms, as both
- // 100ms and 200ms are smaller than the minimum step size of 234.5ms.
- // We pick the candidate that minimizes the step size without letting the
- // number of steps exceed |maxNumberOfSteps|. The factor we pick to also
- // determines the pattern of ticks. This pattern is represented using a string
- // where:
- // | = Major tick
- // : = Medium tick
- // . = Minor tick
- const stepSizeMultipliers: [number, string][] =
- [[1, '|....:....'], [2, '|.:.'], [5, '|....'], [10, '|....:....']];
-
- for (const [multiplier, pattern] of stepSizeMultipliers) {
- const newStepSize = multiplier * initialStepSize;
- const numberOfNewSteps = range / newStepSize;
- if (numberOfNewSteps <= maxNumberOfSteps) {
- return [newStepSize, pattern];
+const micros = 1000n;
+const millis = 1000n * micros;
+const seconds = 1000n * millis;
+const minutes = 60n * seconds;
+const hours = 60n * minutes;
+const days = 24n * hours;
+
+// These patterns cover the entire range of 0 - 2^63-1 nanoseconds
+const patterns: [bigint, string][] = [
+ [1n, '|'],
+ [2n, '|:'],
+ [5n, '|....'],
+ [10n, '|....:....'],
+ [20n, '|.:.'],
+ [50n, '|....'],
+ [100n, '|....:....'],
+ [200n, '|.:.'],
+ [500n, '|....'],
+ [1n * micros, '|....:....'],
+ [2n * micros, '|.:.'],
+ [5n * micros, '|....'],
+ [10n * micros, '|....:....'],
+ [20n * micros, '|.:.'],
+ [50n * micros, '|....'],
+ [100n * micros, '|....:....'],
+ [200n * micros, '|.:.'],
+ [500n * micros, '|....'],
+ [1n * millis, '|....:....'],
+ [2n * millis, '|.:.'],
+ [5n * millis, '|....'],
+ [10n * millis, '|....:....'],
+ [20n * millis, '|.:.'],
+ [50n * millis, '|....'],
+ [100n * millis, '|....:....'],
+ [200n * millis, '|.:.'],
+ [500n * millis, '|....'],
+ [1n * seconds, '|....:....'],
+ [2n * seconds, '|.:.'],
+ [5n * seconds, '|....'],
+ [10n * seconds, '|....:....'],
+ [30n * seconds, '|.:.:.'],
+ [1n * minutes, '|.....'],
+ [2n * minutes, '|.:.'],
+ [5n * minutes, '|.....'],
+ [10n * minutes, '|....:....'],
+ [30n * minutes, '|.:.:.'],
+ [1n * hours, '|.....'],
+ [2n * hours, '|.:.'],
+ [6n * hours, '|.....'],
+ [12n * hours, '|.....:.....'],
+ [1n * days, '|.:.'],
+ [2n * days, '|.:.'],
+ [5n * days, '|....'],
+ [10n * days, '|....:....'],
+ [20n * days, '|.:.'],
+ [50n * days, '|....'],
+ [100n * days, '|....:....'],
+ [200n * days, '|.:.'],
+ [500n * days, '|....'],
+ [1000n * days, '|....:....'],
+ [2000n * days, '|.:.'],
+ [5000n * days, '|....'],
+ [10000n * days, '|....:....'],
+ [20000n * days, '|.:.'],
+ [50000n * days, '|....'],
+ [100000n * days, '|....:....'],
+ [200000n * days, '|.:.'],
+];
+
+// Returns the optimal step size and pattern of ticks within the step.
+export function getPattern(minPatternSize: bigint): [TPDuration, string] {
+ for (const [size, pattern] of patterns) {
+ if (size >= minPatternSize) {
+ return [size, pattern];
}
}
- throw new Error('Something has gone horribly wrong with maths');
+ throw new Error('Pattern not defined for this minsize');
}
function tickPatternToArray(pattern: string): TickType[] {
@@ -75,21 +117,23 @@ function tickPatternToArray(pattern: string): TickType[] {
});
}
-// Assuming a number only has one non-zero decimal digit, find the number of
-// decimal places required to accurately print that number. I.e. the parameter
-// we should pass to number.toFixed(x). To account for floating point
-// innaccuracies when representing numbers in base-10, we only take the first
-// nonzero fractional digit into account. E.g.
+// Get the number of decimal places we would have to print a time to for a given
+// min step size. For example, if we know the min step size is 0.1 and all
+// values are going to be aligned to integral multiples of 0.1, there's no
+// point printing these values with more than 1 decimal place.
+// Note: It's assumed that stepSize only has one significant figure.
+// E.g. 0.3 and 0.00002 are fine, but 0.123 will be treated as if it were 0.1.
+// Some examples: (seconds -> decimal places)
// 1.0 -> 0
// 0.5 -> 1
// 0.009 -> 3
// 0.00007 -> 5
// 30000 -> 0
// 0.30000000000000004 -> 1
-export function guessDecimalPlaces(val: number): number {
- const neglog10 = -Math.floor(Math.log10(val));
- const clamped = Math.max(0, neglog10);
- return clamped;
+export function guessDecimalPlaces(stepSize: TPDuration): number {
+ const stepSizeSeconds = tpDurationToSeconds(stepSize);
+ const decimalPlaces = -Math.floor(Math.log10(stepSizeSeconds));
+ return Math.max(0, decimalPlaces);
}
export enum TickType {
@@ -100,55 +144,58 @@ export enum TickType {
export interface Tick {
type: TickType;
- time: number;
- position: number;
+ time: TPTime;
}
const MIN_PX_PER_STEP = 80;
+export function getMaxMajorTicks(width: number) {
+ return Math.max(1, Math.floor(width / MIN_PX_PER_STEP));
+}
+
+function roundDownNearest(time: TPTime, stepSize: TPDuration): TPTime {
+ return stepSize * (time / stepSize);
+}
// An iterable which generates a series of ticks for a given timescale.
export class TickGenerator implements Iterable<Tick> {
private _tickPattern: TickType[];
- private _patternSize: number;
-
- constructor(private scale: TimeScale, {minLabelPx = MIN_PX_PER_STEP} = {}) {
- assertTrue(minLabelPx > 0, 'minLabelPx cannot be lte 0');
- assertTrue(scale.widthPx > 0, 'widthPx cannot be lte 0');
- assertTrue(
- scale.timeSpan.duration > 0, 'timeSpan.duration cannot be lte 0');
-
- const desiredSteps = scale.widthPx / minLabelPx;
- const [size, pattern] = getStepSize(scale.timeSpan.duration, desiredSteps);
+ private _patternSize: TPDuration;
+ private _timeSpan: Span<TPTime>;
+ private _offset: TPTime;
+
+ constructor(
+ timeSpan: Span<TPTime>, maxMajorTicks: number, offset: TPTime = 0n) {
+ assertTrue(timeSpan.duration > 0n, 'timeSpan.duration cannot be lte 0');
+ assertTrue(maxMajorTicks > 0, 'maxMajorTicks cannot be lte 0');
+
+ this._timeSpan = timeSpan.add(-offset);
+ this._offset = offset;
+ const minStepSize =
+ BigInt(Math.floor(Number(timeSpan.duration) / maxMajorTicks));
+ const [size, pattern] = getPattern(minStepSize);
this._patternSize = size;
this._tickPattern = tickPatternToArray(pattern);
}
// Returns an iterable, so this object can be iterated over directly using the
// `for x of y` notation. The use of a generator here is just to make things
- // more elegant than creating an array of ticks and building an iterator for
- // it.
+ // more elegant compared to creating an array of ticks and building an
+ // iterator for it.
* [Symbol.iterator](): Generator<Tick> {
- const span = this.scale.timeSpan;
- const stepSize = this._patternSize / this._tickPattern.length;
- const start = roundDownNearest(span.start, this._patternSize);
- const timeAtStep = (i: number) => start + (i * stepSize);
-
- // Iterating using steps instead of
- // for (let s = start; s < span.end; s += stepSize) because if start is much
- // larger than stepSize we can enter an infinite loop due to floating
- // point precision errors.
- for (let i = 0; timeAtStep(i) < span.end; i++) {
- const time = timeAtStep(i);
- if (time >= span.start) {
- const position = Math.floor(this.scale.timeToPx(time));
- const type = this._tickPattern[i % this._tickPattern.length];
- yield {type, time, position};
+ const stepSize = this._patternSize / BigInt(this._tickPattern.length);
+ const start = roundDownNearest(this._timeSpan.start, this._patternSize);
+ const end = this._timeSpan.end;
+ let patternIndex = 0;
+
+ for (let time = start; time < end; time += stepSize, patternIndex++) {
+ if (time >= this._timeSpan.start) {
+ patternIndex = patternIndex % this._tickPattern.length;
+ const type = this._tickPattern[patternIndex];
+ yield {type, time: time + this._offset};
}
}
}
- // The number of decimal places labels should be printed with, assuming labels
- // are only printed on major ticks.
get digits(): number {
return guessDecimalPlaces(this._patternSize);
}
@@ -157,9 +204,7 @@ export class TickGenerator implements Iterable<Tick> {
// Gets the timescale associated with the current visible window.
export function timeScaleForVisibleWindow(
startPx: number, endPx: number): TimeScale {
- const span = globals.frontendLocalState.visibleWindowTime;
- const spanRelative = span.add(-globals.state.traceTime.startSec);
- return new TimeScale(spanRelative, [startPx, endPx]);
+ return globals.frontendLocalState.getTimeScale(startPx, endPx);
}
export function drawGridLines(
@@ -169,13 +214,18 @@ export function drawGridLines(
ctx.strokeStyle = TRACK_BORDER_COLOR;
ctx.lineWidth = 1;
- const timeScale = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, width);
- if (timeScale.timeSpan.duration > 0 && timeScale.widthPx > 0) {
- for (const {type, position} of new TickGenerator(timeScale)) {
+ const {earliest, latest} = globals.frontendLocalState.visibleWindow;
+ const span = new TPTimeSpan(earliest, latest);
+ if (width > TRACK_SHELL_WIDTH && span.duration > 0n) {
+ const maxMajorTicks = getMaxMajorTicks(width - TRACK_SHELL_WIDTH);
+ const map = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, width);
+ for (const {type, time} of new TickGenerator(
+ span, maxMajorTicks, globals.state.traceTime.start)) {
+ const px = Math.floor(map.tpTimeToPx(time));
if (type === TickType.MAJOR) {
ctx.beginPath();
- ctx.moveTo(position + 0.5, 0);
- ctx.lineTo(position + 0.5, height);
+ ctx.moveTo(px + 0.5, 0);
+ ctx.lineTo(px + 0.5, height);
ctx.stroke();
}
}
diff --git a/ui/src/frontend/gridline_helper_unittest.ts b/ui/src/frontend/gridline_helper_unittest.ts
index 3b6dcacad..2454680f6 100644
--- a/ui/src/frontend/gridline_helper_unittest.ts
+++ b/ui/src/frontend/gridline_helper_unittest.ts
@@ -12,303 +12,93 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {TimeSpan} from '../common/time';
+import {TPTimeSpan} from '../common/time';
-import {getStepSize, Tick, TickGenerator, TickType} from './gridline_helper';
-import {TimeScale} from './time_scale';
-
-const pattern1 = '|....:....';
-const pattern2 = '|.:.';
-const pattern5 = '|....';
-const timeScale = new TimeScale(new TimeSpan(0, 1), [1, 2]);
+import {getPattern, TickGenerator, TickType} from './gridline_helper';
test('gridline helper to have sensible step sizes', () => {
- expect(getStepSize(10, 14)).toEqual([1, pattern1]);
- expect(getStepSize(30, 14)).toEqual([5, pattern5]);
- expect(getStepSize(60, 14)).toEqual([5, pattern5]);
- expect(getStepSize(100, 14)).toEqual([10, pattern1]);
-
- expect(getStepSize(10, 21)).toEqual([0.5, pattern5]);
- expect(getStepSize(30, 21)).toEqual([2, pattern2]);
- expect(getStepSize(60, 21)).toEqual([5, pattern5]);
- expect(getStepSize(100, 21)).toEqual([5, pattern5]);
-
- expect(getStepSize(10, 3)).toEqual([5, pattern5]);
- expect(getStepSize(30, 3)).toEqual([10, pattern1]);
- expect(getStepSize(60, 3)).toEqual([20, pattern2]);
- expect(getStepSize(100, 3)).toEqual([50, pattern5]);
-
- expect(getStepSize(800, 4)).toEqual([200, pattern2]);
-});
-
-test('gridline helper to scale to very small and very large values', () => {
- expect(getStepSize(.01, 14)).toEqual([.001, pattern1]);
- expect(getStepSize(10000, 14)).toEqual([1000, pattern1]);
-});
-
-test('gridline helper to always return a reasonable number of steps', () => {
- for (let i = 1; i <= 1000; i++) {
- const [stepSize, _] = getStepSize(i, 14);
- expect(Math.round(i / stepSize)).toBeGreaterThanOrEqual(6);
- expect(Math.round(i / stepSize)).toBeLessThanOrEqual(14);
- }
-});
-
-describe('TickGenerator with range 0.0-1.0 and room for 2 labels', () => {
- let tickGen: TickGenerator|undefined = undefined;
- beforeAll(() => {
- const timeSpan = new TimeSpan(0.0, 1.0);
- const timeScale = new TimeScale(timeSpan, [0, 200]);
- tickGen = new TickGenerator(timeScale, {minLabelPx: 100});
- });
- it('should produce major ticks at 0.5s and minor ticks at 0.1s starting at 0',
- () => {
- const expected = [
- {type: TickType.MAJOR, time: 0.0},
- {type: TickType.MINOR, time: 0.1},
- {type: TickType.MINOR, time: 0.2},
- {type: TickType.MINOR, time: 0.3},
- {type: TickType.MINOR, time: 0.4},
- {type: TickType.MAJOR, time: 0.5},
- {type: TickType.MINOR, time: 0.6},
- {type: TickType.MINOR, time: 0.7},
- {type: TickType.MINOR, time: 0.8},
- {type: TickType.MINOR, time: 0.9},
- ];
- const actual = Array.from(tickGen!);
- expectTicksEqual(actual, expected);
- });
- it('should tell us to use 1 decimal place for labels', () => {
- expect(tickGen!.digits).toEqual(1);
- });
+ expect(getPattern(1n)).toEqual([1n, '|']);
+ expect(getPattern(2n)).toEqual([2n, '|:']);
+ expect(getPattern(3n)).toEqual([5n, '|....']);
+ expect(getPattern(4n)).toEqual([5n, '|....']);
+ expect(getPattern(5n)).toEqual([5n, '|....']);
+ expect(getPattern(7n)).toEqual([10n, '|....:....']);
+
+ expect(getPattern(10n)).toEqual([10n, '|....:....']);
+ expect(getPattern(20n)).toEqual([20n, '|.:.']);
+ expect(getPattern(50n)).toEqual([50n, '|....']);
+
+ expect(getPattern(100n)).toEqual([100n, '|....:....']);
});
-describe('TickGenerator with range 0.3-1.3 and room for 2 labels', () => {
- let tickGen: TickGenerator|undefined = undefined;
- beforeAll(() => {
- const timeSpan = new TimeSpan(0.3, 1.3);
- const timeScale = new TimeScale(timeSpan, [0, 200]);
- tickGen = new TickGenerator(timeScale, {minLabelPx: 100});
+describe('TickGenerator', () => {
+ it('can generate ticks with span starting at origin', () => {
+ const tickGen = new TickGenerator(new TPTimeSpan(0n, 10n), 1);
+ const expected = [
+ {type: TickType.MAJOR, time: 0n},
+ {type: TickType.MINOR, time: 1n},
+ {type: TickType.MINOR, time: 2n},
+ {type: TickType.MINOR, time: 3n},
+ {type: TickType.MINOR, time: 4n},
+ {type: TickType.MEDIUM, time: 5n},
+ {type: TickType.MINOR, time: 6n},
+ {type: TickType.MINOR, time: 7n},
+ {type: TickType.MINOR, time: 8n},
+ {type: TickType.MINOR, time: 9n},
+ ];
+ const actual = Array.from(tickGen!);
+ expect(actual).toStrictEqual(expected);
+ expect(tickGen!.digits).toEqual(8);
});
- it('should produce major ticks at 0.5s and minor ticks at 0.1s starting at 0',
- () => {
- const expected = [
- {type: TickType.MINOR, time: 0.3},
- {type: TickType.MINOR, time: 0.4},
- {type: TickType.MAJOR, time: 0.5},
- {type: TickType.MINOR, time: 0.6},
- {type: TickType.MINOR, time: 0.7},
- {type: TickType.MINOR, time: 0.8},
- {type: TickType.MINOR, time: 0.9},
- {type: TickType.MAJOR, time: 1.0},
- {type: TickType.MINOR, time: 1.1},
- {type: TickType.MINOR, time: 1.2},
- ];
- const actual = Array.from(tickGen!);
- expectTicksEqual(actual, expected);
- });
- it('should tell us to use 1 decimal place for labels', () => {
- expect(tickGen!.digits).toEqual(1);
- });
-});
-describe('TickGenerator with range 0.0-0.2 and room for 1 label', () => {
- let tickGen: TickGenerator|undefined = undefined;
- beforeAll(() => {
- const timeSpan = new TimeSpan(0.0, 0.2);
- const timeScale = new TimeScale(timeSpan, [0, 100]);
- tickGen = new TickGenerator(timeScale, {minLabelPx: 100});
+ it('can generate ticks when span has an offset', () => {
+ const tickGen = new TickGenerator(new TPTimeSpan(10n, 20n), 1);
+ const expected = [
+ {type: TickType.MAJOR, time: 10n},
+ {type: TickType.MINOR, time: 11n},
+ {type: TickType.MINOR, time: 12n},
+ {type: TickType.MINOR, time: 13n},
+ {type: TickType.MINOR, time: 14n},
+ {type: TickType.MEDIUM, time: 15n},
+ {type: TickType.MINOR, time: 16n},
+ {type: TickType.MINOR, time: 17n},
+ {type: TickType.MINOR, time: 18n},
+ {type: TickType.MINOR, time: 19n},
+ ];
+ const actual = Array.from(tickGen!);
+ expect(actual).toStrictEqual(expected);
+ expect(tickGen!.digits).toEqual(8);
});
- it('should produce major ticks at 0.2s and minor ticks at 0.1s starting at 0',
- () => {
- const expected = [
- {type: TickType.MAJOR, time: 0.0},
- {type: TickType.MINOR, time: 0.05},
- {type: TickType.MEDIUM, time: 0.1},
- {type: TickType.MINOR, time: 0.15},
- ];
- const actual = Array.from(tickGen!);
- expectTicksEqual(actual, expected);
- });
- it('should tell us to use 1 decimal place for labels', () => {
- expect(tickGen!.digits).toEqual(1);
- });
-});
-describe('TickGenerator with range 0.0-0.1 and room for 1 label', () => {
- let tickGen: TickGenerator|undefined = undefined;
- beforeAll(() => {
- const timeSpan = new TimeSpan(0.0, 0.1);
- const timeScale = new TimeScale(timeSpan, [0, 100]);
- tickGen = new TickGenerator(timeScale, {minLabelPx: 100});
- });
- it('should produce major ticks at 0.1s & minor ticks at 0.02s starting at 0',
- () => {
- const expected = [
- {type: TickType.MAJOR, time: 0.0},
- {type: TickType.MINOR, time: 0.01},
- {type: TickType.MINOR, time: 0.02},
- {type: TickType.MINOR, time: 0.03},
- {type: TickType.MINOR, time: 0.04},
- {type: TickType.MEDIUM, time: 0.05},
- {type: TickType.MINOR, time: 0.06},
- {type: TickType.MINOR, time: 0.07},
- {type: TickType.MINOR, time: 0.08},
- {type: TickType.MINOR, time: 0.09},
- ];
- const actual = Array.from(tickGen!);
- expect(tickGen!.digits).toEqual(1);
- expectTicksEqual(actual, expected);
- });
- it('should tell us to use 1 decimal place for labels', () => {
- expect(tickGen!.digits).toEqual(1);
- });
-});
-
-describe('TickGenerator with a very small timespan', () => {
- let tickGen: TickGenerator|undefined = undefined;
- beforeAll(() => {
- const timeSpan = new TimeSpan(0.0, 1e-9);
- const timeScale = new TimeScale(timeSpan, [0, 100]);
- tickGen = new TickGenerator(timeScale, {minLabelPx: 100});
- });
- it('should generate minor ticks at 2e-10s and one major tick at the start',
- () => {
- const expected = [
- {type: TickType.MAJOR, time: 0.0},
- {type: TickType.MINOR, time: 1e-10},
- {type: TickType.MINOR, time: 2e-10},
- {type: TickType.MINOR, time: 3e-10},
- {type: TickType.MINOR, time: 4e-10},
- {type: TickType.MEDIUM, time: 5e-10},
- {type: TickType.MINOR, time: 6e-10},
- {type: TickType.MINOR, time: 7e-10},
- {type: TickType.MINOR, time: 8e-10},
- {type: TickType.MINOR, time: 9e-10},
- ];
- const actual = Array.from(tickGen!);
- expectTicksEqual(actual, expected);
- });
- it('should tell us to use 9 decimal places for labels', () => {
- expect(tickGen!.digits).toEqual(9);
- });
-});
-
-describe('TickGenerator with a very large timespan', () => {
- let tickGen: TickGenerator|undefined = undefined;
- beforeAll(() => {
- const timeSpan = new TimeSpan(0.0, 1e9);
- const timeScale = new TimeScale(timeSpan, [0, 100]);
- tickGen = new TickGenerator(timeScale, {minLabelPx: 100});
- });
- it('should generate minor ticks at 2e8 and one major tick at the start',
- () => {
- const expected = [
- {type: TickType.MAJOR, time: 0.0},
- {type: TickType.MINOR, time: 1e8},
- {type: TickType.MINOR, time: 2e8},
- {type: TickType.MINOR, time: 3e8},
- {type: TickType.MINOR, time: 4e8},
- {type: TickType.MEDIUM, time: 5e8},
- {type: TickType.MINOR, time: 6e8},
- {type: TickType.MINOR, time: 7e8},
- {type: TickType.MINOR, time: 8e8},
- {type: TickType.MINOR, time: 9e8},
- ];
- const actual = Array.from(tickGen!);
- expectTicksEqual(actual, expected);
- });
- it('should tell us to use 0 decimal places for labels', () => {
+ it('can generate ticks when span is large', () => {
+ const tickGen =
+ new TickGenerator(new TPTimeSpan(1000000000n, 2000000000n), 1);
+ const expected = [
+ {type: TickType.MAJOR, time: 1000000000n},
+ {type: TickType.MINOR, time: 1100000000n},
+ {type: TickType.MINOR, time: 1200000000n},
+ {type: TickType.MINOR, time: 1300000000n},
+ {type: TickType.MINOR, time: 1400000000n},
+ {type: TickType.MEDIUM, time: 1500000000n},
+ {type: TickType.MINOR, time: 1600000000n},
+ {type: TickType.MINOR, time: 1700000000n},
+ {type: TickType.MINOR, time: 1800000000n},
+ {type: TickType.MINOR, time: 1900000000n},
+ ];
+ const actual = Array.from(tickGen!);
+ expect(actual).toStrictEqual(expected);
expect(tickGen!.digits).toEqual(0);
});
-});
-describe('TickGenerator where the timespan has a dynamic range of 1e12', () => {
- // This is the equivalent of zooming in to the nanosecond level, 1000 seconds
- // into a trace Note: this is about the limit of what this generator can
- // handle.
- let tickGen: TickGenerator|undefined = undefined;
- beforeAll(() => {
- const timeSpan = new TimeSpan(1000, 1000.000000001);
- const timeScale = new TimeScale(timeSpan, [0, 100]);
- tickGen = new TickGenerator(timeScale, {minLabelPx: 100});
- });
- it('should generate minor ticks at 1e-10s and one major tick at the start',
- () => {
- const expected = [
- {type: TickType.MAJOR, time: 1000.0000000000},
- {type: TickType.MINOR, time: 1000.0000000001},
- {type: TickType.MINOR, time: 1000.0000000002},
- {type: TickType.MINOR, time: 1000.0000000003},
- {type: TickType.MINOR, time: 1000.0000000004},
- {type: TickType.MEDIUM, time: 1000.0000000005},
- {type: TickType.MINOR, time: 1000.0000000006},
- {type: TickType.MINOR, time: 1000.0000000007},
- {type: TickType.MINOR, time: 1000.0000000008},
- {type: TickType.MINOR, time: 1000.0000000009},
- ];
- const actual = Array.from(tickGen!);
- expectTicksEqual(actual, expected);
- });
- it('should tell us to use 9 decimal places for labels', () => {
- expect(tickGen!.digits).toEqual(9);
+ it('throws an error when timespan duration is 0', () => {
+ expect(() => {
+ new TickGenerator(new TPTimeSpan(0n, 0n), 1);
+ }).toThrow(Error);
});
-});
-
-describe(
- 'TickGenerator where the timespan has a ridiculously huge dynamic range',
- () => {
- // We don't expect this to work, just wanna make sure it doesn't crash or
- // get stuck
- it('should not crash or get stuck in an infinite loop', () => {
- const timeSpan = new TimeSpan(1000, 1000.000000000001);
- const timeScale = new TimeScale(timeSpan, [0, 100]);
- new TickGenerator(timeScale);
- });
- });
-
-describe(
- 'TickGenerator where the timespan has a ridiculously huge dynamic range',
- () => {
- // We don't expect this to work, just wanna make sure it doesn't crash or
- // get stuck
- it('should not crash or get stuck in an infinite loop', () => {
- const timeSpan = new TimeSpan(1000, 1000.000000000001);
- const timeScale = new TimeScale(timeSpan, [0, 100]);
- new TickGenerator(timeScale);
- });
- });
-
-test('TickGenerator constructed with a 0 width throws an error', () => {
- expect(() => {
- const timeScale = new TimeScale(new TimeSpan(0.0, 1.0), [0, 0]);
- new TickGenerator(timeScale);
- }).toThrow(Error);
-});
-
-test(
- 'TickGenerator constructed with desiredPxPerStep of 0 throws an error',
- () => {
- expect(() => {
- new TickGenerator(timeScale, {minLabelPx: 0});
- }).toThrow(Error);
- });
-test('TickGenerator constructed with a 0 duration throws an error', () => {
- expect(() => {
- const timeScale = new TimeScale(new TimeSpan(0.0, 0.0), [0, 1]);
- new TickGenerator(timeScale);
- }).toThrow(Error);
+ it('throws an error when max ticks is 0', () => {
+ expect(() => {
+ new TickGenerator(new TPTimeSpan(0n, 1n), 0);
+ }).toThrow(Error);
+ });
});
-
-function expectTicksEqual(actual: Tick[], expected: any[]) {
- // TODO(stevegolton) We could write a custom matcher for this; this approach
- // produces cryptic error messages.
- expect(actual.length).toEqual(expected.length);
- for (let i = 0; i < actual.length; ++i) {
- const ex = expected[i];
- const ac = actual[i];
- expect(ac.type).toEqual(ex.type);
- expect(ac.time).toBeCloseTo(ex.time, 9);
- }
-}
diff --git a/ui/src/frontend/keyboard_event_handler.ts b/ui/src/frontend/keyboard_event_handler.ts
index 7da04de6a..f25bf5274 100644
--- a/ui/src/frontend/keyboard_event_handler.ts
+++ b/ui/src/frontend/keyboard_event_handler.ts
@@ -14,6 +14,7 @@
import {Actions} from '../common/actions';
import {Area} from '../common/state';
+import {TPTime} from '../common/time';
import {Flow, globals} from './globals';
import {toggleHelp} from './help_modal';
@@ -23,7 +24,8 @@ import {
} from './scroll_helper';
import {executeSearch} from './search_handler';
-const INSTANT_FOCUS_DURATION_S = 1 / 1e9; // 1 ns.
+const INSTANT_FOCUS_DURATION = 1n;
+const INCOMPLETE_SLICE_DURATION = 30_000n;
type Direction = 'Forward'|'Backward';
// Handles all key events than are not handled by the
@@ -55,8 +57,8 @@ export function handleKey(e: KeyboardEvent, down: boolean): boolean {
if (selection !== null && selection.kind === 'AREA') {
const area = globals.state.areas[selection.areaId];
const coversEntireTimeRange =
- globals.state.traceTime.startSec === area.startSec &&
- globals.state.traceTime.endSec === area.endSec;
+ globals.state.traceTime.start === area.start &&
+ globals.state.traceTime.end === area.end;
if (!coversEntireTimeRange) {
// If the current selection is an area which does not cover the entire
// time range, preserve the list of selected tracks and expand the time
@@ -71,10 +73,11 @@ export function handleKey(e: KeyboardEvent, down: boolean): boolean {
// If the current selection is not an area, select all.
tracksToSelect = Object.keys(globals.state.tracks);
}
+ const {start, end} = globals.state.traceTime;
globals.dispatch(Actions.selectArea({
area: {
- startSec: globals.state.traceTime.startSec,
- endSec: globals.state.traceTime.endSec,
+ start,
+ end,
tracks: tracksToSelect,
},
}));
@@ -201,29 +204,29 @@ function moveByFocusedFlow(direction: Direction): void {
}
}
-function findTimeRangeOfSelection(): {startTs: number, endTs: number} {
+function findTimeRangeOfSelection(): {startTs: TPTime, endTs: TPTime} {
const selection = globals.state.currentSelection;
- let startTs = -1;
- let endTs = -1;
+ let startTs = -1n;
+ let endTs = -1n;
if (selection === null) {
return {startTs, endTs};
} else if (selection.kind === 'SLICE' || selection.kind === 'CHROME_SLICE') {
const slice = globals.sliceDetails;
if (slice.ts && slice.dur !== undefined && slice.dur > 0) {
- startTs = slice.ts + globals.state.traceTime.startSec;
+ startTs = slice.ts;
endTs = startTs + slice.dur;
} else if (slice.ts) {
- startTs = slice.ts + globals.state.traceTime.startSec;
+ startTs = slice.ts;
// This will handle either:
// a)slice.dur === -1 -> unfinished slice
// b)slice.dur === 0 -> instant event
- endTs = slice.dur === -1 ? globals.state.traceTime.endSec :
- startTs + INSTANT_FOCUS_DURATION_S;
+ endTs = slice.dur === -1n ? startTs + INCOMPLETE_SLICE_DURATION :
+ startTs + INSTANT_FOCUS_DURATION;
}
} else if (selection.kind === 'THREAD_STATE') {
const threadState = globals.threadStateDetails;
if (threadState.ts && threadState.dur) {
- startTs = threadState.ts + globals.state.traceTime.startSec;
+ startTs = threadState.ts;
endTs = startTs + threadState.dur;
}
} else if (selection.kind === 'COUNTER') {
@@ -232,8 +235,8 @@ function findTimeRangeOfSelection(): {startTs: number, endTs: number} {
} else if (selection.kind === 'AREA') {
const selectedArea = globals.state.areas[selection.areaId];
if (selectedArea) {
- startTs = selectedArea.startSec;
- endTs = selectedArea.endSec;
+ startTs = selectedArea.start;
+ endTs = selectedArea.end;
}
} else if (selection.kind === 'NOTE') {
const selectedNote = globals.state.notes[selection.id];
@@ -241,16 +244,18 @@ function findTimeRangeOfSelection(): {startTs: number, endTs: number} {
// above in the AREA case.
if (selectedNote && selectedNote.noteType === 'DEFAULT') {
startTs = selectedNote.timestamp;
- endTs = selectedNote.timestamp + INSTANT_FOCUS_DURATION_S;
+ endTs = selectedNote.timestamp + INSTANT_FOCUS_DURATION;
}
} else if (selection.kind === 'LOG') {
// TODO(hjd): Make focus selection work for logs.
- } else if (selection.kind === 'DEBUG_SLICE') {
- startTs = selection.startS;
- if (selection.durationS > 0) {
- endTs = startTs + selection.durationS;
+ } else if (
+ selection.kind === 'DEBUG_SLICE' ||
+ selection.kind === 'TOP_LEVEL_SCROLL') {
+ startTs = selection.start;
+ if (selection.duration > 0) {
+ endTs = startTs + selection.duration;
} else {
- endTs = startTs + INSTANT_FOCUS_DURATION_S;
+ endTs = startTs + INSTANT_FOCUS_DURATION;
}
}
@@ -260,12 +265,12 @@ function findTimeRangeOfSelection(): {startTs: number, endTs: number} {
function lockSliceSpan(persistent = false) {
const range = findTimeRangeOfSelection();
- if (range.startTs !== -1 && range.endTs !== -1 &&
+ if (range.startTs !== -1n && range.endTs !== -1n &&
globals.state.currentSelection !== null) {
const tracks = globals.state.currentSelection.trackId ?
[globals.state.currentSelection.trackId] :
[];
- const area: Area = {startSec: range.startTs, endSec: range.endTs, tracks};
+ const area: Area = {start: range.startTs, end: range.endTs, tracks};
globals.dispatch(Actions.markArea({area, persistent}));
}
}
@@ -275,7 +280,7 @@ export function findCurrentSelection() {
if (selection === null) return;
const range = findTimeRangeOfSelection();
- if (range.startTs !== -1 && range.endTs !== -1) {
+ if (range.startTs !== -1n && range.endTs !== -1n) {
focusHorizontalRange(range.startTs, range.endTs);
}
diff --git a/ui/src/frontend/logs_panel.ts b/ui/src/frontend/logs_panel.ts
index 18ed325ba..88baa1ccd 100644
--- a/ui/src/frontend/logs_panel.ts
+++ b/ui/src/frontend/logs_panel.ts
@@ -16,14 +16,14 @@ import m from 'mithril';
import {assertExists} from '../base/logging';
import {Actions} from '../common/actions';
+import {HighPrecisionTimeSpan} from '../common/high_precision_time';
import {
LogBounds,
LogBoundsKey,
LogEntries,
LogEntriesKey,
} from '../common/logs';
-import {formatTimestamp} from '../common/time';
-import {TimeSpan} from '../common/time';
+import {formatTPTime, TPTime} from '../common/time';
import {SELECTED_LOG_ROWS_COLOR} from './css_constants';
import {globals} from './globals';
@@ -62,12 +62,16 @@ export class LogPanel extends Panel<{}> {
dom.parentElement!.parentElement!.parentElement as HTMLElement);
this.scrollContainer.addEventListener(
'scroll', this.onScroll.bind(this), {passive: true});
+ // TODO(stevegolton): Type assersions are a source of bugs.
+ // Let's try to find another way of doing this.
this.bounds = globals.trackDataStore.get(LogBoundsKey) as LogBounds;
this.entries = globals.trackDataStore.get(LogEntriesKey) as LogEntries;
this.recomputeVisibleRowsAndUpdate();
}
onbeforeupdate(_: m.CVnodeDOM) {
+ // TODO(stevegolton): Type assersions are a source of bugs.
+ // Let's try to find another way of doing this.
this.bounds = globals.trackDataStore.get(LogBoundsKey) as LogBounds;
this.entries = globals.trackDataStore.get(LogEntriesKey) as LogEntries;
this.recomputeVisibleRowsAndUpdate();
@@ -79,12 +83,12 @@ export class LogPanel extends Panel<{}> {
globals.rafScheduler.scheduleFullRedraw();
}
- onRowOver(ts: number) {
+ onRowOver(ts: TPTime) {
globals.dispatch(Actions.setHoverCursorTimestamp({ts}));
}
onRowOut() {
- globals.dispatch(Actions.setHoverCursorTimestamp({ts: -1}));
+ globals.dispatch(Actions.setHoverCursorTimestamp({ts: -1n}));
}
private totalRows():
@@ -92,17 +96,19 @@ export class LogPanel extends Panel<{}> {
if (!this.bounds) {
return {isStale: false, total: 0, offset: 0, count: 0};
}
- const {total, startTs, endTs, firstRowTs, lastRowTs} = this.bounds;
+ const {
+ totalVisibleLogs,
+ firstVisibleLogTs,
+ lastVisibleLogTs,
+ } = this.bounds;
const vis = globals.frontendLocalState.visibleWindowTime;
- const leftSpan = new TimeSpan(startTs, firstRowTs);
- const rightSpan = new TimeSpan(lastRowTs, endTs);
-
- const isStaleLeft = !leftSpan.isInBounds(vis.start);
- const isStaleRight = !rightSpan.isInBounds(vis.end);
- const isStale = isStaleLeft || isStaleRight;
- const offset = Math.min(this.visibleRowOffset, total);
- const visCount = Math.min(total - offset, this.visibleRowCount);
- return {isStale, total, count: visCount, offset};
+
+ const visibleLogSpan =
+ new HighPrecisionTimeSpan(firstVisibleLogTs, lastVisibleLogTs);
+ const isStale = !vis.contains(visibleLogSpan);
+ const offset = Math.min(this.visibleRowOffset, totalVisibleLogs);
+ const visCount = Math.min(totalVisibleLogs - offset, this.visibleRowCount);
+ return {isStale, total: totalVisibleLogs, count: visCount, offset};
}
view(_: m.CVnode<{}>) {
@@ -146,11 +152,10 @@ export class LogPanel extends Panel<{}> {
{
'class': isStale ? 'stale' : '',
style,
- 'onmouseover': this.onRowOver.bind(this, ts / 1e9),
+ 'onmouseover': this.onRowOver.bind(this, ts),
'onmouseout': this.onRowOut.bind(this),
},
- m('.cell',
- formatTimestamp(ts / 1e9 - globals.state.traceTime.startSec)),
+ m('.cell', formatTPTime(ts - globals.state.traceTime.start)),
m('.cell', priorityLetter || '?'),
m('.cell', tags[i]),
hasProcessNames ? m('.cell.with-process', processNames[i]) :
diff --git a/ui/src/frontend/notes_panel.ts b/ui/src/frontend/notes_panel.ts
index d3eec0733..27d9ec8ae 100644
--- a/ui/src/frontend/notes_panel.ts
+++ b/ui/src/frontend/notes_panel.ts
@@ -17,7 +17,9 @@ import m from 'mithril';
import {Actions} from '../common/actions';
import {randomColor} from '../common/colorizer';
import {AreaNote, Note} from '../common/state';
-import {timeToString} from '../common/time';
+import {
+ tpTimeToString,
+} from '../common/time';
import {
BottomTab,
@@ -28,6 +30,7 @@ import {TRACK_SHELL_WIDTH} from './css_constants';
import {PerfettoMouseEvent} from './events';
import {globals} from './globals';
import {
+ getMaxMajorTicks,
TickGenerator,
TickType,
timeScaleForVisibleWindow,
@@ -46,7 +49,7 @@ function toSummary(s: string) {
function getStartTimestamp(note: Note|AreaNote) {
if (note.noteType === 'AREA') {
- return globals.state.areas[note.areaId].startSec;
+ return globals.state.areas[note.areaId].start;
} else {
return note.timestamp;
}
@@ -66,7 +69,7 @@ export class NotesPanel extends Panel {
});
dom.addEventListener('mouseout', () => {
this.hoveredX = null;
- globals.dispatch(Actions.setHoveredNoteTimestamp({ts: -1}));
+ globals.dispatch(Actions.setHoveredNoteTimestamp({ts: -1n}));
}, {passive: true});
}
@@ -110,15 +113,27 @@ export class NotesPanel extends Panel {
}
renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
- const timeScale = globals.frontendLocalState.timeScale;
let aNoteIsHovered = false;
ctx.fillStyle = '#999';
ctx.fillRect(TRACK_SHELL_WIDTH - 2, 0, 2, size.height);
- const relScale = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
- if (relScale.timeSpan.duration > 0 && relScale.widthPx > 0) {
- for (const {type, position} of new TickGenerator(relScale)) {
- if (type === TickType.MAJOR) ctx.fillRect(position, 0, 1, size.height);
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(TRACK_SHELL_WIDTH, 0, size.width - TRACK_SHELL_WIDTH, size.height);
+ ctx.clip();
+
+ const span = globals.frontendLocalState.visibleWindow.timestampSpan;
+ const {visibleTimeScale} = globals.frontendLocalState;
+ if (size.width > TRACK_SHELL_WIDTH && span.duration > 0n) {
+ const maxMajorTicks = getMaxMajorTicks(size.width - TRACK_SHELL_WIDTH);
+ const map = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
+ for (const {type, time} of new TickGenerator(
+ span, maxMajorTicks, globals.state.traceTime.start)) {
+ const px = Math.floor(map.tpTimeToPx(time));
+ if (type === TickType.MAJOR) {
+ ctx.fillRect(px, 0, 1, size.height);
+ }
}
}
@@ -129,11 +144,10 @@ export class NotesPanel extends Panel {
const timestamp = getStartTimestamp(note);
// TODO(hjd): We should still render area selection marks in viewport is
// *within* the area (e.g. both lhs and rhs are out of bounds).
- if ((note.noteType !== 'AREA' && !timeScale.timeInBounds(timestamp)) ||
+ if ((note.noteType !== 'AREA' && !span.contains(timestamp)) ||
(note.noteType === 'AREA' &&
- !timeScale.timeInBounds(globals.state.areas[note.areaId].endSec) &&
- !timeScale.timeInBounds(
- globals.state.areas[note.areaId].startSec))) {
+ !span.contains(globals.state.areas[note.areaId].end) &&
+ !span.contains(globals.state.areas[note.areaId].start))) {
continue;
}
const currentIsHovered =
@@ -144,7 +158,7 @@ export class NotesPanel extends Panel {
const isSelected = selection !== null &&
((selection.kind === 'NOTE' && selection.id === note.id) ||
(selection.kind === 'AREA' && selection.noteId === note.id));
- const x = timeScale.timeToPx(timestamp);
+ const x = visibleTimeScale.tpTimeToPx(timestamp);
const left = Math.floor(x + TRACK_SHELL_WIDTH);
// Draw flag or marker.
@@ -153,7 +167,8 @@ export class NotesPanel extends Panel {
this.drawAreaMarker(
ctx,
left,
- Math.floor(timeScale.timeToPx(area.endSec) + TRACK_SHELL_WIDTH),
+ Math.floor(
+ visibleTimeScale.tpTimeToPx(area.end) + TRACK_SHELL_WIDTH),
note.color,
isSelected);
} else {
@@ -175,19 +190,21 @@ export class NotesPanel extends Panel {
// A real note is hovered so we don't need to see the preview line.
// TODO(hjd): Change cursor to pointer here.
if (aNoteIsHovered) {
- globals.dispatch(Actions.setHoveredNoteTimestamp({ts: -1}));
+ globals.dispatch(Actions.setHoveredNoteTimestamp({ts: -1n}));
}
// View preview note flag when hovering on notes panel.
if (!aNoteIsHovered && this.hoveredX !== null) {
- const timestamp = timeScale.pxToTime(this.hoveredX);
- if (timeScale.timeInBounds(timestamp)) {
+ const timestamp = visibleTimeScale.pxToHpTime(this.hoveredX).toTPTime();
+ if (span.contains(timestamp)) {
globals.dispatch(Actions.setHoveredNoteTimestamp({ts: timestamp}));
- const x = timeScale.timeToPx(timestamp);
+ const x = visibleTimeScale.tpTimeToPx(timestamp);
const left = Math.floor(x + TRACK_SHELL_WIDTH);
this.drawFlag(ctx, left, size.height, '#aaa', /* fill */ true);
}
}
+
+ ctx.restore();
}
private drawAreaMarker(
@@ -197,7 +214,7 @@ export class NotesPanel extends Panel {
ctx.strokeStyle = color;
const topOffset = 10;
// Don't draw in the track shell section.
- if (x >= globals.frontendLocalState.timeScale.startPx + TRACK_SHELL_WIDTH) {
+ if (x >= globals.frontendLocalState.windowSpan.start + TRACK_SHELL_WIDTH) {
// Draw left triangle.
ctx.beginPath();
ctx.moveTo(x, topOffset);
@@ -218,7 +235,7 @@ export class NotesPanel extends Panel {
// Start line after track shell section, join triangles.
const startDraw = Math.max(
- x, globals.frontendLocalState.timeScale.startPx + TRACK_SHELL_WIDTH);
+ x, globals.frontendLocalState.windowSpan.start + TRACK_SHELL_WIDTH);
ctx.beginPath();
ctx.moveTo(startDraw, topOffset);
ctx.lineTo(xEnd, topOffset);
@@ -250,8 +267,8 @@ export class NotesPanel extends Panel {
private onClick(x: number, _: number) {
if (x < 0) return;
- const timeScale = globals.frontendLocalState.timeScale;
- const timestamp = timeScale.pxToTime(x);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const timestamp = visibleTimeScale.pxToHpTime(x).toTPTime();
for (const note of Object.values(globals.state.notes)) {
if (this.hoveredX && this.mouseOverNote(this.hoveredX, note)) {
if (note.noteType === 'AREA') {
@@ -268,13 +285,13 @@ export class NotesPanel extends Panel {
}
private mouseOverNote(x: number, note: AreaNote|Note): boolean {
- const timeScale = globals.frontendLocalState.timeScale;
- const noteX = timeScale.timeToPx(getStartTimestamp(note));
+ const timeScale = globals.frontendLocalState.visibleTimeScale;
+ const noteX = timeScale.tpTimeToPx(getStartTimestamp(note));
if (note.noteType === 'AREA') {
const noteArea = globals.state.areas[note.areaId];
return (noteX <= x && x < noteX + AREA_TRIANGLE_WIDTH) ||
- (timeScale.timeToPx(noteArea.endSec) > x &&
- x > timeScale.timeToPx(noteArea.endSec) - AREA_TRIANGLE_WIDTH);
+ (timeScale.tpTimeToPx(noteArea.end) > x &&
+ x > timeScale.tpTimeToPx(noteArea.end) - AREA_TRIANGLE_WIDTH);
} else {
const width = FLAG_WIDTH;
return noteX <= x && x < noteX + width;
@@ -308,13 +325,12 @@ export class NotesEditorTab extends BottomTab<NotesEditorTabConfig> {
if (note === undefined) {
return m('.', `No Note with id ${this.config.id}`);
}
- const startTime =
- getStartTimestamp(note) - globals.state.traceTime.startSec;
+ const startTime = getStartTimestamp(note) - globals.state.traceTime.start;
return m(
'.notes-editor-panel',
m('.notes-editor-panel-heading-bar',
m('.notes-editor-panel-heading',
- `Annotation at ${timeToString(startTime)}`),
+ `Annotation at ${tpTimeToString(startTime)}`),
m('input[type=text]', {
onkeydown: (e: Event) => {
e.stopImmediatePropagation();
diff --git a/ui/src/frontend/overview_timeline_panel.ts b/ui/src/frontend/overview_timeline_panel.ts
index 76b451582..54f932e54 100644
--- a/ui/src/frontend/overview_timeline_panel.ts
+++ b/ui/src/frontend/overview_timeline_panel.ts
@@ -14,9 +14,12 @@
import m from 'mithril';
-import {assertExists} from '../base/logging';
import {hueForCpu} from '../common/colorizer';
-import {TimeSpan} from '../common/time';
+import {
+ Span,
+ TPTime,
+ tpTimeToSeconds,
+} from '../common/time';
import {
OVERVIEW_TIMELINE_NON_VISIBLE_COLOR,
@@ -29,9 +32,9 @@ import {InnerDragStrategy} from './drag/inner_drag_strategy';
import {OuterDragStrategy} from './drag/outer_drag_strategy';
import {DragGestureHandler} from './drag_gesture_handler';
import {globals} from './globals';
-import {TickGenerator, TickType} from './gridline_helper';
+import {getMaxMajorTicks, TickGenerator, TickType} from './gridline_helper';
import {Panel, PanelSize} from './panel';
-import {TimeScale} from './time_scale';
+import {PxSpan, TimeScale} from './time_scale';
export class OverviewTimelinePanel extends Panel {
private static HANDLE_SIZE_PX = 5;
@@ -39,7 +42,7 @@ export class OverviewTimelinePanel extends Panel {
private width = 0;
private gesture?: DragGestureHandler;
private timeScale?: TimeScale;
- private totTime = new TimeSpan(0, 0);
+ private traceTime?: Span<TPTime>;
private dragStrategy?: DragStrategy;
private readonly boundOnMouseMove = this.onMouseMove.bind(this);
@@ -47,11 +50,11 @@ export class OverviewTimelinePanel extends Panel {
// https://github.com/Microsoft/TypeScript/issues/1373
onupdate({dom}: m.CVnodeDOM) {
this.width = dom.getBoundingClientRect().width;
- this.totTime = new TimeSpan(
- globals.state.traceTime.startSec, globals.state.traceTime.endSec);
- this.timeScale = new TimeScale(
- this.totTime, [TRACK_SHELL_WIDTH, assertExists(this.width)]);
-
+ this.traceTime = globals.stateTraceTimeTP();
+ const traceTime = globals.stateTraceTime();
+ const pxSpan = new PxSpan(TRACK_SHELL_WIDTH, this.width);
+ this.timeScale =
+ new TimeScale(traceTime.start, traceTime.duration.nanos, pxSpan);
if (this.gesture === undefined) {
this.gesture = new DragGestureHandler(
dom as HTMLElement,
@@ -78,26 +81,27 @@ export class OverviewTimelinePanel extends Panel {
renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
if (this.width === undefined) return;
+ if (this.traceTime === undefined) return;
if (this.timeScale === undefined) return;
const headerHeight = 20;
const tracksHeight = size.height - headerHeight;
- const timeSpan = new TimeSpan(0, this.totTime.duration);
-
- const timeScale = new TimeScale(timeSpan, [TRACK_SHELL_WIDTH, this.width]);
- if (timeScale.timeSpan.duration > 0 && timeScale.widthPx > 0) {
- const tickGen = new TickGenerator(timeScale);
+ if (size.width > TRACK_SHELL_WIDTH && this.traceTime.duration > 0n) {
+ const maxMajorTicks = getMaxMajorTicks(this.width - TRACK_SHELL_WIDTH);
+ const tickGen = new TickGenerator(
+ this.traceTime, maxMajorTicks, globals.state.traceTime.start);
// Draw time labels on the top header.
ctx.font = '10px Roboto Condensed';
ctx.fillStyle = '#999';
- for (const {type, time, position} of tickGen) {
- const xPos = Math.round(position);
+ for (const {type, time} of tickGen) {
+ const xPos = Math.floor(this.timeScale.tpTimeToPx(time));
if (xPos <= 0) continue;
if (xPos > this.width) break;
if (type === TickType.MAJOR) {
ctx.fillRect(xPos - 1, 0, 1, headerHeight - 5);
- ctx.fillText(time.toFixed(tickGen.digits) + ' s', xPos + 5, 18);
+ const sec = tpTimeToSeconds(time - globals.state.traceTime.start);
+ ctx.fillText(sec.toFixed(tickGen.digits) + ' s', xPos + 5, 18);
} else if (type == TickType.MEDIUM) {
ctx.fillRect(xPos - 1, 0, 1, 8);
} else if (type == TickType.MINOR) {
@@ -114,8 +118,8 @@ export class OverviewTimelinePanel extends Panel {
for (const key of globals.overviewStore.keys()) {
const loads = globals.overviewStore.get(key)!;
for (let i = 0; i < loads.length; i++) {
- const xStart = Math.floor(this.timeScale.timeToPx(loads[i].startSec));
- const xEnd = Math.ceil(this.timeScale.timeToPx(loads[i].endSec));
+ const xStart = Math.floor(this.timeScale.tpTimeToPx(loads[i].start));
+ const xEnd = Math.ceil(this.timeScale.tpTimeToPx(loads[i].end));
const yOff = Math.floor(headerHeight + y * trackHeight);
const lightness = Math.ceil((1 - loads[i].load * 0.7) * 100);
ctx.fillStyle = `hsl(${hueForCpu(y)}, 50%, ${lightness}%)`;
@@ -210,10 +214,10 @@ export class OverviewTimelinePanel extends Panel {
}
private static extractBounds(timeScale: TimeScale): [number, number] {
- const vizTime = globals.frontendLocalState.getVisibleStateBounds();
+ const vizTime = globals.frontendLocalState.visibleWindowTime;
return [
- Math.floor(timeScale.timeToPx(vizTime[0])),
- Math.ceil(timeScale.timeToPx(vizTime[1])),
+ Math.floor(timeScale.hpTimeToPx(vizTime.start)),
+ Math.ceil(timeScale.hpTimeToPx(vizTime.end)),
];
}
diff --git a/ui/src/frontend/panel_container.ts b/ui/src/frontend/panel_container.ts
index 4c6576fde..b7841d7a5 100644
--- a/ui/src/frontend/panel_container.ts
+++ b/ui/src/frontend/panel_container.ts
@@ -135,11 +135,13 @@ export class PanelContainer implements m.ClassComponent<Attrs> {
return;
}
+ const {visibleTimeScale} = globals.frontendLocalState;
+
// The Y value is given from the top of the pan and zoom region, we want it
// from the top of the panel container. The parent offset corrects that.
const panels = this.getPanelsInRegion(
- globals.frontendLocalState.timeScale.timeToPx(area.startSec),
- globals.frontendLocalState.timeScale.timeToPx(area.endSec),
+ visibleTimeScale.tpTimeToPx(area.start),
+ visibleTimeScale.tpTimeToPx(area.end),
globals.frontendLocalState.areaY.start + TOPBAR_HEIGHT,
globals.frontendLocalState.areaY.end + TOPBAR_HEIGHT);
// Get the track ids from the panels.
@@ -160,7 +162,7 @@ export class PanelContainer implements m.ClassComponent<Attrs> {
}
}
}
- globals.frontendLocalState.selectArea(area.startSec, area.endSec, tracks);
+ globals.frontendLocalState.selectArea(area.start, area.end, tracks);
}
constructor(vnode: m.CVnode<Attrs>) {
@@ -449,8 +451,9 @@ export class PanelContainer implements m.ClassComponent<Attrs> {
return;
}
- const startX = globals.frontendLocalState.timeScale.timeToPx(area.startSec);
- const endX = globals.frontendLocalState.timeScale.timeToPx(area.endSec);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const startX = visibleTimeScale.tpTimeToPx(area.start);
+ const endX = visibleTimeScale.tpTimeToPx(area.end);
// To align with where to draw on the canvas subtract the first panel Y.
selectedTracksMinY -= this.panelContainerTop;
selectedTracksMaxY -= this.panelContainerTop;
diff --git a/ui/src/frontend/pivot_table_query_generator.ts b/ui/src/frontend/pivot_table_query_generator.ts
index 0c61f5618..dffa6e405 100644
--- a/ui/src/frontend/pivot_table_query_generator.ts
+++ b/ui/src/frontend/pivot_table_query_generator.ts
@@ -20,7 +20,6 @@ import {
PivotTableQuery,
PivotTableState,
} from '../common/state';
-import {toNs} from '../common/time';
import {
getSelectedTrackIds,
} from '../controller/aggregation/slice_aggregation_controller';
@@ -100,8 +99,8 @@ function aggregationAlias(aggregationIndex: number): string {
export function areaFilter(area: Area): string {
return `
- ts + dur > ${toNs(area.startSec)}
- and ts < ${toNs(area.endSec)}
+ ts + dur > ${area.start}
+ and ts < ${area.end}
and track_id in (${getSelectedTrackIds(area).join(', ')})
`;
}
diff --git a/ui/src/frontend/publish.ts b/ui/src/frontend/publish.ts
index 7632e539c..0cc560439 100644
--- a/ui/src/frontend/publish.ts
+++ b/ui/src/frontend/publish.ts
@@ -54,6 +54,11 @@ export function publishOverviewData(
globals.rafScheduler.scheduleRedraw();
}
+export function clearOverviewData() {
+ globals.overviewStore.clear();
+ globals.rafScheduler.scheduleRedraw();
+}
+
export function publishTrackData(args: {id: string, data: {}}) {
globals.setTrackData(args.id, args.data);
if ([LogExistsKey, LogBoundsKey, LogEntriesKey].includes(args.id)) {
diff --git a/ui/src/frontend/query_table.ts b/ui/src/frontend/query_table.ts
index c27ecc29a..a58d1d6bf 100644
--- a/ui/src/frontend/query_table.ts
+++ b/ui/src/frontend/query_table.ts
@@ -14,13 +14,15 @@
import m from 'mithril';
+import {BigintMath} from '../base/bigint_math';
import {Actions} from '../common/actions';
import {QueryResponse} from '../common/queries';
import {ColumnType, Row} from '../common/query_result';
-import {fromNs} from '../common/time';
-import {Anchor} from './anchor';
+import {TPTime, tpTimeFromNanos} from '../common/time';
+import {TPDuration} from '../common/time';
+import {Anchor} from './anchor';
import {copyToClipboard, queryResponseToClipboard} from './clipboard';
import {downloadData} from './download_utils';
import {globals} from './globals';
@@ -38,6 +40,16 @@ interface QueryTableRowAttrs {
}
// Convert column value to number if it's a bigint or a number, otherwise throw
+function colToTimestamp(colValue: ColumnType): TPTime {
+ if (typeof colValue === 'bigint') {
+ return colValue;
+ } else if (typeof colValue === 'number') {
+ return tpTimeFromNanos(colValue);
+ } else {
+ throw Error('Value is not a number or a bigint');
+ }
+}
+
function colToNumber(colValue: ColumnType): number {
if (typeof colValue === 'bigint') {
return Number(colValue);
@@ -48,6 +60,15 @@ function colToNumber(colValue: ColumnType): number {
}
}
+function colToDuration(colValue: ColumnType): TPDuration {
+ return colToTimestamp(colValue);
+}
+
+function clampDurationLower(
+ dur: TPDuration, lowerClamp: TPDuration): TPDuration {
+ return BigintMath.max(dur, lowerClamp);
+}
+
class QueryTableRow implements m.ClassComponent<QueryTableRowAttrs> {
static columnsContainsSliceLocation(columns: string[]) {
const requiredColumns = ['ts', 'dur', 'track_id'];
@@ -65,15 +86,14 @@ class QueryTableRow implements m.ClassComponent<QueryTableRowAttrs> {
// the slice.
event.stopPropagation();
- const sliceStart = fromNs(colToNumber(row.ts));
+ const sliceStart = colToTimestamp(row.ts);
// row.dur can be negative. Clamp to 1ns.
- const sliceDur = fromNs(Math.max(colToNumber(row.dur), 1));
+ const sliceDur = clampDurationLower(colToDuration(row.dur), 1n);
const sliceEnd = sliceStart + sliceDur;
- const trackId: number = colToNumber(row.track_id);
+ const trackId = colToNumber(row.track_id);
const uiTrackId = globals.state.uiTrackIdByTraceTrackId[trackId];
if (uiTrackId === undefined) return;
verticalScrollToTrack(uiTrackId, true);
- // TODO(stevegolton) Soon this function will only accept Bigints
focusHorizontalRange(sliceStart, sliceEnd);
let sliceId: number|undefined;
diff --git a/ui/src/frontend/scroll_helper.ts b/ui/src/frontend/scroll_helper.ts
index 18a9a7838..f177a6524 100644
--- a/ui/src/frontend/scroll_helper.ts
+++ b/ui/src/frontend/scroll_helper.ts
@@ -13,23 +13,28 @@
// limitations under the License.
import {Actions} from '../common/actions';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../common/high_precision_time';
import {getContainingTrackId} from '../common/state';
-import {fromNs, TimeSpan, toNs} from '../common/time';
+import {TPTime} from '../common/time';
import {globals} from './globals';
-const INCOMPLETE_SLICE_TIME_S = 0.00003;
// Given a timestamp, if |ts| is not currently in view move the view to
// center |ts|, keeping the same zoom level.
-export function horizontalScrollToTs(ts: number) {
- const startNs = toNs(globals.frontendLocalState.visibleWindowTime.start);
- const endNs = toNs(globals.frontendLocalState.visibleWindowTime.end);
- const currentViewNs = endNs - startNs;
- if (ts < startNs || ts > endNs) {
+// TODO(stevegolton): Remove me!
+export function horizontalScrollToTs(ts: TPTime) {
+ console.log('horizontalScrollToTs', ts);
+ const time = HighPrecisionTime.fromTPTime(ts);
+ const {start, end, duration} = globals.frontendLocalState.visibleWindowTime;
+ const halfDuration = duration.nanos / 2;
+ if (time.isLessThan(start) || time.isGreaterThan(end)) {
// TODO(hjd): This is an ugly jump, we should do a smooth pan instead.
- globals.frontendLocalState.updateVisibleTime(new TimeSpan(
- fromNs(ts - currentViewNs / 2), fromNs(ts + currentViewNs / 2)));
+ globals.frontendLocalState.updateVisibleTime(new HighPrecisionTimeSpan(
+ time.subtractNanos(halfDuration), time.addNanos(halfDuration)));
}
}
@@ -46,16 +51,11 @@ export function horizontalScrollToTs(ts: number) {
// to cover 1/5 of the viewport.
// - Otherwise, preserve the zoom range.
export function focusHorizontalRange(
- startTs: number, endTs: number, viewPercentage?: number) {
- const visibleDur = globals.frontendLocalState.visibleWindowTime.end -
- globals.frontendLocalState.visibleWindowTime.start;
- let selectDur = endTs - startTs;
- // TODO(altimin): We go from `ts` and `dur` to `startTs` and `endTs` and back
- // to `dur`. We should fix that.
- if (toNs(selectDur) === -1) { // Unfinished slice
- selectDur = INCOMPLETE_SLICE_TIME_S;
- endTs = startTs;
- }
+ start: TPTime, end: TPTime, viewPercentage?: number) {
+ console.log('focusHorizontalRange', start, end);
+ const visible = globals.frontendLocalState.visibleWindowTime;
+ const trace = globals.stateTraceTime();
+ const select = HighPrecisionTimeSpan.fromTpTime(start, end);
if (viewPercentage !== undefined) {
if (viewPercentage <= 0.0 || viewPercentage > 1.0) {
@@ -67,51 +67,43 @@ export function focusHorizontalRange(
viewPercentage = 0.5;
}
const paddingPercentage = 1.0 - viewPercentage;
- const paddingTime = selectDur * paddingPercentage;
- const halfPaddingTime = paddingTime / 2;
- globals.frontendLocalState.updateVisibleTime(
- new TimeSpan(startTs - halfPaddingTime, endTs + halfPaddingTime));
+ const paddingTime = select.duration.multiply(paddingPercentage);
+ const halfPaddingTime = paddingTime.divide(2);
+ globals.frontendLocalState.updateVisibleTime(select.pad(halfPaddingTime));
return;
}
-
// If the range is too large to fit on the current zoom level, resize.
- if (selectDur > 0.5 * visibleDur) {
- globals.frontendLocalState.updateVisibleTime(
- new TimeSpan(startTs - (selectDur * 2), endTs + (selectDur * 2)));
+ if (select.duration.isGreaterThan(visible.duration.multiply(0.5))) {
+ const paddedRange = select.pad(select.duration.multiply(2));
+ globals.frontendLocalState.updateVisibleTime(paddedRange);
return;
}
- const midpointTs = (endTs + startTs) / 2;
// Calculate the new visible window preserving the zoom level.
- let newStartTs = midpointTs - visibleDur / 2;
- let newEndTs = midpointTs + visibleDur / 2;
+ let newStart = select.midpoint.subtract(visible.duration.divide(2));
+ let newEnd = select.midpoint.add(visible.duration.divide(2));
// Adjust the new visible window if it intersects with the trace boundaries.
// It's needed to make the "update the zoom level if visible window doesn't
// change" logic reliable.
- if (newEndTs > globals.state.traceTime.endSec) {
- newStartTs = globals.state.traceTime.endSec - visibleDur;
- newEndTs = globals.state.traceTime.endSec;
+ if (newEnd.isGreaterThan(trace.end)) {
+ newStart = trace.end.subtract(visible.duration);
+ newEnd = trace.end;
}
- if (newStartTs < globals.state.traceTime.startSec) {
- newStartTs = globals.state.traceTime.startSec;
- newEndTs = globals.state.traceTime.startSec + visibleDur;
+ if (newStart.isLessThan(trace.start)) {
+ newStart = trace.start;
+ newEnd = trace.start.add(visible.duration);
}
- const newStartNs = toNs(newStartTs);
- const newEndNs = toNs(newEndTs);
-
- const viewStartNs = toNs(globals.frontendLocalState.visibleWindowTime.start);
- const viewEndNs = toNs(globals.frontendLocalState.visibleWindowTime.end);
+ const view = new HighPrecisionTimeSpan(newStart, newEnd);
// If preserving the zoom doesn't change the visible window, update the zoom
// level.
- if (newStartNs === viewStartNs && newEndNs === viewEndNs) {
- globals.frontendLocalState.updateVisibleTime(
- new TimeSpan(startTs - (selectDur * 2), endTs + (selectDur * 2)));
- return;
+ if (view.start.equals(visible.start) && view.end.equals(visible.end)) {
+ const padded = select.pad(select.duration.multiply(2));
+ globals.frontendLocalState.updateVisibleTime(padded);
+ } else {
+ globals.frontendLocalState.updateVisibleTime(view);
}
- globals.frontendLocalState.updateVisibleTime(
- new TimeSpan(newStartTs, newEndTs));
}
// Given a track id, find a track with that id and scroll it into view. If the
@@ -155,7 +147,7 @@ export function verticalScrollToTrack(
// Scroll vertically and horizontally to reach track (|trackId|) at |ts|.
export function scrollToTrackAndTs(
- trackId: string|number|undefined, ts: number, openGroup = false) {
+ trackId: string|number|undefined, ts: TPTime, openGroup = false) {
if (trackId !== undefined) {
verticalScrollToTrack(trackId, openGroup);
}
diff --git a/ui/src/frontend/search_handler.ts b/ui/src/frontend/search_handler.ts
index 1622a7efe..f99561713 100644
--- a/ui/src/frontend/search_handler.ts
+++ b/ui/src/frontend/search_handler.ts
@@ -14,8 +14,6 @@
import {searchSegment} from '../base/binary_search';
import {Actions} from '../common/actions';
-import {toNs} from '../common/time';
-
import {globals} from './globals';
function setToPrevious(current: number) {
@@ -34,8 +32,9 @@ function setToNext(current: number) {
export function executeSearch(reverse = false) {
const index = globals.state.searchIndex;
- const startNs = toNs(globals.frontendLocalState.visibleWindowTime.start);
- const endNs = toNs(globals.frontendLocalState.visibleWindowTime.end);
+ const vizWindow = globals.frontendLocalState.visibleWindowTime;
+ const startNs = vizWindow.start.nanos;
+ const endNs = vizWindow.end.nanos;
const currentTs = globals.currentSearchResults.tsStarts[index];
// If the value of |globals.currentSearchResults.totalResults| is 0,
diff --git a/ui/src/frontend/slice.ts b/ui/src/frontend/slice.ts
index 5b660ef0e..7587a27e9 100644
--- a/ui/src/frontend/slice.ts
+++ b/ui/src/frontend/slice.ts
@@ -13,13 +13,14 @@
// limitations under the License.
import {Color} from '../common/colorizer';
+import {TPDuration, TPTime} from '../common/time';
export interface Slice {
// These properties are updated only once per query result when the Slice
// object is created and don't change afterwards.
readonly id: number;
- readonly startS: number;
- readonly durationS: number;
+ readonly start: TPTime;
+ readonly duration: TPDuration;
readonly depth: number;
readonly flags: number;
diff --git a/ui/src/frontend/slice_details_panel.ts b/ui/src/frontend/slice_details_panel.ts
index 9b018dd9b..13e3dd572 100644
--- a/ui/src/frontend/slice_details_panel.ts
+++ b/ui/src/frontend/slice_details_panel.ts
@@ -16,7 +16,7 @@ import m from 'mithril';
import {Actions} from '../common/actions';
import {translateState} from '../common/thread_state';
-import {timeToCode, toNs} from '../common/time';
+import {tpTimeToCode} from '../common/time';
import {globals, SliceDetails, ThreadDesc} from './globals';
import {scrollToTrackAndTs} from './scroll_helper';
import {SlicePanel} from './slice_panel';
@@ -60,9 +60,8 @@ export class SliceDetailsPanel extends SlicePanel {
if (!threadInfo) {
return null;
}
- const timestamp = timeToCode(
- sliceInfo.wakeupTs! - globals.state.traceTime.startSec,
- );
+ const timestamp =
+ tpTimeToCode(sliceInfo.wakeupTs! - globals.state.traceTime.start);
return m(
'.slice-details-wakeup-text',
m('', `Wakeup @ ${timestamp} on CPU ${sliceInfo.wakerCpu} by`),
@@ -76,9 +75,7 @@ export class SliceDetailsPanel extends SlicePanel {
return null;
}
- const latency = timeToCode(
- sliceInfo.ts - (sliceInfo.wakeupTs - globals.state.traceTime.startSec),
- );
+ const latency = tpTimeToCode(sliceInfo.ts - sliceInfo.wakeupTs);
return m(
'.slice-details-latency-text',
m('', `Scheduling latency: ${latency}`),
@@ -111,7 +108,10 @@ export class SliceDetailsPanel extends SlicePanel {
{onclick: () => this.goToThread(), title: 'Go to thread'},
'call_made'))),
m('tr', m('th', `Cmdline`), m('td', threadInfo.cmdline)),
- m('tr', m('th', `Start time`), m('td', `${timeToCode(sliceInfo.ts)}`)),
+ m('tr',
+ m('th', `Start time`),
+ m('td',
+ `${tpTimeToCode(sliceInfo.ts - globals.state.traceTime.start)}`)),
m('tr',
m('th', `Duration`),
m('td', this.computeDuration(sliceInfo.ts, sliceInfo.dur))),
@@ -172,8 +172,7 @@ export class SliceDetailsPanel extends SlicePanel {
trackId: trackId.toString(),
}));
- scrollToTrackAndTs(
- trackId, toNs(sliceInfo.ts + globals.state.traceTime.startSec), true);
+ scrollToTrackAndTs(trackId, sliceInfo.ts, true);
}
}
diff --git a/ui/src/frontend/slice_panel.ts b/ui/src/frontend/slice_panel.ts
index 17b4aeb31..9d6f542e1 100644
--- a/ui/src/frontend/slice_panel.ts
+++ b/ui/src/frontend/slice_panel.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {timeToCode, toNs} from '../common/time';
+import {TPDuration, TPTime, tpTimeToCode} from '../common/time';
import {globals, SliceDetails} from './globals';
import {Panel} from './panel';
@@ -34,10 +34,9 @@ function getDisplayName(name: string|undefined, id: number|undefined): string|
}
export abstract class SlicePanel extends Panel {
- protected computeDuration(ts: number, dur: number): string {
- return toNs(dur) === -1 ?
- `${globals.state.traceTime.endSec - ts} (Did not end)` :
- timeToCode(dur);
+ protected computeDuration(ts: TPTime, dur: TPDuration): string {
+ return dur === -1n ? `${globals.state.traceTime.end - ts} (Did not end)` :
+ tpTimeToCode(dur);
}
protected getProcessThreadDetails(sliceInfo: SliceDetails) {
diff --git a/ui/src/frontend/sql_types.ts b/ui/src/frontend/sql_types.ts
index f7135faaf..b7e2df20c 100644
--- a/ui/src/frontend/sql_types.ts
+++ b/ui/src/frontend/sql_types.ts
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {ColumnType} from 'src/common/query_result';
-import {fromNs, toNs} from '../common/time';
+import {TPTime} from '../common/time';
+
import {globals} from './globals';
// Type-safe aliases for various flavours of ints Trace Processor exposes
@@ -26,37 +26,19 @@ import {globals} from './globals';
// Timestamp (in nanoseconds) in the same time domain as Trace Processor is
// exposing.
-export type TPTimestamp = bigint&{
+export type TPTimestamp = TPTime&{
__type: 'TPTimestamp'
}
-// Create a timestamp from a bigint in nanos.
-// Use this when we know the type is a bigint.
-export function timestampFromNanos(nanos: bigint) {
- return nanos as TPTimestamp;
-}
-
-// Create a timestamp from an arbitrary SQL value.
-// Throws if the value cannot be reasonably converted to a timestamp.
-// Assumes the input will be in units of nanoseconds.
-export function timestampFromSqlNanos(nanos: ColumnType): TPTimestamp {
- if (typeof nanos === 'bigint') {
- return nanos as TPTimestamp;
- } else if (typeof nanos === 'number') {
- // Note - this will throw if the number is something which cannot be
- // represented by an integer - i.e. decimals, infinity, or NaN.
- return BigInt(nanos) as TPTimestamp;
- } else {
- throw Error('Refusing to create TPTimestamp from unrelated type');
- }
+export function asTPTimestamp(v: bigint): TPTimestamp;
+export function asTPTimestamp(v?: bigint): TPTimestamp|undefined;
+export function asTPTimestamp(v?: bigint): TPTimestamp|undefined {
+ return v as (TPTimestamp | undefined);
}
// TODO: unify this with common/time.ts.
-// TODO(stevegolton): Return a bigint, or a new TPDuration object rather than
-// convert to number which could lose precision.
-export function toTraceTime(ts: TPTimestamp): number {
- const traceStartNs = toNs(globals.state.traceTime.startSec);
- return fromNs(Number(ts - BigInt(traceStartNs)));
+export function toTraceTime(ts: TPTimestamp): TPTime {
+ return ts - globals.state.traceTime.start;
}
// Unique id for a process, id into |process| table.
diff --git a/ui/src/frontend/thread_state.ts b/ui/src/frontend/thread_state.ts
index c7031f229..0bc40827c 100644
--- a/ui/src/frontend/thread_state.ts
+++ b/ui/src/frontend/thread_state.ts
@@ -16,7 +16,11 @@ import {Actions} from '../common/actions';
import {EngineProxy} from '../common/engine';
import {LONG, NUM, NUM_NULL, STR_NULL} from '../common/query_result';
import {translateState} from '../common/thread_state';
-import {fromNs, timeToCode} from '../common/time';
+import {
+ TPDuration,
+ TPTime,
+ tpTimeToCode,
+} from '../common/time';
import {copyToClipboard} from './clipboard';
import {globals} from './globals';
@@ -26,9 +30,6 @@ import {
asUtid,
SchedSqlId,
ThreadStateSqlId,
- timestampFromNanos,
- toTraceTime,
- TPTimestamp,
} from './sql_types';
import {
constraintsToQueryFragment,
@@ -50,10 +51,10 @@ export interface ThreadState {
threadStateSqlId: ThreadStateSqlId;
// Id of the corresponding entry in the |sched| table.
schedSqlId?: SchedSqlId;
- // Timestamp of the beginning of this thread state in nanoseconds.
- ts: TPTimestamp;
+ // Timestamp of the the beginning of this thread state in nanoseconds.
+ ts: TPTime;
// Duration of this thread state in nanoseconds.
- dur: number;
+ dur: TPDuration;
// CPU id if this thread state corresponds to a thread running on the CPU.
cpu?: number;
// Human-readable name of this thread state.
@@ -90,7 +91,7 @@ export async function getThreadStateFromConstraints(
threadStateSqlId: NUM,
schedSqlId: NUM_NULL,
ts: LONG,
- dur: NUM,
+ dur: LONG,
cpu: NUM_NULL,
state: STR_NULL,
blockedFunction: STR_NULL,
@@ -110,7 +111,7 @@ export async function getThreadStateFromConstraints(
result.push({
threadStateSqlId: it.threadStateSqlId as ThreadStateSqlId,
schedSqlId: fromNumNull(it.schedSqlId) as (SchedSqlId | undefined),
- ts: timestampFromNanos(it.ts),
+ ts: it.ts,
dur: it.dur,
cpu: fromNumNull(it.cpu),
state: translateState(it.state || undefined, ioWait),
@@ -137,7 +138,7 @@ export async function getThreadState(
return result[0];
}
-export function goToSchedSlice(cpu: number, id: SchedSqlId, ts: TPTimestamp) {
+export function goToSchedSlice(cpu: number, id: SchedSqlId, ts: TPTime) {
let trackId: string|undefined;
for (const track of Object.values(globals.state.tracks)) {
if (track.kind === 'CpuSliceTrack' &&
@@ -149,15 +150,12 @@ export function goToSchedSlice(cpu: number, id: SchedSqlId, ts: TPTimestamp) {
return;
}
globals.makeSelection(Actions.selectSlice({id, trackId}));
- // TODO(stevegolton): scrollToTrackAndTs() should take a TPTimestamp
- scrollToTrackAndTs(trackId, Number(ts));
+ scrollToTrackAndTs(trackId, ts);
}
function stateToValue(
- state: string,
- cpu: number|undefined,
- id: SchedSqlId|undefined,
- ts: TPTimestamp): Value|null {
+ state: string, cpu: number|undefined, id: SchedSqlId|undefined, ts: TPTime):
+ Value|null {
if (!state) {
return null;
}
@@ -177,8 +175,9 @@ function stateToValue(
export function threadStateToDict(state: ThreadState): Dict {
const result: {[name: string]: Value|null} = {};
- result['Start time'] = value(timeToCode(toTraceTime(state.ts)));
- result['Duration'] = value(timeToCode(fromNs(state.dur)));
+ result['Start time'] =
+ value(tpTimeToCode(state.ts - globals.state.traceTime.start));
+ result['Duration'] = value(tpTimeToCode(state.dur));
result['State'] =
stateToValue(state.state, state.cpu, state.schedSqlId, state.ts);
result['Blocked function'] = maybeValue(state.blockedFunction);
diff --git a/ui/src/frontend/tickmark_panel.ts b/ui/src/frontend/tickmark_panel.ts
index 00612eb7a..f1579b9b8 100644
--- a/ui/src/frontend/tickmark_panel.ts
+++ b/ui/src/frontend/tickmark_panel.ts
@@ -19,6 +19,7 @@ import {fromNs} from '../common/time';
import {TRACK_SHELL_WIDTH} from './css_constants';
import {globals} from './globals';
import {
+ getMaxMajorTicks,
TickGenerator,
TickType,
timeScaleForVisibleWindow,
@@ -32,14 +33,26 @@ export class TickmarkPanel extends Panel {
}
renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {visibleWindowTime, visibleTimeScale} = globals.frontendLocalState;
ctx.fillStyle = '#999';
ctx.fillRect(TRACK_SHELL_WIDTH - 2, 0, 2, size.height);
- const relScale = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
- if (relScale.timeSpan.duration > 0 && relScale.widthPx > 0) {
- for (const {type, position} of new TickGenerator(relScale)) {
- if (type === TickType.MAJOR) ctx.fillRect(position, 0, 1, size.height);
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(TRACK_SHELL_WIDTH, 0, size.width - TRACK_SHELL_WIDTH, size.height);
+ ctx.clip();
+
+ const span = globals.frontendLocalState.visibleWindow.timestampSpan;
+ if (size.width > TRACK_SHELL_WIDTH && span.duration > 0n) {
+ const maxMajorTicks = getMaxMajorTicks(size.width - TRACK_SHELL_WIDTH);
+ const map = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
+ for (const {type, time} of new TickGenerator(
+ span, maxMajorTicks, globals.state.traceTime.start)) {
+ const px = Math.floor(map.tpTimeToPx(time));
+ if (type === TickType.MAJOR) {
+ ctx.fillRect(px, 0, 1, size.height);
+ }
}
}
@@ -47,12 +60,13 @@ export class TickmarkPanel extends Panel {
for (let i = 0; i < data.tsStarts.length; i++) {
const tStart = data.tsStarts[i];
const tEnd = data.tsEnds[i];
- if (tEnd <= visibleWindowTime.start || tStart >= visibleWindowTime.end) {
+ if (tEnd <= visibleWindowTime.start.seconds ||
+ tStart >= visibleWindowTime.end.seconds) {
continue;
}
const rectStart =
- Math.max(timeScale.timeToPx(tStart), 0) + TRACK_SHELL_WIDTH;
- const rectEnd = timeScale.timeToPx(tEnd) + TRACK_SHELL_WIDTH;
+ Math.max(visibleTimeScale.secondsToPx(tStart), 0) + TRACK_SHELL_WIDTH;
+ const rectEnd = visibleTimeScale.secondsToPx(tEnd) + TRACK_SHELL_WIDTH;
ctx.fillStyle = '#ffe263';
ctx.fillRect(
Math.floor(rectStart),
@@ -61,16 +75,21 @@ export class TickmarkPanel extends Panel {
size.height);
}
const index = globals.state.searchIndex;
- const startSec = fromNs(globals.currentSearchResults.tsStarts[index]);
- const triangleStart =
- Math.max(timeScale.timeToPx(startSec), 0) + TRACK_SHELL_WIDTH;
- ctx.fillStyle = '#000';
- ctx.beginPath();
- ctx.moveTo(triangleStart, size.height);
- ctx.lineTo(triangleStart - 3, 0);
- ctx.lineTo(triangleStart + 3, 0);
- ctx.lineTo(triangleStart, size.height);
- ctx.fill();
- ctx.closePath();
+ if (index !== -1) {
+ const startSec = fromNs(globals.currentSearchResults.tsStarts[index]);
+ const triangleStart =
+ Math.max(visibleTimeScale.secondsToPx(startSec), 0) +
+ TRACK_SHELL_WIDTH;
+ ctx.fillStyle = '#000';
+ ctx.beginPath();
+ ctx.moveTo(triangleStart, size.height);
+ ctx.lineTo(triangleStart - 3, 0);
+ ctx.lineTo(triangleStart + 3, 0);
+ ctx.lineTo(triangleStart, size.height);
+ ctx.fill();
+ ctx.closePath();
+ }
+
+ ctx.restore();
}
}
diff --git a/ui/src/frontend/time_axis_panel.ts b/ui/src/frontend/time_axis_panel.ts
index 3f6dc6499..4819d54a9 100644
--- a/ui/src/frontend/time_axis_panel.ts
+++ b/ui/src/frontend/time_axis_panel.ts
@@ -14,11 +14,15 @@
import m from 'mithril';
-import {timeToString} from '../common/time';
+import {
+ tpTimeToSeconds,
+ tpTimeToString,
+} from '../common/time';
import {TRACK_SHELL_WIDTH} from './css_constants';
import {globals} from './globals';
import {
+ getMaxMajorTicks,
TickGenerator,
TickType,
timeScaleForVisibleWindow,
@@ -35,21 +39,33 @@ export class TimeAxisPanel extends Panel {
ctx.font = '10px Roboto Condensed';
ctx.textAlign = 'left';
- const startTime = timeToString(globals.state.traceTime.startSec);
+ const startTime = tpTimeToString(globals.state.traceTime.start);
ctx.fillText(startTime + ' +', 6, 11);
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(TRACK_SHELL_WIDTH, 0, size.width - TRACK_SHELL_WIDTH, size.height);
+ ctx.clip();
+
// Draw time axis.
- const timeScale = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
- if (timeScale.timeSpan.duration > 0 && timeScale.widthPx > 0) {
- const tickGen = new TickGenerator(timeScale);
- for (const {type, time, position} of tickGen) {
+ const span = globals.frontendLocalState.visibleWindow.timestampSpan;
+ if (size.width > TRACK_SHELL_WIDTH && span.duration > 0n) {
+ const maxMajorTicks = getMaxMajorTicks(size.width - TRACK_SHELL_WIDTH);
+ const map = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
+ const tickGen =
+ new TickGenerator(span, maxMajorTicks, globals.state.traceTime.start);
+ for (const {type, time} of tickGen) {
+ const position = Math.floor(map.tpTimeToPx(time));
+ const sec = tpTimeToSeconds(time - globals.state.traceTime.start);
if (type === TickType.MAJOR) {
ctx.fillRect(position, 0, 1, size.height);
- ctx.fillText(time.toFixed(tickGen.digits) + ' s', position + 5, 10);
+ ctx.fillText(sec.toFixed(tickGen.digits) + ' s', position + 5, 10);
}
}
}
+ ctx.restore();
+
ctx.fillRect(TRACK_SHELL_WIDTH - 2, 0, 2, size.height);
}
}
diff --git a/ui/src/frontend/time_scale.ts b/ui/src/frontend/time_scale.ts
index 6f0307af8..7804348c8 100644
--- a/ui/src/frontend/time_scale.ts
+++ b/ui/src/frontend/time_scale.ts
@@ -12,95 +12,92 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {assertFalse, assertTrue} from '../base/logging';
-import {TimeSpan} from '../common/time';
+import {assertTrue} from '../base/logging';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../common/high_precision_time';
+import {Span} from '../common/time';
+import {
+ TPDuration,
+ TPTime,
+} from '../common/time';
-const MAX_ZOOM_SPAN_SEC = 1e-8; // 10 ns.
-
-/**
- * Defines a mapping between number and seconds for the entire application.
- * Linearly scales time values from boundsMs to pixel values in boundsPx and
- * back.
- */
export class TimeScale {
- private timeBounds: TimeSpan;
- private _startPx: number;
- private _endPx: number;
- private secPerPx = 0;
-
- constructor(timeBounds: TimeSpan, boundsPx: [number, number]) {
- this.timeBounds = timeBounds;
- this._startPx = boundsPx[0];
- this._endPx = boundsPx[1];
- this.updateSlope();
- }
-
- private updateSlope() {
- this.secPerPx = this.timeBounds.duration / (this._endPx - this._startPx);
+ private _start: HighPrecisionTime;
+ private _durationNanos: number;
+ readonly pxSpan: PxSpan;
+ private _nanosPerPx = 0;
+ private _startSec: number;
+
+ constructor(start: HighPrecisionTime, durationNanos: number, pxSpan: PxSpan) {
+ // TODO(stevegolton): Ensure duration & pxSpan > 0.
+ // assertTrue(pxSpan.start < pxSpan.end, 'Px start >= end');
+ // assertTrue(durationNanos < 0, 'Duration <= 0');
+ this.pxSpan = pxSpan;
+ this._start = start;
+ this._durationNanos = durationNanos;
+ if (durationNanos <= 0 || pxSpan.delta <= 0) {
+ this._nanosPerPx = 1;
+ } else {
+ this._nanosPerPx = durationNanos / (pxSpan.delta);
+ }
+ this._startSec = this._start.seconds;
}
- deltaTimeToPx(time: number): number {
- return Math.round(time / this.secPerPx);
+ get timeSpan(): Span<HighPrecisionTime> {
+ const end = this._start.addNanos(this._durationNanos);
+ return new HighPrecisionTimeSpan(this._start, end);
}
- timeToPx(time: number): number {
- return this._startPx + (time - this.timeBounds.start) / this.secPerPx;
+ tpTimeToPx(ts: TPTime): number {
+ // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath.
+ const timeOffsetNanos = Number(ts - this._start.base) - this._start.offset;
+ return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx;
}
- pxToTime(px: number): number {
- return this.timeBounds.start + (px - this._startPx) * this.secPerPx;
+ secondsToPx(seconds: number): number {
+ const timeOffset = (seconds - this._startSec) * 1e9;
+ return this.pxSpan.start + timeOffset / this._nanosPerPx;
}
- deltaPxToDuration(px: number): number {
- return px * this.secPerPx;
+ hpTimeToPx(time: HighPrecisionTime): number {
+ const timeOffsetNanos = time.subtract(this._start).nanos;
+ return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx;
}
- setTimeBounds(timeBounds: TimeSpan) {
- this.timeBounds = timeBounds;
- this.updateSlope();
+ // Convert pixels to a high precision time object, which can be futher
+ // converted to other time formats.
+ pxToHpTime(px: number): HighPrecisionTime {
+ const offsetNanos = (px - this.pxSpan.start) * this._nanosPerPx;
+ return this._start.addNanos(offsetNanos);
}
- setLimitsPx(pxStart: number, pxEnd: number) {
- assertFalse(pxStart === pxEnd);
- assertTrue(pxStart >= 0 && pxEnd >= 0);
- this._startPx = pxStart;
- this._endPx = pxEnd;
- this.updateSlope();
+ durationToPx(dur: TPDuration): number {
+ // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath.
+ return Number(dur) / this._nanosPerPx;
}
- timeInBounds(time: number): boolean {
- return this.timeBounds.isInBounds(time);
+ pxDeltaToDuration(pxDelta: number): HighPrecisionTime {
+ const time = pxDelta * this._nanosPerPx;
+ return HighPrecisionTime.fromNanos(time);
}
+}
- get startPx(): number {
- return this._startPx;
+export class PxSpan {
+ constructor(private _start: number, private _end: number) {
+ assertTrue(_start <= _end, 'PxSpan start > end');
}
- get endPx(): number {
- return this._endPx;
+ get start(): number {
+ return this._start;
}
- get widthPx(): number {
- return this._endPx - this._startPx;
+ get end(): number {
+ return this._end;
}
- get timeSpan(): TimeSpan {
- return this.timeBounds;
+ get delta(): number {
+ return this._end - this._start;
}
}
-
-export function computeZoom(
- scale: TimeScale, span: TimeSpan, zoomFactor: number, zoomPx: number):
- TimeSpan {
- const startPx = scale.startPx;
- const endPx = scale.endPx;
- const deltaPx = endPx - startPx;
- const deltaTime = span.end - span.start;
- const newDeltaTime = Math.max(deltaTime * zoomFactor, MAX_ZOOM_SPAN_SEC);
- const clampedZoomPx = Math.max(startPx, Math.min(endPx, zoomPx));
- const zoomTime = scale.pxToTime(clampedZoomPx);
- const r = (clampedZoomPx - startPx) / deltaPx;
- const newStartTime = zoomTime - newDeltaTime * r;
- const newEndTime = newStartTime + newDeltaTime;
- return new TimeSpan(newStartTime, newEndTime);
-}
diff --git a/ui/src/frontend/time_scale_unittest.ts b/ui/src/frontend/time_scale_unittest.ts
index 7a1be031d..f7046ded3 100644
--- a/ui/src/frontend/time_scale_unittest.ts
+++ b/ui/src/frontend/time_scale_unittest.ts
@@ -12,66 +12,62 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {TimeSpan} from '../common/time';
+import {HighPrecisionTime} from '../common/high_precision_time';
-import {computeZoom, TimeScale} from './time_scale';
+import {PxSpan, TimeScale} from './time_scale';
-test('time scale to work', () => {
- const scale = new TimeScale(new TimeSpan(0, 100), [200, 1000]);
+describe('TimeScale', () => {
+ const ts =
+ new TimeScale(new HighPrecisionTime(40n), 100, new PxSpan(200, 1000));
- expect(scale.timeToPx(0)).toEqual(200);
- expect(scale.timeToPx(100)).toEqual(1000);
- expect(scale.timeToPx(50)).toEqual(600);
+ it('converts timescales to pixels', () => {
+ expect(ts.tpTimeToPx(40n)).toEqual(200);
+ expect(ts.tpTimeToPx(140n)).toEqual(1000);
+ expect(ts.tpTimeToPx(90n)).toEqual(600);
- expect(scale.pxToTime(200)).toEqual(0);
- expect(scale.pxToTime(1000)).toEqual(100);
- expect(scale.pxToTime(600)).toEqual(50);
+ expect(ts.tpTimeToPx(240n)).toEqual(1800);
+ expect(ts.tpTimeToPx(-60n)).toEqual(-600);
+ });
- expect(scale.deltaPxToDuration(400)).toEqual(50);
+ it('converts pixels to HPTime objects', () => {
+ let result = ts.pxToHpTime(200);
+ expect(result.base).toEqual(40n);
+ expect(result.offset).toBeCloseTo(0);
- expect(scale.timeInBounds(50)).toEqual(true);
- expect(scale.timeInBounds(0)).toEqual(true);
- expect(scale.timeInBounds(100)).toEqual(true);
- expect(scale.timeInBounds(-1)).toEqual(false);
- expect(scale.timeInBounds(101)).toEqual(false);
-});
+ result = ts.pxToHpTime(1000);
+ expect(result.base).toEqual(140n);
+ expect(result.offset).toBeCloseTo(0);
+ result = ts.pxToHpTime(600);
+ expect(result.base).toEqual(90n);
+ expect(result.offset).toBeCloseTo(0);
-test('time scale to be updatable', () => {
- const scale = new TimeScale(new TimeSpan(0, 100), [100, 1000]);
+ result = ts.pxToHpTime(1800);
+ expect(result.base).toEqual(240n);
+ expect(result.offset).toBeCloseTo(0);
- expect(scale.timeToPx(0)).toEqual(100);
+ result = ts.pxToHpTime(-600);
+ expect(result.base).toEqual(-60n);
+ expect(result.offset).toBeCloseTo(0);
+ });
- scale.setLimitsPx(200, 1000);
- expect(scale.timeToPx(0)).toEqual(200);
- expect(scale.timeToPx(100)).toEqual(1000);
+ it('converts durations to pixels', () => {
+ expect(ts.durationToPx(0n)).toEqual(0);
+ expect(ts.durationToPx(1n)).toEqual(8);
+ expect(ts.durationToPx(1000n)).toEqual(8000);
+ });
- scale.setTimeBounds(new TimeSpan(0, 200));
- expect(scale.timeToPx(0)).toEqual(200);
- expect(scale.timeToPx(100)).toEqual(600);
- expect(scale.timeToPx(200)).toEqual(1000);
-});
+ it('converts pxDeltaToDurations to HPTime durations', () => {
+ let result = ts.pxDeltaToDuration(0);
+ expect(result.base).toEqual(0n);
+ expect(result.offset).toBeCloseTo(0);
-test('it zooms', () => {
- const span = new TimeSpan(0, 20);
- const scale = new TimeScale(span, [0, 100]);
- const newSpan = computeZoom(scale, span, 0.5, 50);
- expect(newSpan.start).toEqual(5);
- expect(newSpan.end).toEqual(15);
-});
-
-test('it zooms an offset scale and span', () => {
- const span = new TimeSpan(1000, 1020);
- const scale = new TimeScale(span, [200, 300]);
- const newSpan = computeZoom(scale, span, 0.5, 250);
- expect(newSpan.start).toEqual(1005);
- expect(newSpan.end).toEqual(1015);
-});
+ result = ts.pxDeltaToDuration(1);
+ expect(result.base).toEqual(0n);
+ expect(result.offset).toBeCloseTo(0.125);
-test('it clamps zoom in', () => {
- const span = new TimeSpan(1000, 1040);
- const scale = new TimeScale(span, [200, 300]);
- const newSpan = computeZoom(scale, span, 0.0000000001, 225);
- expect((newSpan.end - newSpan.start) / 2 + newSpan.start).toBeCloseTo(1010);
- expect(newSpan.end - newSpan.start).toBeCloseTo(1e-8);
+ result = ts.pxDeltaToDuration(100);
+ expect(result.base).toEqual(12n);
+ expect(result.offset).toBeCloseTo(0.5);
+ });
});
diff --git a/ui/src/frontend/time_selection_panel.ts b/ui/src/frontend/time_selection_panel.ts
index 20f1c53f1..5711e6a31 100644
--- a/ui/src/frontend/time_selection_panel.ts
+++ b/ui/src/frontend/time_selection_panel.ts
@@ -13,9 +13,13 @@
// limitations under the License.
import m from 'mithril';
+import {BigintMath} from '../base/bigint_math';
-import {timeToString} from '../common/time';
-import {TimeSpan} from '../common/time';
+import {Span, tpTimeToString} from '../common/time';
+import {
+ TPTime,
+ TPTimeSpan,
+} from '../common/time';
import {
BACKGROUND_COLOR,
@@ -24,6 +28,7 @@ import {
} from './css_constants';
import {globals} from './globals';
import {
+ getMaxMajorTicks,
TickGenerator,
TickType,
timeScaleForVisibleWindow,
@@ -48,7 +53,7 @@ function drawHBar(
ctx.fillStyle = FOREGROUND_COLOR;
const xLeft = Math.floor(target.x);
- const xRight = Math.ceil(target.x + target.width);
+ const xRight = Math.floor(target.x + target.width);
const yMid = Math.floor(target.height / 2 + target.y);
const xWidth = xRight - xLeft;
@@ -130,11 +135,21 @@ export class TimeSelectionPanel extends Panel {
renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
ctx.fillStyle = '#999';
ctx.fillRect(TRACK_SHELL_WIDTH - 2, 0, 2, size.height);
- const scale = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
- if (scale.timeSpan.duration > 0 && scale.widthPx > 0) {
- for (const {position, type} of new TickGenerator(scale)) {
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(TRACK_SHELL_WIDTH, 0, size.width - TRACK_SHELL_WIDTH, size.height);
+ ctx.clip();
+
+ const span = globals.frontendLocalState.visibleWindow.timestampSpan;
+ if (size.width > TRACK_SHELL_WIDTH && span.duration > 0n) {
+ const maxMajorTicks = getMaxMajorTicks(size.width - TRACK_SHELL_WIDTH);
+ const map = timeScaleForVisibleWindow(TRACK_SHELL_WIDTH, size.width);
+ for (const {type, time} of new TickGenerator(
+ span, maxMajorTicks, globals.state.traceTime.start)) {
+ const px = Math.floor(map.tpTimeToPx(time));
if (type === TickType.MAJOR) {
- ctx.fillRect(position, 0, 1, size.height);
+ ctx.fillRect(px, 0, 1, size.height);
}
}
}
@@ -142,17 +157,17 @@ export class TimeSelectionPanel extends Panel {
const localArea = globals.frontendLocalState.selectedArea;
const selection = globals.state.currentSelection;
if (localArea !== undefined) {
- const start = Math.min(localArea.startSec, localArea.endSec);
- const end = Math.max(localArea.startSec, localArea.endSec);
- this.renderSpan(ctx, size, new TimeSpan(start, end));
+ const start = BigintMath.min(localArea.start, localArea.end);
+ const end = BigintMath.max(localArea.start, localArea.end);
+ this.renderSpan(ctx, size, new TPTimeSpan(start, end));
} else if (selection !== null && selection.kind === 'AREA') {
const selectedArea = globals.state.areas[selection.areaId];
- const start = Math.min(selectedArea.startSec, selectedArea.endSec);
- const end = Math.max(selectedArea.startSec, selectedArea.endSec);
- this.renderSpan(ctx, size, new TimeSpan(start, end));
+ const start = BigintMath.min(selectedArea.start, selectedArea.end);
+ const end = BigintMath.max(selectedArea.start, selectedArea.end);
+ this.renderSpan(ctx, size, new TPTimeSpan(start, end));
}
- if (globals.state.hoverCursorTimestamp !== -1) {
+ if (globals.state.hoverCursorTimestamp !== -1n) {
this.renderHover(ctx, size, globals.state.hoverCursorTimestamp);
}
@@ -162,27 +177,29 @@ export class TimeSelectionPanel extends Panel {
if (note.noteType === 'AREA' && !noteIsSelected) {
const selectedArea = globals.state.areas[note.areaId];
this.renderSpan(
- ctx,
- size,
- new TimeSpan(selectedArea.startSec, selectedArea.endSec));
+ ctx, size, new TPTimeSpan(selectedArea.start, selectedArea.end));
}
}
+
+ ctx.restore();
}
- renderHover(ctx: CanvasRenderingContext2D, size: PanelSize, ts: number) {
- const timeScale = globals.frontendLocalState.timeScale;
- const xPos = TRACK_SHELL_WIDTH + Math.floor(timeScale.timeToPx(ts));
- const offsetTime = timeToString(ts - globals.state.traceTime.startSec);
- const timeFromStart = timeToString(ts);
+ renderHover(ctx: CanvasRenderingContext2D, size: PanelSize, ts: TPTime) {
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const xPos =
+ TRACK_SHELL_WIDTH + Math.floor(visibleTimeScale.tpTimeToPx(ts));
+ const offsetTime = tpTimeToString(ts - globals.state.traceTime.start);
+ const timeFromStart = tpTimeToString(ts);
const label = `${offsetTime} (${timeFromStart})`;
drawIBar(ctx, xPos, this.bounds(size), label);
}
- renderSpan(ctx: CanvasRenderingContext2D, size: PanelSize, span: TimeSpan) {
- const timeScale = globals.frontendLocalState.timeScale;
- const xLeft = timeScale.timeToPx(span.start);
- const xRight = timeScale.timeToPx(span.end);
- const label = timeToString(span.duration);
+ renderSpan(
+ ctx: CanvasRenderingContext2D, size: PanelSize, span: Span<TPTime>) {
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const xLeft = visibleTimeScale.tpTimeToPx(span.start);
+ const xRight = visibleTimeScale.tpTimeToPx(span.end);
+ const label = tpTimeToString(span.duration);
drawHBar(
ctx,
{
diff --git a/ui/src/frontend/trace_converter.ts b/ui/src/frontend/trace_converter.ts
index ca4ced368..0f5ca69cb 100644
--- a/ui/src/frontend/trace_converter.ts
+++ b/ui/src/frontend/trace_converter.ts
@@ -17,6 +17,7 @@ import {
ConversionJobName,
ConversionJobStatus,
} from '../common/conversion_jobs';
+import {TPTime} from '../common/time';
import {download} from './clipboard';
import {maybeShowErrorDialog} from './error_dialog';
@@ -106,7 +107,7 @@ export function convertToJson(trace: Blob, truncate?: 'start'|'end') {
}
export function convertTraceToPprofAndDownload(
- trace: Blob, pid: number, ts: number) {
+ trace: Blob, pid: number, ts: TPTime) {
makeWorkerAndPost({
kind: 'ConvertTraceToPprof',
trace,
diff --git a/ui/src/frontend/track.ts b/ui/src/frontend/track.ts
index 2d5ab81d0..e82631799 100644
--- a/ui/src/frontend/track.ts
+++ b/ui/src/frontend/track.ts
@@ -130,9 +130,11 @@ export abstract class Track<Config = {}, Data extends TrackData = TrackData> {
render(ctx: CanvasRenderingContext2D) {
globals.frontendLocalState.addVisibleTrack(this.trackState.id);
if (this.data() === undefined && !this.frontendOnly) {
- const {visibleWindowTime, timeScale} = globals.frontendLocalState;
- const startPx = Math.floor(timeScale.timeToPx(visibleWindowTime.start));
- const endPx = Math.ceil(timeScale.timeToPx(visibleWindowTime.end));
+ const {visibleWindowTime, visibleTimeScale} = globals.frontendLocalState;
+ const startPx =
+ Math.floor(visibleTimeScale.hpTimeToPx(visibleWindowTime.start));
+ const endPx =
+ Math.ceil(visibleTimeScale.hpTimeToPx(visibleWindowTime.end));
checkerboard(ctx, this.getHeight(), startPx, endPx);
} else {
this.renderCanvas(ctx);
@@ -175,7 +177,7 @@ export abstract class Track<Config = {}, Data extends TrackData = TrackData> {
y -= 10;
// Ensure the box is on screen:
- const endPx = globals.frontendLocalState.timeScale.endPx;
+ const endPx = globals.frontendLocalState.visibleTimeScale.pxSpan.end;
if (x + width > endPx) {
x -= x + width - endPx;
}
diff --git a/ui/src/frontend/track_cache.ts b/ui/src/frontend/track_cache.ts
index 049cbf43c..2adbd0c7d 100644
--- a/ui/src/frontend/track_cache.ts
+++ b/ui/src/frontend/track_cache.ts
@@ -52,6 +52,7 @@ export const BUCKETS_PER_PIXEL = 2;
// In other words the normal window is a superset of the data of the
// non-normal window at a higher resolution. Normalization is used to
// avoid re-fetching data on tiny zooms/moves/resizes.
+// TODO(stevegolton): Convert to bigint timestamps.
export class CacheKey {
readonly startNs: number;
readonly endNs: number;
diff --git a/ui/src/frontend/track_group_panel.ts b/ui/src/frontend/track_group_panel.ts
index c9d109f72..dbab7f7e5 100644
--- a/ui/src/frontend/track_group_panel.ts
+++ b/ui/src/frontend/track_group_panel.ts
@@ -187,18 +187,17 @@ export class TrackGroupPanel extends Panel<Attrs> {
}
highlightIfTrackSelected(ctx: CanvasRenderingContext2D, size: PanelSize) {
- const localState = globals.frontendLocalState;
+ const {visibleTimeScale} = globals.frontendLocalState;
const selection = globals.state.currentSelection;
if (!selection || selection.kind !== 'AREA') return;
const selectedArea = globals.state.areas[selection.areaId];
+ const selectedAreaDuration = selectedArea.end - selectedArea.start;
if (selectedArea.tracks.includes(this.trackGroupId)) {
ctx.fillStyle = 'rgba(131, 152, 230, 0.3)';
ctx.fillRect(
- localState.timeScale.timeToPx(selectedArea.startSec) +
- this.shellWidth,
+ visibleTimeScale.tpTimeToPx(selectedArea.start) + this.shellWidth,
0,
- localState.timeScale.deltaTimeToPx(
- selectedArea.endSec - selectedArea.startSec),
+ visibleTimeScale.durationToPx(selectedAreaDuration),
size.height);
}
}
@@ -227,20 +226,20 @@ export class TrackGroupPanel extends Panel<Attrs> {
this.highlightIfTrackSelected(ctx, size);
- const localState = globals.frontendLocalState;
+ const {visibleTimeScale} = globals.frontendLocalState;
// Draw vertical line when hovering on the notes panel.
- if (globals.state.hoveredNoteTimestamp !== -1) {
+ if (globals.state.hoveredNoteTimestamp !== -1n) {
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
+ visibleTimeScale,
globals.state.hoveredNoteTimestamp,
size.height,
`#aaa`);
}
- if (globals.state.hoverCursorTimestamp !== -1) {
+ if (globals.state.hoverCursorTimestamp !== -1n) {
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
+ visibleTimeScale,
globals.state.hoverCursorTimestamp,
size.height,
`#344596`);
@@ -251,7 +250,7 @@ export class TrackGroupPanel extends Panel<Attrs> {
globals.sliceDetails.wakeupTs !== undefined) {
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
+ visibleTimeScale,
globals.sliceDetails.wakeupTs,
size.height,
`black`);
@@ -265,21 +264,21 @@ export class TrackGroupPanel extends Panel<Attrs> {
'rgba(' + hex.rgb(note.color.substr(1)).toString() + ', 0.65)';
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
- globals.state.areas[note.areaId].startSec,
+ visibleTimeScale,
+ globals.state.areas[note.areaId].start,
size.height,
transparentNoteColor,
1);
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
- globals.state.areas[note.areaId].endSec,
+ visibleTimeScale,
+ globals.state.areas[note.areaId].end,
size.height,
transparentNoteColor,
1);
} else if (note.noteType === 'DEFAULT') {
drawVerticalLineAtTime(
- ctx, localState.timeScale, note.timestamp, size.height, note.color);
+ ctx, visibleTimeScale, note.timestamp, size.height, note.color);
}
}
}
diff --git a/ui/src/frontend/track_panel.ts b/ui/src/frontend/track_panel.ts
index 9b3c3cc4f..278b73d01 100644
--- a/ui/src/frontend/track_panel.ts
+++ b/ui/src/frontend/track_panel.ts
@@ -31,6 +31,26 @@ import {
drawVerticalLineAtTime,
} from './vertical_line_helper';
+function getTitleSize(title: string): string|undefined {
+ const length = title.length;
+ if (length > 55) {
+ return '9px';
+ }
+ if (length > 50) {
+ return '10px';
+ }
+ if (length > 45) {
+ return '11px';
+ }
+ if (length > 40) {
+ return '12px';
+ }
+ if (length > 35) {
+ return '13px';
+ }
+ return undefined;
+}
+
function isPinned(id: string) {
return globals.state.pinnedTracks.indexOf(id) !== -1;
}
@@ -75,7 +95,6 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {
`.track-shell[draggable=true]`,
{
class: `${highlightClass} ${dragClass} ${dropClass}`,
- onmousedown: this.onmousedown.bind(this),
ondragstart: this.ondragstart.bind(this),
ondragend: this.ondragend.bind(this),
ondragover: this.ondragover.bind(this),
@@ -86,6 +105,9 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {
'h1',
{
title: attrs.trackState.name,
+ style: {
+ 'font-size': getTitleSize(attrs.trackState.name),
+ },
},
attrs.trackState.name,
('namespace' in attrs.trackState.config) &&
@@ -122,12 +144,6 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {
''));
}
- onmousedown(e: MouseEvent) {
- // Prevent that the click is intercepted by the PanAndZoomHandler and that
- // we start panning while dragging.
- e.stopPropagation();
- }
-
ondragstart(e: DragEvent) {
const dataTransfer = e.dataTransfer;
if (dataTransfer === null) return;
@@ -135,7 +151,6 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {
globals.rafScheduler.scheduleFullRedraw();
dataTransfer.setData('perfetto/track', `${this.attrs!.trackState.id}`);
dataTransfer.setDragImage(new Image(), 0, 0);
- e.stopImmediatePropagation();
}
ondragend() {
@@ -347,20 +362,20 @@ export class TrackPanel extends Panel<TrackPanelAttrs> {
}
highlightIfTrackSelected(ctx: CanvasRenderingContext2D, size: PanelSize) {
- const localState = globals.frontendLocalState;
+ const {visibleTimeScale} = globals.frontendLocalState;
const selection = globals.state.currentSelection;
const trackState = this.trackState;
if (!selection || selection.kind !== 'AREA' || trackState === undefined) {
return;
}
const selectedArea = globals.state.areas[selection.areaId];
+ const selectedAreaDuration = selectedArea.end - selectedArea.start;
if (selectedArea.tracks.includes(trackState.id)) {
- const timeScale = localState.timeScale;
ctx.fillStyle = SELECTION_FILL_COLOR;
ctx.fillRect(
- timeScale.timeToPx(selectedArea.startSec) + TRACK_SHELL_WIDTH,
+ visibleTimeScale.tpTimeToPx(selectedArea.start) + TRACK_SHELL_WIDTH,
0,
- timeScale.deltaTimeToPx(selectedArea.endSec - selectedArea.startSec),
+ visibleTimeScale.durationToPx(selectedAreaDuration),
size.height);
}
}
@@ -381,20 +396,20 @@ export class TrackPanel extends Panel<TrackPanelAttrs> {
this.highlightIfTrackSelected(ctx, size);
- const localState = globals.frontendLocalState;
+ const {visibleTimeScale} = globals.frontendLocalState;
// Draw vertical line when hovering on the notes panel.
- if (globals.state.hoveredNoteTimestamp !== -1) {
+ if (globals.state.hoveredNoteTimestamp !== -1n) {
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
+ visibleTimeScale,
globals.state.hoveredNoteTimestamp,
size.height,
`#aaa`);
}
- if (globals.state.hoverCursorTimestamp !== -1) {
+ if (globals.state.hoverCursorTimestamp !== -1n) {
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
+ visibleTimeScale,
globals.state.hoverCursorTimestamp,
size.height,
`#344596`);
@@ -405,7 +420,7 @@ export class TrackPanel extends Panel<TrackPanelAttrs> {
globals.sliceDetails.wakeupTs !== undefined) {
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
+ visibleTimeScale,
globals.sliceDetails.wakeupTs,
size.height,
`black`);
@@ -419,21 +434,21 @@ export class TrackPanel extends Panel<TrackPanelAttrs> {
'rgba(' + hex.rgb(note.color.substr(1)).toString() + ', 0.65)';
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
- globals.state.areas[note.areaId].startSec,
+ visibleTimeScale,
+ globals.state.areas[note.areaId].start,
size.height,
transparentNoteColor,
1);
drawVerticalLineAtTime(
ctx,
- localState.timeScale,
- globals.state.areas[note.areaId].endSec,
+ visibleTimeScale,
+ globals.state.areas[note.areaId].end,
size.height,
transparentNoteColor,
1);
} else if (note.noteType === 'DEFAULT') {
drawVerticalLineAtTime(
- ctx, localState.timeScale, note.timestamp, size.height, note.color);
+ ctx, visibleTimeScale, note.timestamp, size.height, note.color);
}
}
}
diff --git a/ui/src/frontend/vertical_line_helper.ts b/ui/src/frontend/vertical_line_helper.ts
index b1e2cfc8c..353d166cb 100644
--- a/ui/src/frontend/vertical_line_helper.ts
+++ b/ui/src/frontend/vertical_line_helper.ts
@@ -12,18 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {TPTime} from '../common/time';
import {TRACK_SHELL_WIDTH} from './css_constants';
import {TimeScale} from './time_scale';
-export function drawVerticalLineAtTime(ctx: CanvasRenderingContext2D,
- timeScale: TimeScale,
- time: number,
- height: number,
- color: string,
- lineWidth = 2) {
- const xPos = TRACK_SHELL_WIDTH + Math.floor(timeScale.timeToPx(time));
- drawVerticalLine(ctx, xPos, height, color, lineWidth);
- }
+export function drawVerticalLineAtTime(
+ ctx: CanvasRenderingContext2D,
+ timeScale: TimeScale,
+ time: TPTime,
+ height: number,
+ color: string,
+ lineWidth = 2) {
+ const xPos = TRACK_SHELL_WIDTH + Math.floor(timeScale.tpTimeToPx(time));
+ drawVerticalLine(ctx, xPos, height, color, lineWidth);
+}
function drawVerticalLine(ctx: CanvasRenderingContext2D,
xPos: number,
diff --git a/ui/src/frontend/viewer_page.ts b/ui/src/frontend/viewer_page.ts
index 996cae6af..1a9e0962a 100644
--- a/ui/src/frontend/viewer_page.ts
+++ b/ui/src/frontend/viewer_page.ts
@@ -13,9 +13,10 @@
// limitations under the License.
import m from 'mithril';
+import {BigintMath} from '../base/bigint_math';
import {Actions} from '../common/actions';
-import {TimeSpan} from '../common/time';
+import {featureFlags} from '../common/feature_flags';
import {TRACK_SHELL_WIDTH} from './css_constants';
import {DetailsPanel} from './details_panel';
@@ -27,7 +28,6 @@ import {PanAndZoomHandler} from './pan_and_zoom_handler';
import {AnyAttrsVnode, PanelContainer} from './panel_container';
import {TickmarkPanel} from './tickmark_panel';
import {TimeAxisPanel} from './time_axis_panel';
-import {computeZoom} from './time_scale';
import {TimeSelectionPanel} from './time_selection_panel';
import {DISMISSED_PANNING_HINT_KEY} from './topbar';
import {TrackGroupPanel} from './track_group_panel';
@@ -35,6 +35,13 @@ import {TrackPanel} from './track_panel';
const SIDEBAR_WIDTH = 256;
+const OVERVIEW_PANEL_FLAG = featureFlags.register({
+ id: 'overviewVisible',
+ name: 'Overview Panel',
+ description: 'Show the panel providing an overview of the trace',
+ defaultValue: true,
+});
+
// Checks if the mousePos is within 3px of the start or end of the
// current selected time range.
function onTimeRangeBoundary(mousePos: number): 'START'|'END'|null {
@@ -45,8 +52,9 @@ function onTimeRangeBoundary(mousePos: number): 'START'|'END'|null {
const area = globals.frontendLocalState.selectedArea ?
globals.frontendLocalState.selectedArea :
globals.state.areas[selection.areaId];
- const start = globals.frontendLocalState.timeScale.timeToPx(area.startSec);
- const end = globals.frontendLocalState.timeScale.timeToPx(area.endSec);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const start = visibleTimeScale.tpTimeToPx(area.start);
+ const end = visibleTimeScale.tpTimeToPx(area.end);
const startDrag = mousePos - TRACK_SHELL_WIDTH;
const startDistance = Math.abs(start - startDrag);
const endDistance = Math.abs(end - startDrag);
@@ -111,21 +119,14 @@ class TraceViewer implements m.ClassComponent {
element: panZoomEl,
contentOffsetX: SIDEBAR_WIDTH,
onPanned: (pannedPx: number) => {
+ const {
+ visibleTimeScale,
+ } = globals.frontendLocalState;
+
this.keepCurrentSelection = true;
- const traceTime = globals.state.traceTime;
- const vizTime = globals.frontendLocalState.visibleWindowTime;
- const origDelta = vizTime.duration;
- const tDelta = frontendLocalState.timeScale.deltaPxToDuration(pannedPx);
- let tStart = vizTime.start + tDelta;
- let tEnd = vizTime.end + tDelta;
- if (tStart < traceTime.startSec) {
- tStart = traceTime.startSec;
- tEnd = tStart + origDelta;
- } else if (tEnd > traceTime.endSec) {
- tEnd = traceTime.endSec;
- tStart = tEnd - origDelta;
- }
- frontendLocalState.updateVisibleTime(new TimeSpan(tStart, tEnd));
+ const tDelta = visibleTimeScale.pxDeltaToDuration(pannedPx);
+ frontendLocalState.panVisibleWindow(tDelta);
+
// If the user has panned they no longer need the hint.
localStorage.setItem(DISMISSED_PANNING_HINT_KEY, 'true');
globals.rafScheduler.scheduleRedraw();
@@ -133,11 +134,10 @@ class TraceViewer implements m.ClassComponent {
onZoomed: (zoomedPositionPx: number, zoomRatio: number) => {
// TODO(hjd): Avoid hardcoding TRACK_SHELL_WIDTH.
// TODO(hjd): Improve support for zooming in overview timeline.
- const span = frontendLocalState.visibleWindowTime;
- const scale = frontendLocalState.timeScale;
const zoomPx = zoomedPositionPx - TRACK_SHELL_WIDTH;
- const newSpan = computeZoom(scale, span, 1 - zoomRatio, zoomPx);
- frontendLocalState.updateVisibleTime(newSpan);
+ const rect = vnode.dom.getBoundingClientRect();
+ const centerPoint = zoomPx / (rect.width - TRACK_SHELL_WIDTH);
+ frontendLocalState.zoomVisibleWindow(1 - zoomRatio, centerPoint);
globals.rafScheduler.scheduleRedraw();
},
editSelection: (currentPx: number) => {
@@ -151,7 +151,7 @@ class TraceViewer implements m.ClassComponent {
currentY: number,
editing: boolean) => {
const traceTime = globals.state.traceTime;
- const scale = frontendLocalState.timeScale;
+ const {visibleTimeScale} = frontendLocalState;
this.keepCurrentSelection = true;
if (editing) {
const selection = globals.state.currentSelection;
@@ -159,33 +159,40 @@ class TraceViewer implements m.ClassComponent {
const area = globals.frontendLocalState.selectedArea ?
globals.frontendLocalState.selectedArea :
globals.state.areas[selection.areaId];
- let newTime = scale.pxToTime(currentX - TRACK_SHELL_WIDTH);
+ let newTime =
+ visibleTimeScale.pxToHpTime(currentX - TRACK_SHELL_WIDTH)
+ .toTPTime();
// Have to check again for when one boundary crosses over the other.
const curBoundary = onTimeRangeBoundary(prevX);
if (curBoundary == null) return;
- const keepTime =
- curBoundary === 'START' ? area.endSec : area.startSec;
+ const keepTime = curBoundary === 'START' ? area.end : area.start;
// Don't drag selection outside of current screen.
if (newTime < keepTime) {
- newTime = Math.max(newTime, scale.pxToTime(scale.startPx));
+ newTime = BigintMath.max(
+ newTime, visibleTimeScale.timeSpan.start.toTPTime());
} else {
- newTime = Math.min(newTime, scale.pxToTime(scale.endPx));
+ newTime = BigintMath.max(
+ newTime, visibleTimeScale.timeSpan.end.toTPTime());
}
// When editing the time range we always use the saved tracks,
// since these will not change.
frontendLocalState.selectArea(
- Math.max(Math.min(keepTime, newTime), traceTime.startSec),
- Math.min(Math.max(keepTime, newTime), traceTime.endSec),
+ BigintMath.max(
+ BigintMath.min(keepTime, newTime), traceTime.start),
+ BigintMath.min(
+ BigintMath.max(keepTime, newTime), traceTime.end),
globals.state.areas[selection.areaId].tracks);
}
} else {
let startPx = Math.min(dragStartX, currentX) - TRACK_SHELL_WIDTH;
let endPx = Math.max(dragStartX, currentX) - TRACK_SHELL_WIDTH;
if (startPx < 0 && endPx < 0) return;
- startPx = Math.max(startPx, scale.startPx);
- endPx = Math.min(endPx, scale.endPx);
+ startPx = Math.max(startPx, visibleTimeScale.pxSpan.start);
+ endPx = Math.min(endPx, visibleTimeScale.pxSpan.end);
frontendLocalState.selectArea(
- scale.pxToTime(startPx), scale.pxToTime(endPx));
+ visibleTimeScale.pxToHpTime(startPx).toTPTime('floor'),
+ visibleTimeScale.pxToHpTime(endPx).toTPTime('ceil'),
+ );
frontendLocalState.areaY.start = dragStartY;
frontendLocalState.areaY.end = currentY;
}
@@ -252,12 +259,20 @@ class TraceViewer implements m.ClassComponent {
} as TrackGroupAttrs));
}
+ const overviewPanel = [];
+ if (OVERVIEW_PANEL_FLAG.get()) {
+ overviewPanel.push(m(OverviewTimelinePanel, {key: 'overview'}));
+ }
+
return m(
'.page',
m('.split-panel',
m('.pan-and-zoom-content',
{
onclick: () => {
+ // TODO(stevegolton): Make it possible to click buttons and
+ // things on this element without deselecting the selected
+ // element!
// We don't want to deselect when panning/drag selecting.
if (this.keepCurrentSelection) {
this.keepCurrentSelection = false;
@@ -269,7 +284,7 @@ class TraceViewer implements m.ClassComponent {
m('.pinned-panel-container', m(PanelContainer, {
doesScroll: false,
panels: [
- m(OverviewTimelinePanel, {key: 'overview'}),
+ ...overviewPanel,
m(TimeAxisPanel, {key: 'timeaxis'}),
m(TimeSelectionPanel, {key: 'timeselection'}),
m(NotesPanel, {key: 'notes'}),
diff --git a/ui/src/frontend/widgets/button.ts b/ui/src/frontend/widgets/button.ts
index 28df66a23..ac86e135d 100644
--- a/ui/src/frontend/widgets/button.ts
+++ b/ui/src/frontend/widgets/button.ts
@@ -15,6 +15,7 @@
import m from 'mithril';
import {classNames} from '../classnames';
import {Icon} from './icon';
+import {Popup} from './popup';
interface CommonAttrs {
// Always show the button as if the "active" pseudo class were applied, which
@@ -35,6 +36,11 @@ interface CommonAttrs {
disabled?: boolean;
// Optional right icon.
rightIcon?: string;
+ // List of space separated class names forwarded to the icon.
+ className?: string;
+ // Allow clicking this button to close parent popups.
+ // Defaults to false.
+ dismissPopup?: boolean;
// Remaining attributes forwarded to the underlying HTML <button>.
[htmlAttrs: string]: any;
}
@@ -63,6 +69,8 @@ export class Button implements m.ClassComponent<ButtonAttrs> {
minimal = false,
disabled = false,
rightIcon,
+ className,
+ dismissPopup = false,
...htmlAttrs
} = attrs;
@@ -72,6 +80,8 @@ export class Button implements m.ClassComponent<ButtonAttrs> {
compact && 'pf-compact',
minimal && 'pf-minimal',
(icon && !label) && 'pf-icon-only',
+ dismissPopup && Popup.DISMISS_POPUP_GROUP_CLASS,
+ className,
);
return m(
diff --git a/ui/src/frontend/widgets/duration.ts b/ui/src/frontend/widgets/duration.ts
index 6f36c95bd..cd18e029e 100644
--- a/ui/src/frontend/widgets/duration.ts
+++ b/ui/src/frontend/widgets/duration.ts
@@ -14,14 +14,14 @@
import m from 'mithril';
-import {fromNs, timeToCode} from '../../common/time';
+import {TPDuration, tpTimeToCode} from '../../common/time';
interface DurationAttrs {
- dur: number;
+ dur: TPDuration;
}
export class Duration implements m.ClassComponent<DurationAttrs> {
view(vnode: m.Vnode<DurationAttrs>) {
- return timeToCode(fromNs(vnode.attrs.dur));
+ return tpTimeToCode(vnode.attrs.dur);
}
}
diff --git a/ui/src/frontend/widgets/form.ts b/ui/src/frontend/widgets/form.ts
new file mode 100644
index 000000000..64bf1ee77
--- /dev/null
+++ b/ui/src/frontend/widgets/form.ts
@@ -0,0 +1,61 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import m from 'mithril';
+import {classNames} from '../classnames';
+
+interface FormAttrs {
+ // List of space separated class names forwarded to the icon.
+ className?: string;
+ // Remaining attributes forwarded to the underlying HTML <button>.
+ [htmlAttrs: string]: any;
+}
+
+export class Form implements m.ClassComponent<FormAttrs> {
+ view({attrs, children}: m.CVnode<FormAttrs>) {
+ const {className, ...htmlAttrs} = attrs;
+
+ const classes = classNames(
+ 'pf-form',
+ className,
+ );
+
+ return m(
+ 'form.pf-form',
+ {
+ class: classes,
+ ...htmlAttrs,
+ },
+ children,
+ );
+ }
+}
+
+export class FormButtonBar implements m.ClassComponent<{}> {
+ view({children}: m.CVnode<{}>) {
+ return m('.pf-form-button-bar', children);
+ }
+}
+
+interface FormLabelAttrs {
+ for: string;
+ // Remaining attributes forwarded to the underlying HTML <button>.
+ [htmlAttrs: string]: any;
+}
+
+export class FormLabel implements m.ClassComponent<FormLabelAttrs> {
+ view({attrs, children}: m.CVnode<FormLabelAttrs>) {
+ return m('label.pf-form-label', attrs, children);
+ }
+}
diff --git a/ui/src/frontend/widgets/menu.ts b/ui/src/frontend/widgets/menu.ts
index 582e6fbf1..b521dabb6 100644
--- a/ui/src/frontend/widgets/menu.ts
+++ b/ui/src/frontend/widgets/menu.ts
@@ -68,6 +68,7 @@ export class MenuItem implements m.ClassComponent<MenuItemAttrs> {
...rest,
}),
showArrow: false,
+ createNewGroup: false,
},
children,
);
@@ -86,7 +87,7 @@ export class MenuItem implements m.ClassComponent<MenuItemAttrs> {
const classes = classNames(
active && 'pf-active',
- !disabled && closePopupOnClick && 'pf-close-parent-popup-on-click',
+ !disabled && closePopupOnClick && Popup.DISMISS_POPUP_GROUP_CLASS,
);
return m(
@@ -131,6 +132,14 @@ interface PopupMenu2Attrs {
// Whether we should show the little arrow pointing to the trigger.
// Defaults to true.
showArrow?: boolean;
+ // Whether this popup should form a new popup group.
+ // When nesting popups, grouping controls how popups are closed.
+ // When closing popups via the Escape key, each group is closed one by one,
+ // starting at the topmost group in the stack.
+ // When using a magic button to close groups (see DISMISS_POPUP_GROUP_CLASS),
+ // only the group in which the button lives and it's children will be closed.
+ // Defaults to true.
+ createNewGroup?: boolean;
}
// A combination of a Popup and a Menu component.
@@ -146,7 +155,6 @@ export class PopupMenu2 implements m.ClassComponent<PopupMenu2Attrs> {
{
trigger,
position: popupPosition,
- closeOnContentClick: true,
...popupAttrs,
},
m(Menu, children));
diff --git a/ui/src/frontend/widgets/popup.ts b/ui/src/frontend/widgets/popup.ts
index ca6feb8fe..b258a115a 100644
--- a/ui/src/frontend/widgets/popup.ts
+++ b/ui/src/frontend/widgets/popup.ts
@@ -65,14 +65,19 @@ export interface PopupAttrs {
isOpen?: boolean;
// Called when the popup isOpen state should be changed in controlled mode.
onChange?: OnChangeCallback;
- // Close the popup if clicked on.
- // Defaults to false.
- closeOnContentClick?: boolean;
// Space delimited class names applied to the popup div.
className?: string;
// Whether to show a little arrow pointing to our trigger element.
// Defaults to true.
showArrow?: boolean;
+ // Whether this popup should form a new popup group.
+ // When nesting popups, grouping controls how popups are closed.
+ // When closing popups via the Escape key, each group is closed one by one,
+ // starting at the topmost group in the stack.
+ // When using a magic button to close groups (see DISMISS_POPUP_GROUP_CLASS),
+ // only the group in which the button lives and it's children will be closed.
+ // Defaults to true.
+ createNewGroup?: boolean;
}
// A popup is a portal whose position is dynamically updated so that it floats
@@ -90,6 +95,10 @@ export class Popup implements m.ClassComponent<PopupAttrs> {
private static readonly TRIGGER_REF = 'trigger';
private static readonly POPUP_REF = 'popup';
+ static readonly POPUP_GROUP_CLASS = 'pf-popup-group';
+
+ // Any element with this class will close its containing popup group on click
+ static readonly DISMISS_POPUP_GROUP_CLASS = 'pf-dismiss-popup-group';
view({attrs, children}: m.CVnode<PopupAttrs>): m.Children {
const {
@@ -127,6 +136,7 @@ export class Popup implements m.ClassComponent<PopupAttrs> {
const {
className,
showArrow = true,
+ createNewGroup = true,
} = attrs;
const portalAttrs: PortalAttrs = {
@@ -168,7 +178,8 @@ export class Popup implements m.ClassComponent<PopupAttrs> {
portalAttrs,
m('.pf-popup',
{
- class: classNames(className),
+ class: classNames(
+ className, createNewGroup && Popup.POPUP_GROUP_CLASS),
ref: Popup.POPUP_REF,
},
showArrow && m('.pf-popup-arrow[data-popper-arrow]'),
@@ -236,14 +247,29 @@ export class Popup implements m.ClassComponent<PopupAttrs> {
};
private handleDocKeyPress = (e: KeyboardEvent) => {
- if (this.closeOnEscape && e.key === 'Escape') {
- this.closePopup();
+ // Close on escape keypress if we are in the toplevel group
+ const nextGroupElement =
+ this.popupElement?.querySelector(`.${Popup.POPUP_GROUP_CLASS}`);
+ if (!nextGroupElement) {
+ if (this.closeOnEscape && e.key === 'Escape') {
+ this.closePopup();
+ }
}
};
private handleContentClick = (e: Event) => {
+ // Close the popup if the clicked element:
+ // - Is in the same group as this class
+ // - Has the magic class
const target = e.target as HTMLElement;
- if (target.closest('.pf-close-parent-popup-on-click')) {
+ const childPopup =
+ this.popupElement?.querySelector(`.${Popup.POPUP_GROUP_CLASS}`);
+ if (childPopup) {
+ if (childPopup.contains(target)) {
+ return;
+ }
+ }
+ if (target.closest(`.${Popup.DISMISS_POPUP_GROUP_CLASS}`)) {
this.closePopup();
}
};
diff --git a/ui/src/frontend/widgets/timestamp.ts b/ui/src/frontend/widgets/timestamp.ts
index 455227535..d8cc841d2 100644
--- a/ui/src/frontend/widgets/timestamp.ts
+++ b/ui/src/frontend/widgets/timestamp.ts
@@ -14,7 +14,7 @@
import m from 'mithril';
-import {timeToCode} from '../../common/time';
+import {tpTimeToCode} from '../../common/time';
import {toTraceTime, TPTimestamp} from '../sql_types';
interface TimestampAttrs {
@@ -23,6 +23,6 @@ interface TimestampAttrs {
export class Timestamp implements m.ClassComponent<TimestampAttrs> {
view(vnode: m.Vnode<TimestampAttrs>) {
- return timeToCode(toTraceTime(vnode.attrs.ts));
+ return tpTimeToCode(toTraceTime(vnode.attrs.ts));
}
}
diff --git a/ui/src/frontend/widgets/tree.ts b/ui/src/frontend/widgets/tree.ts
index 0428a482a..e79734386 100644
--- a/ui/src/frontend/widgets/tree.ts
+++ b/ui/src/frontend/widgets/tree.ts
@@ -1,7 +1,10 @@
import m from 'mithril';
+
import {classNames} from '../classnames';
import {globals} from '../globals';
+
import {Button} from './button';
+import {Spinner} from './spinner';
import {hasChildren} from './utils';
export enum TreeLayout {
@@ -48,12 +51,16 @@ export class Tree implements m.ClassComponent<TreeAttrs> {
}
interface TreeNodeAttrs {
- // Content to display on the left hand column.
+ // Content to display in the left hand column.
// If omitted, this side will be blank.
- left?: m.Child;
- // Content to display on the right hand column.
+ left?: m.Children;
+ // Content to display in the right hand column.
// If omitted, this side will be left blank.
- right?: m.Child;
+ right?: m.Children;
+ // Content to display in the right hand column when the node is collapsed.
+ // If omitted, the value of `right` shall be shown when collapsed instead.
+ // If the node has no children, this value is never shown.
+ summary?: m.Children;
// Whether this node is collapsed or not.
// If omitted, collapsed state 'uncontrolled' - i.e. controlled internally.
collapsed?: boolean;
@@ -86,8 +93,13 @@ export class TreeNode implements m.ClassComponent<TreeNodeAttrs> {
);
}
- private renderRight({attrs: {right}}: m.CVnode<TreeNodeAttrs>) {
- return m('.pf-tree-right', right);
+ private renderRight(vnode: m.CVnode<TreeNodeAttrs>) {
+ const {attrs: {right, summary}} = vnode;
+ if (hasChildren(vnode) && this.isCollapsed(vnode)) {
+ return m('.pf-tree-right', summary ?? right);
+ } else {
+ return m('.pf-tree-right', right);
+ }
}
private renderChildren(vnode: m.CVnode<TreeNodeAttrs>) {
@@ -126,3 +138,81 @@ export class TreeNode implements m.ClassComponent<TreeNodeAttrs> {
return collapsed;
}
}
+
+export function dictToTree(dict: {[key: string]: m.Child}): m.Children {
+ const children: m.Child[] = [];
+ for (const key of Object.keys(dict)) {
+ children.push(m(TreeNode, {
+ left: key,
+ right: dict[key],
+ }));
+ }
+ return m(Tree, children);
+}
+
+interface LazyTreeNodeAttrs {
+ // Same as TreeNode (see above).
+ left?: m.Children;
+ // Same as TreeNode (see above).
+ right?: m.Children;
+ // Same as TreeNode (see above).
+ summary?: m.Children;
+ // A callback to be called when the TreeNode is expanded, in order to fetch
+ // child nodes.
+ // The callback must return a promise to a function which returns m.Children.
+ // The reason the promise must return a function rather than the actual
+ // children is to avoid storing vnodes between render cycles, which is a bug
+ // in Mithril.
+ fetchData: () => Promise<() => m.Children>;
+ // Whether to keep child nodes in memory after the node has been collapsed.
+ // Defaults to true
+ hoardData?: boolean;
+}
+
+// This component is a TreeNode which only loads child nodes when it's expanded.
+// This allows us to represent huge trees without having to load all the data
+// up front, and even allows us to represent infinite or recursive trees.
+export class LazyTreeNode implements m.ClassComponent<LazyTreeNodeAttrs> {
+ private collapsed: boolean = true;
+ private renderChildren = this.renderSpinner;
+
+ private renderSpinner(): m.Children {
+ return m(TreeNode, {left: m(Spinner)});
+ }
+
+ view({attrs}: m.CVnode<LazyTreeNodeAttrs>): m.Children {
+ const {
+ left,
+ right,
+ summary,
+ fetchData,
+ hoardData = true,
+ } = attrs;
+
+ return m(
+ TreeNode,
+ {
+ left,
+ right,
+ summary,
+ collapsed: this.collapsed,
+ onCollapseChanged: (collapsed) => {
+ if (collapsed) {
+ if (!hoardData) {
+ this.renderChildren = this.renderSpinner;
+ }
+ } else {
+ fetchData().then((result) => {
+ if (!this.collapsed) {
+ this.renderChildren = result;
+ globals.rafScheduler.scheduleFullRedraw();
+ }
+ });
+ }
+ this.collapsed = collapsed;
+ globals.rafScheduler.scheduleFullRedraw();
+ },
+ },
+ this.renderChildren());
+ }
+}
diff --git a/ui/src/frontend/widgets_page.ts b/ui/src/frontend/widgets_page.ts
index 2c2ca9b7b..989be89be 100644
--- a/ui/src/frontend/widgets_page.ts
+++ b/ui/src/frontend/widgets_page.ts
@@ -24,6 +24,7 @@ import {TableShowcase} from './tables/table_showcase';
import {Button} from './widgets/button';
import {Checkbox} from './widgets/checkbox';
import {EmptyState} from './widgets/empty_state';
+import {Form, FormButtonBar, FormLabel} from './widgets/form';
import {Icon} from './widgets/icon';
import {Menu, MenuDivider, MenuItem, PopupMenu2} from './widgets/menu';
import {MultiSelect, MultiSelectDiff} from './widgets/multiselect';
@@ -33,7 +34,7 @@ import {Select} from './widgets/select';
import {Spinner} from './widgets/spinner';
import {Switch} from './widgets/switch';
import {TextInput} from './widgets/text_input';
-import {Tree, TreeLayout, TreeNode} from './widgets/tree';
+import {LazyTreeNode, Tree, TreeLayout, TreeNode} from './widgets/tree';
const options: {[key: string]: boolean} = {
foobar: false,
@@ -242,6 +243,18 @@ class WidgetShowcase implements m.ClassComponent<WidgetShowcaseAttrs> {
}
}
+function recursiveLazyTreeNode(
+ left: string, summary: string, hoardData: boolean): m.Children {
+ return m(LazyTreeNode, {
+ left,
+ summary,
+ hoardData,
+ fetchData: async () => {
+ await new Promise((r) => setTimeout(r, 200));
+ return () => recursiveLazyTreeNode(left, summary, hoardData);
+ },
+ });
+}
export const WidgetsPage = createPage({
view() {
@@ -540,7 +553,7 @@ export const WidgetsPage = createPage({
PopupMenu2,
{
trigger: m(Anchor, {
- text: 'SELECT * FROM raw WHERE id = 123',
+ text: 'SELECT * FROM ftrace_event WHERE id = 123',
icon: 'unfold_more',
}),
},
@@ -562,9 +575,14 @@ export const WidgetsPage = createPage({
left: 'Process',
right: m(Anchor, {text: '/bin/foo[789]', icon: 'open_in_new'}),
}),
+ recursiveLazyTreeNode('Lazy', '(hoarding)', true),
+ recursiveLazyTreeNode('Lazy', '(non-hoarding)', false),
m(
TreeNode,
- {left: 'Args', right: 'foo: bar, baz: qux'},
+ {
+ left: 'Args',
+ summary: 'foo: string, baz: string, quux: string[4]',
+ },
m(TreeNode, {left: 'foo', right: 'bar'}),
m(TreeNode, {left: 'baz', right: 'qux'}),
m(
@@ -585,6 +603,45 @@ export const WidgetsPage = createPage({
},
wide: true,
}),
+ m('h2', 'Form'),
+ m(
+ WidgetShowcase, {
+ renderWidget: () => m(
+ Form,
+ m(FormLabel, {for: 'foo'}, 'Foo'),
+ m(TextInput, {id: 'foo'}),
+ m(FormLabel, {for: 'bar'}, 'Bar'),
+ m(Select, {id: 'bar'}, [
+ m('option', {value: 'foo', label: 'Foo'}),
+ m('option', {value: 'bar', label: 'Bar'}),
+ m('option', {value: 'baz', label: 'Baz'}),
+ ]),
+ m(FormButtonBar,
+ m(Button, {label: 'Submit', rightIcon: 'chevron_right'}),
+ m(Button, {label: 'Cancel', minimal: true}),
+ )),
+ }),
+ m('h2', 'Nested Popups'),
+ m(
+ WidgetShowcase, {
+ renderWidget: () => m(
+ Popup,
+ {
+ trigger: m(Button, {label: 'Open the popup'}),
+ },
+ m(PopupMenu2,
+ {
+ trigger: m(Button, {label: 'Select an option'}),
+ },
+ m(MenuItem, {label: 'Option 1'}),
+ m(MenuItem, {label: 'Option 2'}),
+ ),
+ m(Button, {
+ label: 'Done',
+ dismissPopup: true,
+ }),
+ ),
+ }),
);
},
});
diff --git a/ui/src/traceconv/index.ts b/ui/src/traceconv/index.ts
index 714666a08..df3e8a000 100644
--- a/ui/src/traceconv/index.ts
+++ b/ui/src/traceconv/index.ts
@@ -18,6 +18,7 @@ import {
ConversionJobName,
ConversionJobStatus,
} from '../common/conversion_jobs';
+import {TPTime} from '../common/time';
import traceconv from '../gen/traceconv';
const selfWorker = self as {} as Worker;
@@ -176,7 +177,7 @@ interface ConvertTraceToPprofArgs {
kind: 'ConvertTraceToPprof';
trace: Blob;
pid: number;
- ts: number;
+ ts: TPTime;
}
function isConvertTraceToPprof(msg: Args): msg is ConvertTraceToPprofArgs {
@@ -186,8 +187,7 @@ function isConvertTraceToPprof(msg: Args): msg is ConvertTraceToPprofArgs {
return true;
}
-async function ConvertTraceToPprof(
-trace: Blob, pid: number, ts: number) {
+async function ConvertTraceToPprof(trace: Blob, pid: number, ts: TPTime) {
const jobName = 'convert_pprof';
updateJobStatus(jobName, ConversionJobStatus.InProgress);
const args = [
diff --git a/ui/src/tracks/actual_frames/index.ts b/ui/src/tracks/actual_frames/index.ts
index 927dea442..7f5afb0fc 100644
--- a/ui/src/tracks/actual_frames/index.ts
+++ b/ui/src/tracks/actual_frames/index.ts
@@ -14,7 +14,7 @@
import {PluginContext} from '../../common/plugin_api';
import {NUM, NUM_NULL, STR} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {fromNs, TPDuration, TPTime, tpTimeToNanos} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {TrackController} from '../../controller/track_controller';
import {NewTrackArgs, Track} from '../../frontend/track';
@@ -51,16 +51,17 @@ class ActualFramesSliceTrackController extends TrackController<Config, Data> {
static readonly kind = ACTUAL_FRAMES_SLICE_TRACK_KIND;
private maxDurNs = 0;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNs(start);
- const endNs = toNs(end);
+ const startNs = tpTimeToNanos(start);
+ const endNs = tpTimeToNanos(end);
const pxSize = this.pxSize();
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
- const bucketNs = Math.max(Math.round(resolution * 1e9 * pxSize / 2) * 2, 1);
+ const bucketNs =
+ Math.max(Math.round(Number(resolution) * pxSize / 2) * 2, 1);
if (this.maxDurNs === 0) {
const maxDurResult = await this.query(`
diff --git a/ui/src/tracks/android_log/index.ts b/ui/src/tracks/android_log/index.ts
index b2a824bf2..6c8a1bc03 100644
--- a/ui/src/tracks/android_log/index.ts
+++ b/ui/src/tracks/android_log/index.ts
@@ -14,7 +14,7 @@
import {PluginContext} from '../../common/plugin_api';
import {NUM} from '../../common/query_result';
-import {fromNs, toNsCeil, toNsFloor} from '../../common/time';
+import {fromNs, TPDuration, TPTime} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {LIMIT} from '../../common/track_data';
import {
@@ -61,21 +61,15 @@ const EVT_PX = 2; // Width of an event tick in pixels.
class AndroidLogTrackController extends TrackController<Config, Data> {
static readonly kind = ANDROID_LOGS_TRACK_KIND;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNsFloor(start);
- const endNs = toNsCeil(end);
-
- // |resolution| is in s/px the frontend wants.
- const quantNs = toNsCeil(resolution);
-
const queryRes = await this.query(`
select
- cast(ts / ${quantNs} as integer) * ${quantNs} as tsQuant,
+ cast(ts / ${resolution} as integer) * ${resolution} as tsQuant,
prio,
count(prio) as numEvents
from android_logs
- where ts >= ${startNs} and ts <= ${endNs}
+ where ts >= ${start} and ts <= ${end}
group by tsQuant, prio
order by tsQuant, prio limit ${LIMIT};`);
@@ -113,16 +107,16 @@ class AndroidLogTrack extends Track<Config, Data> {
}
renderCanvas(ctx: CanvasRenderingContext2D): void {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {visibleTimeScale, windowSpan} = globals.frontendLocalState;
const data = this.data();
if (data === undefined) return; // Can't possibly draw anything.
- const dataStartPx = timeScale.timeToPx(data.start);
- const dataEndPx = timeScale.timeToPx(data.end);
- const visibleStartPx = timeScale.timeToPx(visibleWindowTime.start);
- const visibleEndPx = timeScale.timeToPx(visibleWindowTime.end);
+ const dataStartPx = visibleTimeScale.tpTimeToPx(data.start);
+ const dataEndPx = visibleTimeScale.tpTimeToPx(data.end);
+ const visibleStartPx = windowSpan.start;
+ const visibleEndPx = windowSpan.end;
checkerboardExcept(
ctx,
@@ -133,7 +127,7 @@ class AndroidLogTrack extends Track<Config, Data> {
dataEndPx);
const quantWidth =
- Math.max(EVT_PX, timeScale.deltaTimeToPx(data.resolution));
+ Math.max(EVT_PX, visibleTimeScale.durationToPx(data.resolution));
const blockH = RECT_HEIGHT / LEVELS.length;
for (let i = 0; i < data.timestamps.length; i++) {
for (let lev = 0; lev < LEVELS.length; lev++) {
@@ -143,7 +137,7 @@ class AndroidLogTrack extends Track<Config, Data> {
}
if (!hasEventsForCurColor) continue;
ctx.fillStyle = LEVELS[lev].color;
- const px = Math.floor(timeScale.timeToPx(data.timestamps[i]));
+ const px = Math.floor(visibleTimeScale.secondsToPx(data.timestamps[i]));
ctx.fillRect(px, MARGIN_TOP + blockH * lev, quantWidth, blockH);
} // for(lev)
} // for (timestamps)
diff --git a/ui/src/tracks/async_slices/index.ts b/ui/src/tracks/async_slices/index.ts
index 338e02a22..997577f71 100644
--- a/ui/src/tracks/async_slices/index.ts
+++ b/ui/src/tracks/async_slices/index.ts
@@ -13,8 +13,8 @@
// limitations under the License.
import {PluginContext} from '../../common/plugin_api';
-import {NUM, NUM_NULL, STR} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {LONG_NULL, NUM, STR} from '../../common/query_result';
+import {fromNs, TPDuration, TPTime} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
@@ -43,26 +43,24 @@ export interface Data extends TrackData {
class AsyncSliceTrackController extends TrackController<Config, Data> {
static readonly kind = ASYNC_SLICE_TRACK_KIND;
- private maxDurNs = 0;
+ private maxDurNs: TPDuration = 0n;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNs(start);
- const endNs = toNs(end);
-
const pxSize = this.pxSize();
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
- const bucketNs = Math.max(Math.round(resolution * 1e9 * pxSize / 2) * 2, 1);
+ const bucketNs =
+ Math.max(Math.round(Number(resolution) * pxSize / 2) * 2, 1);
- if (this.maxDurNs === 0) {
+ if (this.maxDurNs === 0n) {
const maxDurResult = await this.query(`
select max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur))
as maxDur from experimental_slice_layout
where filter_track_ids = '${this.config.trackIds.join(',')}'
`);
- this.maxDurNs = maxDurResult.firstRow({maxDur: NUM_NULL}).maxDur || 0;
+ this.maxDurNs = maxDurResult.firstRow({maxDur: LONG_NULL}).maxDur || 0n;
}
const queryRes = await this.query(`
@@ -78,8 +76,8 @@ class AsyncSliceTrackController extends TrackController<Config, Data> {
from experimental_slice_layout
where
filter_track_ids = '${this.config.trackIds.join(',')}' and
- ts >= ${startNs - this.maxDurNs} and
- ts <= ${endNs}
+ ts >= ${start - this.maxDurNs} and
+ ts <= ${end}
group by tsq, layout_depth
order by tsq, layout_depth
`);
diff --git a/ui/src/tracks/chrome_slices/index.ts b/ui/src/tracks/chrome_slices/index.ts
index 23f9a5e1a..4e7050782 100644
--- a/ui/src/tracks/chrome_slices/index.ts
+++ b/ui/src/tracks/chrome_slices/index.ts
@@ -15,9 +15,16 @@
import {Actions} from '../../common/actions';
import {cropText, drawIncompleteSlice} from '../../common/canvas_utils';
import {colorForThreadIdleSlice, hslForSlice} from '../../common/colorizer';
+import {
+ HighPrecisionTime,
+} from '../../common/high_precision_time';
import {PluginContext} from '../../common/plugin_api';
-import {NUM, NUM_NULL, STR} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {LONG_NULL, NUM, NUM_NULL, STR} from '../../common/query_result';
+import {
+ fromNs,
+ TPDuration,
+ TPTime,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
@@ -60,27 +67,25 @@ export interface Data extends TrackData {
export class ChromeSliceTrackController extends TrackController<Config, Data> {
static kind = SLICE_TRACK_KIND;
- private maxDurNs = 0;
+ private maxDurNs: TPDuration = 0n;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNs(start);
- const endNs = toNs(end);
-
const pxSize = this.pxSize();
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
- const bucketNs = Math.max(Math.round(resolution * 1e9 * pxSize / 2) * 2, 1);
+ const bucketNs =
+ Math.max(Math.round(Number(resolution) * pxSize / 2) * 2, 1);
const tableName = this.namespaceTable('slice');
- if (this.maxDurNs === 0) {
+ if (this.maxDurNs === 0n) {
const query = `
SELECT max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur))
AS maxDur FROM ${tableName} WHERE track_id = ${this.config.trackId}`;
const queryRes = await this.query(query);
- this.maxDurNs = queryRes.firstRow({maxDur: NUM_NULL}).maxDur || 0;
+ this.maxDurNs = queryRes.firstRow({maxDur: LONG_NULL}).maxDur || 0n;
}
// Buckets are always even and positive, don't quantize once we zoom to
@@ -103,8 +108,8 @@ export class ChromeSliceTrackController extends TrackController<Config, Data> {
thread_dur as threadDur
FROM ${tableName}
WHERE track_id = ${this.config.trackId} AND
- ts >= (${startNs - this.maxDurNs}) AND
- ts <= ${endNs}
+ ts >= (${start - this.maxDurNs}) AND
+ ts <= ${end}
GROUP BY depth, tsq`;
const queryRes = await this.query(query);
@@ -209,7 +214,7 @@ export class ChromeSliceTrack extends Track<Config, Data> {
renderCanvas(ctx: CanvasRenderingContext2D): void {
// TODO: fonts and colors should come from the CSS and not hardcoded here.
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {visibleTimeScale, visibleWindowTime} = globals.frontendLocalState;
const data = this.data();
if (data === undefined) return; // Can't possibly draw anything.
@@ -219,10 +224,10 @@ export class ChromeSliceTrack extends Track<Config, Data> {
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(visibleWindowTime.start),
- timeScale.timeToPx(visibleWindowTime.end),
- timeScale.timeToPx(data.start),
- timeScale.timeToPx(data.end),
+ visibleTimeScale.hpTimeToPx(visibleWindowTime.start),
+ visibleTimeScale.hpTimeToPx(visibleWindowTime.end),
+ visibleTimeScale.tpTimeToPx(data.start),
+ visibleTimeScale.tpTimeToPx(data.end),
);
ctx.textAlign = 'center';
@@ -245,7 +250,7 @@ export class ChromeSliceTrack extends Track<Config, Data> {
const title = data.strings[titleId];
const colorOverride = data.colors && data.strings[data.colors[i]];
if (isIncomplete) { // incomplete slice
- tEnd = visibleWindowTime.end;
+ tEnd = visibleWindowTime.end.seconds;
}
const rect = this.getSliceRect(tStart, tEnd, depth);
@@ -369,10 +374,14 @@ export class ChromeSliceTrack extends Track<Config, Data> {
getSliceIndex({x, y}: {x: number, y: number}): number|void {
const data = this.data();
if (data === undefined) return;
- const {timeScale} = globals.frontendLocalState;
+ const {
+ visibleTimeScale: timeScale,
+ visibleWindowTime,
+ } = globals.frontendLocalState;
if (y < TRACK_PADDING) return;
- const instantWidthTime = timeScale.deltaPxToDuration(HALF_CHEVRON_WIDTH_PX);
- const t = timeScale.pxToTime(x);
+ const instantWidthTime = timeScale.pxDeltaToDuration(HALF_CHEVRON_WIDTH_PX);
+ const instantWidthTimeSec = instantWidthTime.seconds;
+ const t = timeScale.pxToHpTime(x).seconds;
const depth = Math.floor((y - TRACK_PADDING) / SLICE_HEIGHT);
for (let i = 0; i < data.starts.length; i++) {
if (depth !== data.depths[i]) {
@@ -380,13 +389,13 @@ export class ChromeSliceTrack extends Track<Config, Data> {
}
const tStart = data.starts[i];
if (data.isInstant[i]) {
- if (Math.abs(tStart - t) < instantWidthTime) {
+ if (Math.abs(tStart - t) < instantWidthTimeSec) {
return i;
}
} else {
let tEnd = data.ends[i];
if (data.isIncomplete[i]) {
- tEnd = globals.frontendLocalState.visibleWindowTime.end;
+ tEnd = visibleWindowTime.end.seconds;
}
if (tStart <= t && t <= tEnd) {
return i;
@@ -435,17 +444,28 @@ export class ChromeSliceTrack extends Track<Config, Data> {
getSliceRect(tStart: number, tEnd: number, depth: number): SliceRect
|undefined {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
- const pxEnd = timeScale.timeToPx(visibleWindowTime.end);
- const left = Math.max(timeScale.timeToPx(tStart), 0);
- const right = Math.min(timeScale.timeToPx(tEnd), pxEnd);
+ const {
+ visibleTimeScale: timeScale,
+ visibleWindowTime,
+ windowSpan,
+ } = globals.frontendLocalState;
+
+ const pxEnd = windowSpan.end;
+ const left = Math.max(timeScale.secondsToPx(tStart), 0);
+ const right = Math.min(timeScale.secondsToPx(tEnd), pxEnd);
+
+ const visible =
+ !(visibleWindowTime.start.isGreaterThan(
+ HighPrecisionTime.fromSeconds(tEnd)) ||
+ visibleWindowTime.end.isLessThan(
+ HighPrecisionTime.fromSeconds(tStart)));
+
return {
left,
width: Math.max(right - left, 1),
top: TRACK_PADDING + depth * SLICE_HEIGHT,
height: SLICE_HEIGHT,
- visible:
- !(tEnd <= visibleWindowTime.start || tStart >= visibleWindowTime.end),
+ visible,
};
}
}
diff --git a/ui/src/tracks/counter/index.ts b/ui/src/tracks/counter/index.ts
index e49549945..f22e8c7c5 100644
--- a/ui/src/tracks/counter/index.ts
+++ b/ui/src/tracks/counter/index.ts
@@ -19,21 +19,27 @@ import {assertTrue} from '../../base/logging';
import {Actions} from '../../common/actions';
import {
EngineProxy,
+ LONG_NULL,
NUM,
- NUM_NULL,
PluginContext,
STR,
TrackInfo,
} from '../../common/plugin_api';
-import {fromNs, toNs} from '../../common/time';
+import {
+ fromNs,
+ TPDuration,
+ TPTime,
+ tpTimeFromSeconds,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
} from '../../controller/track_controller';
import {checkerboardExcept} from '../../frontend/checkerboard';
import {globals} from '../../frontend/globals';
-import {PopupMenuButton, PopupMenuItem} from '../../frontend/popup_menu';
import {NewTrackArgs, Track} from '../../frontend/track';
+import {Button} from '../../frontend/widgets/button';
+import {MenuItem, PopupMenu2} from '../../frontend/widgets/menu';
export const COUNTER_TRACK_KIND = 'CounterTrack';
@@ -61,8 +67,8 @@ export interface Config {
name: string;
maximumValue?: number;
minimumValue?: number;
- startTs?: number;
- endTs?: number;
+ startTs?: TPTime;
+ endTs?: TPTime;
namespace: string;
trackId: number;
scale?: CounterScaleOptions;
@@ -75,18 +81,16 @@ class CounterTrackController extends TrackController<Config, Data> {
private minimumValueSeen = 0;
private maximumDeltaSeen = 0;
private minimumDeltaSeen = 0;
- private maxDurNs = 0;
+ private maxDurNs: TPDuration = 0n;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNs(start);
- const endNs = toNs(end);
-
const pxSize = this.pxSize();
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
- const bucketNs = Math.max(Math.round(resolution * 1e9 * pxSize / 2) * 2, 1);
+ const bucketNs =
+ Math.max(Math.round(Number(resolution) * pxSize / 2) * 2, 1);
if (!this.setup) {
if (this.config.namespace === undefined) {
@@ -122,7 +126,7 @@ class CounterTrackController extends TrackController<Config, Data> {
) as maxDur
from ${this.tableName('counter_view')}
`);
- this.maxDurNs = maxDurResult.firstRow({maxDur: NUM_NULL}).maxDur || 0;
+ this.maxDurNs = maxDurResult.firstRow({maxDur: LONG_NULL}).maxDur || 0n;
const queryRes = await this.query(`
select
@@ -150,7 +154,7 @@ class CounterTrackController extends TrackController<Config, Data> {
value_at_max_ts(ts, id) as lastId,
value_at_max_ts(ts, value) as lastValue
from ${this.tableName('counter_view')}
- where ts >= ${startNs - this.maxDurNs} and ts <= ${endNs}
+ where ts >= ${start - this.maxDurNs} and ts <= ${end}
group by tsq
order by tsq
`);
@@ -259,18 +263,11 @@ class CounterTrack extends Track<Config, Data> {
{name: 'DELTA_FROM_PREVIOUS', humanName: 'Delta'},
{name: 'RATE', humanName: 'Rate'},
];
- const items: PopupMenuItem[] = [];
- for (const scale of scales) {
- let text;
- if (currentScale === scale.name) {
- text = `*${scale.humanName}*`;
- } else {
- text = scale.humanName;
- }
- items.push({
- itemType: 'regular',
- text,
- callback: () => {
+ const menuItems = scales.map((scale) => {
+ return m(MenuItem, {
+ label: scale.humanName,
+ active: currentScale === scale.name,
+ onclick: () => {
this.config.scale = scale.name;
Actions.updateTrackConfig({
id: this.trackState.id,
@@ -278,16 +275,23 @@ class CounterTrack extends Track<Config, Data> {
});
},
});
- }
- return m(PopupMenuButton, {
- icon: 'show_chart',
- items,
});
+
+ return m(
+ PopupMenu2,
+ {
+ trigger: m(Button, {icon: 'show_chart', minimal: true}),
+ },
+ menuItems,
+ );
}
renderCanvas(ctx: CanvasRenderingContext2D): void {
// TODO: fonts and colors should come from the CSS and not hardcoded here.
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {
+ visibleTimeScale: timeScale,
+ windowSpan,
+ } = globals.frontendLocalState;
const data = this.data();
// Can't possibly draw anything.
@@ -323,7 +327,7 @@ class CounterTrack extends Track<Config, Data> {
minimumValue = data.minimumRate;
}
- const endPx = Math.floor(timeScale.timeToPx(visibleWindowTime.end));
+ const endPx = windowSpan.end;
const zeroY = MARGIN_TOP + RECT_HEIGHT / (minimumValue < 0 ? 2 : 1);
// Quantize the Y axis to quarters of powers of tens (7.5K, 10K, 12.5K).
@@ -368,7 +372,7 @@ class CounterTrack extends Track<Config, Data> {
ctx.strokeStyle = `hsl(${hue}, 45%, 45%)`;
const calculateX = (ts: number) => {
- return Math.floor(timeScale.timeToPx(ts));
+ return Math.floor(timeScale.secondsToPx(ts));
};
const calculateY = (value: number) => {
return MARGIN_TOP + RECT_HEIGHT -
@@ -429,10 +433,10 @@ class CounterTrack extends Track<Config, Data> {
ctx.fillStyle = `hsl(${hue}, 45%, 75%)`;
ctx.strokeStyle = `hsl(${hue}, 45%, 45%)`;
- const xStart = Math.floor(timeScale.timeToPx(this.hoveredTs));
+ const xStart = Math.floor(timeScale.secondsToPx(this.hoveredTs));
const xEnd = this.hoveredTsEnd === undefined ?
endPx :
- Math.floor(timeScale.timeToPx(this.hoveredTsEnd));
+ Math.floor(timeScale.secondsToPx(this.hoveredTsEnd));
const y = MARGIN_TOP + RECT_HEIGHT -
Math.round(((this.hoveredValue - yMin) / yRange) * RECT_HEIGHT);
@@ -465,9 +469,10 @@ class CounterTrack extends Track<Config, Data> {
// TODO(hjd): Refactor this into checkerboardExcept
{
- const endPx = timeScale.timeToPx(visibleWindowTime.end);
- const counterEndPx =
- Math.min(timeScale.timeToPx(this.config.endTs || Infinity), endPx);
+ let counterEndPx = Infinity;
+ if (this.config.endTs) {
+ counterEndPx = Math.min(timeScale.tpTimeToPx(this.config.endTs), endPx);
+ }
// Grey out RHS.
if (counterEndPx < endPx) {
@@ -481,18 +486,18 @@ class CounterTrack extends Track<Config, Data> {
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(visibleWindowTime.start),
- timeScale.timeToPx(visibleWindowTime.end),
- timeScale.timeToPx(data.start),
- timeScale.timeToPx(data.end));
+ windowSpan.start,
+ windowSpan.end,
+ timeScale.tpTimeToPx(data.start),
+ timeScale.tpTimeToPx(data.end));
}
onMouseMove(pos: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return;
this.mousePos = pos;
- const {timeScale} = globals.frontendLocalState;
- const time = timeScale.pxToTime(pos.x);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const time = visibleTimeScale.pxToHpTime(pos.x).seconds;
const values = this.config.scale === 'DELTA_FROM_PREVIOUS' ?
data.totalDeltas :
@@ -511,8 +516,8 @@ class CounterTrack extends Track<Config, Data> {
onMouseClick({x}: {x: number}) {
const data = this.data();
if (data === undefined) return false;
- const {timeScale} = globals.frontendLocalState;
- const time = timeScale.pxToTime(x);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const time = visibleTimeScale.pxToHpTime(x).seconds;
const [left, right] = searchSegment(data.timestamps, time);
if (left === -1) {
return false;
@@ -520,8 +525,8 @@ class CounterTrack extends Track<Config, Data> {
const counterId = data.lastIds[left];
if (counterId === -1) return true;
globals.makeSelection(Actions.selectCounter({
- leftTs: toNs(data.timestamps[left]),
- rightTs: right !== -1 ? toNs(data.timestamps[right]) : -1,
+ leftTs: tpTimeFromSeconds(data.timestamps[left]),
+ rightTs: tpTimeFromSeconds(right !== -1 ? data.timestamps[right] : -1),
id: counterId,
trackId: this.trackState.id,
}));
diff --git a/ui/src/tracks/cpu_freq/index.ts b/ui/src/tracks/cpu_freq/index.ts
index 8bb2e3b58..795617281 100644
--- a/ui/src/tracks/cpu_freq/index.ts
+++ b/ui/src/tracks/cpu_freq/index.ts
@@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../../base/bigint_math';
import {searchSegment} from '../../base/binary_search';
import {assertTrue} from '../../base/logging';
import {hueForCpu} from '../../common/colorizer';
import {PluginContext} from '../../common/plugin_api';
import {NUM, NUM_NULL, QueryResult} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {fromNs, TPDuration, TPTime, tpTimeToNanos} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
@@ -96,15 +97,17 @@ class CpuFreqTrackController extends TrackController<Config, Data> {
this.cachedBucketNs = bucketNs;
}
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
// The resolution should always be a power of two for the logic of this
// function to make sense.
- const resolutionNs = toNs(resolution);
- assertTrue(Math.log2(resolutionNs) % 1 === 0);
+ assertTrue(
+ BigintMath.popcount(resolution) === 1,
+ `${resolution} is not a power of 2`);
+ const resolutionNs = Number(resolution);
- const startNs = toNs(start);
- const endNs = toNs(end);
+ const startNs = tpTimeToNanos(start);
+ const endNs = tpTimeToNanos(end);
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
@@ -289,7 +292,11 @@ class CpuFreqTrack extends Track<Config, Data> {
renderCanvas(ctx: CanvasRenderingContext2D): void {
// TODO: fonts and colors should come from the CSS and not hardcoded here.
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {
+ visibleTimeScale,
+ visibleWindowTime,
+ windowSpan,
+ } = globals.frontendLocalState;
const data = this.data();
if (data === undefined || data.timestamps.length === 0) {
@@ -302,7 +309,7 @@ class CpuFreqTrack extends Track<Config, Data> {
assertTrue(data.timestamps.length === data.maxFreqKHz.length);
assertTrue(data.timestamps.length === data.lastIdleValues.length);
- const endPx = timeScale.timeToPx(visibleWindowTime.end);
+ const endPx = windowSpan.end;
const zeroY = MARGIN_TOP + RECT_HEIGHT;
// Quantize the Y axis to quarters of powers of tens (7.5K, 10K, 12.5K).
@@ -326,17 +333,18 @@ class CpuFreqTrack extends Track<Config, Data> {
ctx.strokeStyle = `hsl(${hue}, ${saturation}%, 55%)`;
const calculateX = (timestamp: number) => {
- return Math.floor(timeScale.timeToPx(timestamp));
+ return Math.floor(visibleTimeScale.secondsToPx(timestamp));
};
const calculateY = (value: number) => {
return zeroY - Math.round((value / yMax) * RECT_HEIGHT);
};
- const [rawStartIdx] =
- searchSegment(data.timestamps, visibleWindowTime.start);
+ const startSec = visibleWindowTime.start.seconds;
+ const endSec = visibleWindowTime.end.seconds;
+ const [rawStartIdx] = searchSegment(data.timestamps, startSec);
const startIdx = rawStartIdx === -1 ? 0 : rawStartIdx;
- const [, rawEndIdx] = searchSegment(data.timestamps, visibleWindowTime.end);
+ const [, rawEndIdx] = searchSegment(data.timestamps, endSec);
const endIdx = rawEndIdx === -1 ? data.timestamps.length : rawEndIdx;
ctx.beginPath();
@@ -383,10 +391,10 @@ class CpuFreqTrack extends Track<Config, Data> {
// coordinates. Instead we use floating point which prevents flickering as
// we pan and zoom; this relies on the browser anti-aliasing pixels
// correctly.
- const x = timeScale.timeToPx(data.timestamps[i]);
+ const x = visibleTimeScale.secondsToPx(data.timestamps[i]);
const xEnd = i === data.lastIdleValues.length - 1 ?
finalX :
- timeScale.timeToPx(data.timestamps[i + 1]);
+ visibleTimeScale.secondsToPx(data.timestamps[i + 1]);
const width = xEnd - x;
const height = calculateY(data.lastFreqKHz[i]) - zeroY;
@@ -402,10 +410,10 @@ class CpuFreqTrack extends Track<Config, Data> {
ctx.fillStyle = `hsl(${hue}, 45%, 75%)`;
ctx.strokeStyle = `hsl(${hue}, 45%, 45%)`;
- const xStart = Math.floor(timeScale.timeToPx(this.hoveredTs));
+ const xStart = Math.floor(visibleTimeScale.secondsToPx(this.hoveredTs));
const xEnd = this.hoveredTsEnd === undefined ?
endPx :
- Math.floor(timeScale.timeToPx(this.hoveredTsEnd));
+ Math.floor(visibleTimeScale.secondsToPx(this.hoveredTsEnd));
const y = zeroY - Math.round((this.hoveredValue / yMax) * RECT_HEIGHT);
// Highlight line.
@@ -446,18 +454,18 @@ class CpuFreqTrack extends Track<Config, Data> {
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(visibleWindowTime.start),
- timeScale.timeToPx(visibleWindowTime.end),
- timeScale.timeToPx(data.start),
- timeScale.timeToPx(data.end));
+ windowSpan.start,
+ windowSpan.end,
+ visibleTimeScale.tpTimeToPx(data.start),
+ visibleTimeScale.tpTimeToPx(data.end));
}
onMouseMove(pos: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return;
this.mousePos = pos;
- const {timeScale} = globals.frontendLocalState;
- const time = timeScale.pxToTime(pos.x);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const time = visibleTimeScale.pxToHpTime(pos.x).seconds;
const [left, right] = searchSegment(data.timestamps, time);
this.hoveredTs = left === -1 ? undefined : data.timestamps[left];
diff --git a/ui/src/tracks/cpu_profile/index.ts b/ui/src/tracks/cpu_profile/index.ts
index eee7b17fc..028d5b112 100644
--- a/ui/src/tracks/cpu_profile/index.ts
+++ b/ui/src/tracks/cpu_profile/index.ts
@@ -18,7 +18,7 @@ import {Actions} from '../../common/actions';
import {hslForSlice} from '../../common/colorizer';
import {PluginContext} from '../../common/plugin_api';
import {NUM} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {fromNs, TPDuration, TPTime} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
@@ -46,7 +46,7 @@ export interface Config {
class CpuProfileTrackController extends TrackController<Config, Data> {
static readonly kind = CPU_PROFILE_TRACK_KIND;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
const query = `select
id,
@@ -105,7 +105,7 @@ class CpuProfileTrack extends Track<Config, Data> {
renderCanvas(ctx: CanvasRenderingContext2D): void {
const {
- timeScale,
+ visibleTimeScale: timeScale,
} = globals.frontendLocalState;
const data = this.data();
@@ -120,7 +120,7 @@ class CpuProfileTrack extends Track<Config, Data> {
const strokeWidth = isSelected ? 3 : 0;
this.drawMarker(
ctx,
- timeScale.timeToPx(fromNs(centerX)),
+ timeScale.secondsToPx(fromNs(centerX)),
this.centerY,
isHovered,
strokeWidth,
@@ -146,8 +146,8 @@ class CpuProfileTrack extends Track<Config, Data> {
if (clusterStartIndex !== clusterEndIndex) {
const startX = data.tsStarts[clusterStartIndex];
const endX = data.tsStarts[clusterEndIndex];
- const leftPx = timeScale.timeToPx(fromNs(startX)) - this.markerWidth;
- const rightPx = timeScale.timeToPx(fromNs(endX)) + this.markerWidth;
+ const leftPx = timeScale.secondsToPx(fromNs(startX)) - this.markerWidth;
+ const rightPx = timeScale.secondsToPx(fromNs(endX)) + this.markerWidth;
const width = rightPx - leftPx;
ctx.fillStyle = colorForSample(callsiteId, false);
ctx.fillRect(leftPx, MARGIN_TOP, width, BAR_HEIGHT);
@@ -179,8 +179,10 @@ class CpuProfileTrack extends Track<Config, Data> {
onMouseMove({x, y}: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return;
- const {timeScale} = globals.frontendLocalState;
- const time = toNs(timeScale.pxToTime(x));
+ const {
+ visibleTimeScale: timeScale,
+ } = globals.frontendLocalState;
+ const time = timeScale.pxToHpTime(x).nanos;
const [left, right] = searchSegment(data.tsStarts, time);
const index = this.findTimestampIndex(left, timeScale, data, x, y, right);
this.hoveredTs = index === -1 ? undefined : data.tsStarts[index];
@@ -193,9 +195,11 @@ class CpuProfileTrack extends Track<Config, Data> {
onMouseClick({x, y}: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return false;
- const {timeScale} = globals.frontendLocalState;
+ const {
+ visibleTimeScale: timeScale,
+ } = globals.frontendLocalState;
- const time = toNs(timeScale.pxToTime(x));
+ const time = timeScale.pxToHpTime(x).nanos;
const [left, right] = searchSegment(data.tsStarts, time);
const index = this.findTimestampIndex(left, timeScale, data, x, y, right);
@@ -217,13 +221,13 @@ class CpuProfileTrack extends Track<Config, Data> {
right: number): number {
let index = -1;
if (left !== -1) {
- const centerX = timeScale.timeToPx(fromNs(data.tsStarts[left]));
+ const centerX = timeScale.secondsToPx(fromNs(data.tsStarts[left]));
if (this.isInMarker(x, y, centerX)) {
index = left;
}
}
if (right !== -1) {
- const centerX = timeScale.timeToPx(fromNs(data.tsStarts[right]));
+ const centerX = timeScale.secondsToPx(fromNs(data.tsStarts[right]));
if (this.isInMarker(x, y, centerX)) {
index = right;
}
diff --git a/ui/src/tracks/cpu_slices/index.ts b/ui/src/tracks/cpu_slices/index.ts
index 0953d2ff1..4264069a9 100644
--- a/ui/src/tracks/cpu_slices/index.ts
+++ b/ui/src/tracks/cpu_slices/index.ts
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../../base/bigint_math';
import {search, searchEq, searchSegment} from '../../base/binary_search';
import {assertTrue} from '../../base/logging';
import {Actions} from '../../common/actions';
@@ -23,7 +24,15 @@ import {
import {colorForThread} from '../../common/colorizer';
import {PluginContext} from '../../common/plugin_api';
import {NUM} from '../../common/query_result';
-import {fromNs, timeToString, toNs} from '../../common/time';
+import {
+ fromNs,
+ toNs,
+ TPDuration,
+ TPTime,
+ tpTimeFromSeconds,
+ tpTimeToNanos,
+ tpTimeToString,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
@@ -102,16 +111,19 @@ class CpuSliceTrackController extends TrackController<Config, Data> {
this.cachedBucketNs = bucketNs;
}
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const resolutionNs = toNs(resolution);
+ assertTrue(
+ BigintMath.popcount(resolution) === 1,
+ `${resolution} is not a power of 2`);
+ const resolutionNs = Number(resolution);
// The resolution should always be a power of two for the logic of this
// function to make sense.
assertTrue(Math.log2(resolutionNs) % 1 === 0);
- const boundStartNs = toNs(start);
- const boundEndNs = toNs(end);
+ const boundStartNs = tpTimeToNanos(start);
+ const boundEndNs = tpTimeToNanos(end);
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
@@ -223,7 +235,7 @@ class CpuSliceTrack extends Track<Config, Data> {
renderCanvas(ctx: CanvasRenderingContext2D): void {
// TODO: fonts and colors should come from the CSS and not hardcoded here.
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {visibleTimeScale, windowSpan} = globals.frontendLocalState;
const data = this.data();
if (data === undefined) return; // Can't possibly draw anything.
@@ -233,28 +245,35 @@ class CpuSliceTrack extends Track<Config, Data> {
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(visibleWindowTime.start),
- timeScale.timeToPx(visibleWindowTime.end),
- timeScale.timeToPx(data.start),
- timeScale.timeToPx(data.end));
+ windowSpan.start,
+ windowSpan.end,
+ visibleTimeScale.tpTimeToPx(data.start),
+ visibleTimeScale.tpTimeToPx(data.end));
this.renderSlices(ctx, data);
}
renderSlices(ctx: CanvasRenderingContext2D, data: Data): void {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {
+ visibleTimeScale,
+ visibleWindowTime,
+ } = globals.frontendLocalState;
assertTrue(data.starts.length === data.ends.length);
assertTrue(data.starts.length === data.utids.length);
+ const visWindowEndPx = visibleTimeScale.hpTimeToPx(visibleWindowTime.end);
+
ctx.textAlign = 'center';
ctx.font = '12px Roboto Condensed';
const charWidth = ctx.measureText('dbpqaouk').width / 8;
- const rawStartIdx =
- data.ends.findIndex((end) => end >= visibleWindowTime.start);
+ const startSec = visibleWindowTime.start.seconds;
+ const endSec = visibleWindowTime.end.seconds;
+
+ const rawStartIdx = data.ends.findIndex((end) => end >= startSec);
const startIdx = rawStartIdx === -1 ? 0 : rawStartIdx;
- const [, rawEndIdx] = searchSegment(data.starts, visibleWindowTime.end);
+ const [, rawEndIdx] = searchSegment(data.starts, endSec);
const endIdx = rawEndIdx === -1 ? data.starts.length : rawEndIdx;
for (let i = startIdx; i < endIdx; i++) {
@@ -266,10 +285,10 @@ class CpuSliceTrack extends Track<Config, Data> {
// window, else it might spill over the window and the end would not be
// visible as a zigzag line.
if (data.ids[i] === data.lastRowId && data.isIncomplete[i]) {
- tEnd = visibleWindowTime.end;
+ tEnd = visibleWindowTime.end.seconds;
}
- const rectStart = timeScale.timeToPx(tStart);
- const rectEnd = timeScale.timeToPx(tEnd);
+ const rectStart = visibleTimeScale.secondsToPx(tStart);
+ const rectEnd = visibleTimeScale.secondsToPx(tEnd);
const rectWidth = Math.max(1, rectEnd - rectStart);
const threadInfo = globals.threads.get(utid);
@@ -317,8 +336,7 @@ class CpuSliceTrack extends Track<Config, Data> {
title = `${threadInfo.threadName} [${threadInfo.tid}]`;
}
}
- const right =
- Math.min(timeScale.timeToPx(visibleWindowTime.end), rectEnd);
+ const right = Math.min(visWindowEndPx, rectEnd);
const left = Math.max(rectStart, 0);
const visibleWidth = Math.max(right - left, 1);
title = cropText(title, charWidth, visibleWidth);
@@ -341,8 +359,8 @@ class CpuSliceTrack extends Track<Config, Data> {
const tEnd = data.ends[startIndex];
const utid = data.utids[startIndex];
const color = colorForThread(globals.threads.get(utid));
- const rectStart = timeScale.timeToPx(tStart);
- const rectEnd = timeScale.timeToPx(tEnd);
+ const rectStart = visibleTimeScale.secondsToPx(tStart);
+ const rectEnd = visibleTimeScale.secondsToPx(tEnd);
const rectWidth = Math.max(1, rectEnd - rectStart);
// Draw a rectangle around the slice that is currently selected.
@@ -353,7 +371,7 @@ class CpuSliceTrack extends Track<Config, Data> {
ctx.closePath();
// Draw arrow from wakeup time of current slice.
if (details.wakeupTs) {
- const wakeupPos = timeScale.timeToPx(details.wakeupTs);
+ const wakeupPos = visibleTimeScale.tpTimeToPx(details.wakeupTs);
const latencyWidth = rectStart - wakeupPos;
drawDoubleHeadedArrow(
ctx,
@@ -362,7 +380,8 @@ class CpuSliceTrack extends Track<Config, Data> {
latencyWidth,
latencyWidth >= 20);
// Latency time with a white semi-transparent background.
- const displayText = timeToString(tStart - details.wakeupTs);
+ const latency = tpTimeFromSeconds(tStart) - details.wakeupTs;
+ const displayText = tpTimeToString(latency);
const measured = ctx.measureText(displayText);
if (latencyWidth >= measured.width + 2) {
ctx.fillStyle = 'rgba(255,255,255,0.7)';
@@ -383,7 +402,8 @@ class CpuSliceTrack extends Track<Config, Data> {
// Draw diamond if the track being drawn is the cpu of the waker.
if (this.config.cpu === details.wakerCpu && details.wakeupTs) {
- const wakeupPos = Math.floor(timeScale.timeToPx(details.wakeupTs));
+ const wakeupPos =
+ Math.floor(visibleTimeScale.tpTimeToPx(details.wakeupTs));
ctx.beginPath();
ctx.moveTo(wakeupPos, MARGIN_TOP + RECT_HEIGHT / 2 + 8);
ctx.fillStyle = 'black';
@@ -411,13 +431,13 @@ class CpuSliceTrack extends Track<Config, Data> {
const data = this.data();
this.mousePos = pos;
if (data === undefined) return;
- const {timeScale} = globals.frontendLocalState;
+ const {visibleTimeScale} = globals.frontendLocalState;
if (pos.y < MARGIN_TOP || pos.y > MARGIN_TOP + RECT_HEIGHT) {
this.utidHoveredInThisTrack = -1;
globals.dispatch(Actions.setHoveredUtidAndPid({utid: -1, pid: -1}));
return;
}
- const t = timeScale.pxToTime(pos.x);
+ const t = visibleTimeScale.pxToHpTime(pos.x).seconds;
let hoveredUtid = -1;
for (let i = 0; i < data.starts.length; i++) {
@@ -445,8 +465,8 @@ class CpuSliceTrack extends Track<Config, Data> {
onMouseClick({x}: {x: number}) {
const data = this.data();
if (data === undefined) return false;
- const {timeScale} = globals.frontendLocalState;
- const time = timeScale.pxToTime(x);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const time = visibleTimeScale.pxToHpTime(x).seconds;
const index = search(data.starts, time);
const id = index === -1 ? undefined : data.ids[index];
if (!id || this.utidHoveredInThisTrack === -1) return false;
diff --git a/ui/src/tracks/debug/add_debug_track_menu.ts b/ui/src/tracks/debug/add_debug_track_menu.ts
index 8b0441562..d14bfd85d 100644
--- a/ui/src/tracks/debug/add_debug_track_menu.ts
+++ b/ui/src/tracks/debug/add_debug_track_menu.ts
@@ -16,9 +16,10 @@ import m from 'mithril';
import {EngineProxy} from '../../common/engine';
import {Button} from '../../frontend/widgets/button';
+import {Form, FormButtonBar, FormLabel} from '../../frontend/widgets/form';
import {Select} from '../../frontend/widgets/select';
import {TextInput} from '../../frontend/widgets/text_input';
-import {Tree, TreeNode} from '../../frontend/widgets/tree';
+
import {addDebugTrack, SliceColumns} from './slice_track';
export const ARG_PREFIX = 'arg_';
@@ -67,51 +68,59 @@ export class AddDebugTrackMenu implements
},
column));
}
- return m(TreeNode, {
- left: name,
- right: m(
- Select,
- {
- oninput: (e: Event) => {
- if (!e.target) return;
- this.sliceColumns[name] = (e.target as HTMLSelectElement).value;
- },
+ return [
+ m(FormLabel,
+ {for: name,
+ },
+ name),
+ m(Select,
+ {
+ id: name,
+ oninput: (e: Event) => {
+ if (!e.target) return;
+ this.sliceColumns[name] = (e.target as HTMLSelectElement).value;
},
- options),
- });
+ },
+ options),
+ ];
};
- return [
- m(
- Tree,
- m(TreeNode, {
- left: 'Name',
- right: m(TextInput, {
- onkeydown: (e: KeyboardEvent) => {
- // Allow Esc to close popup.
- if (e.key === 'Escape') return;
- e.stopPropagation();
- },
- oninput: (e: KeyboardEvent) => {
- if (!e.target) return;
- this.name = (e.target as HTMLInputElement).value;
+ return m(
+ Form,
+ m(FormLabel,
+ {for: 'track_name',
+ },
+ 'Name'),
+ m(TextInput, {
+ id: 'track_name',
+ onkeydown: (e: KeyboardEvent) => {
+ // Allow Esc to close popup.
+ if (e.key === 'Escape') return;
+ e.stopPropagation();
+ },
+ oninput: (e: KeyboardEvent) => {
+ if (!e.target) return;
+ this.name = (e.target as HTMLInputElement).value;
+ },
+ }),
+ renderSelect('ts'),
+ renderSelect('dur'),
+ renderSelect('name'),
+ m(
+ FormButtonBar,
+ m(Button, {
+ label: 'Show',
+ dismissPopup: true,
+ onclick: (e: Event) => {
+ e.preventDefault();
+ addDebugTrack(
+ vnode.attrs.engine,
+ vnode.attrs.sqlViewName,
+ this.name,
+ this.sliceColumns,
+ vnode.attrs.columns);
},
}),
- }),
- renderSelect('ts'),
- renderSelect('dur'),
- renderSelect('name'),
- ),
- m(Button, {
- label: 'Show',
- onclick: () => {
- addDebugTrack(
- vnode.attrs.engine,
- vnode.attrs.sqlViewName,
- this.name,
- this.sliceColumns,
- vnode.attrs.columns);
- },
- }),
- ];
+ ),
+ );
}
}
diff --git a/ui/src/tracks/debug/details_tab.ts b/ui/src/tracks/debug/details_tab.ts
index c168eb6c4..50c231985 100644
--- a/ui/src/tracks/debug/details_tab.ts
+++ b/ui/src/tracks/debug/details_tab.ts
@@ -15,19 +15,21 @@
import m from 'mithril';
import {ColumnType} from '../../common/query_result';
+import {tpDurationFromSql, tpTimeFromSql} from '../../common/time';
import {
BottomTab,
bottomTabRegistry,
NewBottomTabArgs,
} from '../../frontend/bottom_tab';
import {globals} from '../../frontend/globals';
-import {timestampFromSqlNanos} from '../../frontend/sql_types';
+import {asTPTimestamp} from '../../frontend/sql_types';
import {Duration} from '../../frontend/widgets/duration';
import {Timestamp} from '../../frontend/widgets/timestamp';
-import {Tree, TreeNode} from '../../frontend/widgets/tree';
+import {dictToTree} from '../../frontend/widgets/tree';
+
import {ARG_PREFIX} from './add_debug_track_menu';
-interface DebugSliceDetalsTabConfig {
+interface DebugSliceDetailsTabConfig {
sqlTableName: string;
id: number;
}
@@ -42,18 +44,8 @@ function SqlValueToString(val: ColumnType) {
return val.toString();
}
-function dictToTree(dict: {[key: string]: m.Child}): m.Children {
- const children: m.Child[] = [];
- for (const key of Object.keys(dict)) {
- children.push(m(TreeNode, {
- left: key,
- right: dict[key],
- }));
- }
- return m(Tree, children);
-}
-
-export class DebugSliceDetailsTab extends BottomTab<DebugSliceDetalsTabConfig> {
+export class DebugSliceDetailsTab extends
+ BottomTab<DebugSliceDetailsTabConfig> {
static readonly kind = 'org.perfetto.DebugSliceDetailsTab';
data: {[key: string]: ColumnType}|undefined;
@@ -78,12 +70,11 @@ export class DebugSliceDetailsTab extends BottomTab<DebugSliceDetalsTabConfig> {
if (this.data === undefined) {
return m('h2', 'Loading');
}
- // TODO(stevegolton): These type assertions are dangerous, but no more
- // dangerous than they used to be before this change.
const left = dictToTree({
'Name': this.data['name'] as string,
- 'Start time': m(Timestamp, {ts: timestampFromSqlNanos(this.data['ts'])}),
- 'Duration': m(Duration, {dur: Number(this.data['dur'])}),
+ 'Start time':
+ m(Timestamp, {ts: asTPTimestamp(tpTimeFromSql(this.data['ts']))}),
+ 'Duration': m(Duration, {dur: tpDurationFromSql(this.data['dur'])}),
'Debug slice id': `${this.config.sqlTableName}[${this.config.id}]`,
});
const args: {[key: string]: m.Child} = {};
@@ -93,7 +84,7 @@ export class DebugSliceDetailsTab extends BottomTab<DebugSliceDetalsTabConfig> {
}
}
return m(
- 'div.details-panel',
+ '.details-panel',
m('header.overview', m('span', 'Debug Slice')),
m('.details-table-multicolumn',
{
diff --git a/ui/src/tracks/debug/slice_track.ts b/ui/src/tracks/debug/slice_track.ts
index a871a9fae..664840dd4 100644
--- a/ui/src/tracks/debug/slice_track.ts
+++ b/ui/src/tracks/debug/slice_track.ts
@@ -78,8 +78,8 @@ export class DebugTrackV2 extends NamedSliceTrack<DebugTrackV2Types> {
globals.dispatch(Actions.selectDebugSlice({
id: args.slice.id,
sqlTableName: this.config.sqlTableName,
- startS: args.slice.startS,
- durationS: args.slice.durationS,
+ start: args.slice.start,
+ duration: args.slice.duration,
trackId: this.trackId,
}));
}
diff --git a/ui/src/tracks/expected_frames/index.ts b/ui/src/tracks/expected_frames/index.ts
index f2ab086b4..f7e5121d8 100644
--- a/ui/src/tracks/expected_frames/index.ts
+++ b/ui/src/tracks/expected_frames/index.ts
@@ -19,8 +19,8 @@ export const EXPECTED_FRAMES_SLICE_TRACK_KIND = 'ExpectedFramesSliceTrack';
import {NewTrackArgs, Track} from '../../frontend/track';
import {ChromeSliceTrack} from '../chrome_slices';
-import {NUM, NUM_NULL, STR} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {LONG_NULL, NUM, STR} from '../../common/query_result';
+import {TPDuration, TPTime, fromNs} from '../../common/time';
import {
TrackController,
} from '../../controller/track_controller';
@@ -46,27 +46,25 @@ export interface Data extends TrackData {
class ExpectedFramesSliceTrackController extends TrackController<Config, Data> {
static readonly kind = EXPECTED_FRAMES_SLICE_TRACK_KIND;
- private maxDurNs = 0;
+ private maxDurNs: TPDuration = 0n;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNs(start);
- const endNs = toNs(end);
-
const pxSize = this.pxSize();
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
- const bucketNs = Math.max(Math.round(resolution * 1e9 * pxSize / 2) * 2, 1);
+ const bucketNs =
+ Math.max(Math.round(Number(resolution) * pxSize / 2) * 2, 1);
- if (this.maxDurNs === 0) {
+ if (this.maxDurNs === 0n) {
const maxDurResult = await this.query(`
select max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur))
as maxDur
from experimental_slice_layout
where filter_track_ids = '${this.config.trackIds.join(',')}'
`);
- this.maxDurNs = maxDurResult.firstRow({maxDur: NUM_NULL}).maxDur || 0;
+ this.maxDurNs = maxDurResult.firstRow({maxDur: LONG_NULL}).maxDur || 0n;
}
const queryRes = await this.query(`
@@ -82,8 +80,8 @@ class ExpectedFramesSliceTrackController extends TrackController<Config, Data> {
from experimental_slice_layout
where
filter_track_ids = '${this.config.trackIds.join(',')}' and
- ts >= ${startNs - this.maxDurNs} and
- ts <= ${endNs}
+ ts >= ${start - this.maxDurNs} and
+ ts <= ${end}
group by tsq, layout_depth
order by tsq, layout_depth
`);
diff --git a/ui/src/tracks/ftrace/index.ts b/ui/src/tracks/ftrace/index.ts
index e82934dae..8cd40f330 100644
--- a/ui/src/tracks/ftrace/index.ts
+++ b/ui/src/tracks/ftrace/index.ts
@@ -17,7 +17,8 @@ import {Vnode} from 'mithril';
import {colorForString} from '../../common/colorizer';
import {PluginContext} from '../../common/plugin_api';
import {NUM, STR} from '../../common/query_result';
-import {fromNs, toNsCeil, toNsFloor} from '../../common/time';
+import {fromNs, TPDuration} from '../../common/time';
+import {TPTime} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {LIMIT} from '../../common/track_data';
import {
@@ -29,12 +30,7 @@ import {NewTrackArgs, Track} from '../../frontend/track';
export interface Data extends TrackData {
- // Total number of events within [start, end], before any quantization.
- numEvents: number;
-
- // Below: data quantized by resolution and aggregated by event priority.
timestamps: Float64Array;
-
names: string[];
}
@@ -51,14 +47,8 @@ const TRACK_HEIGHT = (RECT_HEIGHT) + (2 * MARGIN);
class FtraceRawTrackController extends TrackController<Config, Data> {
static readonly kind = FTRACE_RAW_TRACK_KIND;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNsFloor(start);
- const endNs = toNsCeil(end);
-
- // |resolution| is in s/px the frontend wants.
- const quantNs = toNsCeil(resolution);
-
const excludeList = Array.from(globals.state.ftraceFilter.excludedNames);
const excludeListSql = excludeList.map((s) => `'${s}'`).join(',');
const cpuFilter =
@@ -66,35 +56,32 @@ class FtraceRawTrackController extends TrackController<Config, Data> {
const queryRes = await this.query(`
select
- cast(ts / ${quantNs} as integer) * ${quantNs} as tsQuant,
+ cast(ts / ${resolution} as integer) * ${resolution} as tsQuant,
type,
- count(type) as numEvents,
name
from ftrace_event
where
name not in (${excludeListSql}) and
- ts >= ${startNs} and ts <= ${endNs} ${cpuFilter}
+ ts >= ${start} and ts <= ${end} ${cpuFilter}
group by tsQuant
order by tsQuant limit ${LIMIT};`);
const rowCount = queryRes.numRows();
- const result = {
+ const result: Data = {
start,
end,
resolution,
length: rowCount,
- numEvents: 0,
timestamps: new Float64Array(rowCount),
names: [],
- } as Data;
+ };
const it = queryRes.iter(
- {tsQuant: NUM, type: STR, numEvents: NUM, name: STR},
+ {tsQuant: NUM, type: STR, name: STR},
);
for (let row = 0; it.valid(); it.next(), row++) {
result.timestamps[row] = fromNs(it.tsQuant);
result.names[row] = it.name;
- result.numEvents += it.numEvents;
}
return result;
}
@@ -115,16 +102,19 @@ export class FtraceRawTrack extends Track<Config, Data> {
}
renderCanvas(ctx: CanvasRenderingContext2D): void {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {
+ visibleTimeScale,
+ windowSpan,
+ } = globals.frontendLocalState;
const data = this.data();
if (data === undefined) return; // Can't possibly draw anything.
- const dataStartPx = timeScale.timeToPx(data.start);
- const dataEndPx = timeScale.timeToPx(data.end);
- const visibleStartPx = timeScale.timeToPx(visibleWindowTime.start);
- const visibleEndPx = timeScale.timeToPx(visibleWindowTime.end);
+ const dataStartPx = visibleTimeScale.tpTimeToPx(data.start);
+ const dataEndPx = visibleTimeScale.tpTimeToPx(data.end);
+ const visibleStartPx = windowSpan.start;
+ const visibleEndPx = windowSpan.end;
checkerboardExcept(
ctx,
@@ -145,7 +135,7 @@ export class FtraceRawTrack extends Track<Config, Data> {
${Math.min(color.l + 10, 60)}%
)`;
ctx.fillStyle = hsl;
- const xPos = Math.floor(timeScale.timeToPx(data.timestamps[i]));
+ const xPos = Math.floor(visibleTimeScale.secondsToPx(data.timestamps[i]));
// Draw a diamond over the event
ctx.save();
diff --git a/ui/src/tracks/heap_profile/index.ts b/ui/src/tracks/heap_profile/index.ts
index b3eb40ae4..3e656f03b 100644
--- a/ui/src/tracks/heap_profile/index.ts
+++ b/ui/src/tracks/heap_profile/index.ts
@@ -18,7 +18,13 @@ import {searchSegment} from '../../base/binary_search';
import {Actions} from '../../common/actions';
import {PluginContext} from '../../common/plugin_api';
import {NUM, STR} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {
+ fromNs,
+ TPDuration,
+ TPTime,
+ tpTimeFromNanos,
+ tpTimeFromSeconds,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {profileType} from '../../controller/flamegraph_controller';
import {
@@ -42,7 +48,7 @@ export interface Config {
class HeapProfileTrackController extends TrackController<Config, Data> {
static readonly kind = HEAP_PROFILE_TRACK_KIND;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
if (this.config.upid === undefined) {
return {
@@ -111,7 +117,7 @@ class HeapProfileTrack extends Track<Config, Data> {
renderCanvas(ctx: CanvasRenderingContext2D): void {
const {
- timeScale,
+ visibleTimeScale: timeScale,
} = globals.frontendLocalState;
const data = this.data();
@@ -122,11 +128,12 @@ class HeapProfileTrack extends Track<Config, Data> {
const selection = globals.state.currentSelection;
const isHovered = this.hoveredTs === centerX;
const isSelected = selection !== null &&
- selection.kind === 'HEAP_PROFILE' && selection.ts === centerX;
+ selection.kind === 'HEAP_PROFILE' &&
+ selection.ts === tpTimeFromSeconds(centerX);
const strokeWidth = isSelected ? 3 : 0;
this.drawMarker(
ctx,
- timeScale.timeToPx(fromNs(centerX)),
+ timeScale.secondsToPx(fromNs(centerX)),
this.centerY,
isHovered,
strokeWidth);
@@ -155,8 +162,10 @@ class HeapProfileTrack extends Track<Config, Data> {
onMouseMove({x, y}: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return;
- const {timeScale} = globals.frontendLocalState;
- const time = toNs(timeScale.pxToTime(x));
+ const {
+ visibleTimeScale: timeScale,
+ } = globals.frontendLocalState;
+ const time = timeScale.pxToHpTime(x).nanos;
const [left, right] = searchSegment(data.tsStarts, time);
const index = this.findTimestampIndex(left, timeScale, data, x, y, right);
this.hoveredTs = index === -1 ? undefined : data.tsStarts[index];
@@ -169,15 +178,18 @@ class HeapProfileTrack extends Track<Config, Data> {
onMouseClick({x, y}: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return false;
- const {timeScale} = globals.frontendLocalState;
+ const {
+ visibleTimeScale: timeScale,
+ } = globals.frontendLocalState;
- const time = toNs(timeScale.pxToTime(x));
+ const time = timeScale.pxToHpTime(x).nanos;
const [left, right] = searchSegment(data.tsStarts, time);
const index = this.findTimestampIndex(left, timeScale, data, x, y, right);
if (index !== -1) {
- const ts = data.tsStarts[index];
+ // TODO(stevegolton): Remove conversion from number to bigint.
+ const ts = tpTimeFromNanos(data.tsStarts[index]);
const type = data.types[index];
globals.makeSelection(Actions.selectHeapProfile(
{id: index, upid: this.config.upid, ts, type}));
@@ -192,13 +204,13 @@ class HeapProfileTrack extends Track<Config, Data> {
right: number): number {
let index = -1;
if (left !== -1) {
- const centerX = timeScale.timeToPx(fromNs(data.tsStarts[left]));
+ const centerX = timeScale.secondsToPx(fromNs(data.tsStarts[left]));
if (this.isInMarker(x, y, centerX)) {
index = left;
}
}
if (right !== -1) {
- const centerX = timeScale.timeToPx(fromNs(data.tsStarts[right]));
+ const centerX = timeScale.secondsToPx(fromNs(data.tsStarts[right]));
if (this.isInMarker(x, y, centerX)) {
index = right;
}
diff --git a/ui/src/tracks/perf_samples_profile/index.ts b/ui/src/tracks/perf_samples_profile/index.ts
index cfc73dd32..693e2953e 100644
--- a/ui/src/tracks/perf_samples_profile/index.ts
+++ b/ui/src/tracks/perf_samples_profile/index.ts
@@ -17,7 +17,12 @@ import {Actions} from '../../common/actions';
import {PluginContext} from '../../common/plugin_api';
import {NUM} from '../../common/query_result';
import {ProfileType} from '../../common/state';
-import {fromNs, toNs} from '../../common/time';
+import {
+ fromNs,
+ TPDuration,
+ TPTime,
+ tpTimeFromSeconds,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
@@ -39,7 +44,7 @@ export interface Config {
class PerfSamplesProfileTrackController extends TrackController<Config, Data> {
static readonly kind = PERF_SAMPLES_PROFILE_TRACK_KIND;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
if (this.config.upid === undefined) {
return {
@@ -99,7 +104,7 @@ class PerfSamplesProfileTrack extends Track<Config, Data> {
renderCanvas(ctx: CanvasRenderingContext2D): void {
const {
- timeScale,
+ visibleTimeScale,
} = globals.frontendLocalState;
const data = this.data();
@@ -115,7 +120,7 @@ class PerfSamplesProfileTrack extends Track<Config, Data> {
const strokeWidth = isSelected ? 3 : 0;
this.drawMarker(
ctx,
- timeScale.timeToPx(fromNs(centerX)),
+ visibleTimeScale.secondsToPx(fromNs(centerX)),
this.centerY,
isHovered,
strokeWidth);
@@ -144,10 +149,11 @@ class PerfSamplesProfileTrack extends Track<Config, Data> {
onMouseMove({x, y}: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return;
- const {timeScale} = globals.frontendLocalState;
- const time = toNs(timeScale.pxToTime(x));
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const time = visibleTimeScale.pxToHpTime(x).nanos;
const [left, right] = searchSegment(data.tsStartsNs, time);
- const index = this.findTimestampIndex(left, timeScale, data, x, y, right);
+ const index =
+ this.findTimestampIndex(left, visibleTimeScale, data, x, y, right);
this.hoveredTs = index === -1 ? undefined : data.tsStartsNs[index];
}
@@ -158,9 +164,11 @@ class PerfSamplesProfileTrack extends Track<Config, Data> {
onMouseClick({x, y}: {x: number, y: number}) {
const data = this.data();
if (data === undefined) return false;
- const {timeScale} = globals.frontendLocalState;
+ const {
+ visibleTimeScale: timeScale,
+ } = globals.frontendLocalState;
- const time = toNs(timeScale.pxToTime(x));
+ const time = timeScale.pxToHpTime(x).nanos;
const [left, right] = searchSegment(data.tsStartsNs, time);
const index = this.findTimestampIndex(left, timeScale, data, x, y, right);
@@ -170,8 +178,8 @@ class PerfSamplesProfileTrack extends Track<Config, Data> {
globals.makeSelection(Actions.selectPerfSamples({
id: index,
upid: this.config.upid,
- leftTs: ts,
- rightTs: ts,
+ leftTs: tpTimeFromSeconds(ts),
+ rightTs: tpTimeFromSeconds(ts),
type: ProfileType.PERF_SAMPLE,
}));
return true;
@@ -185,13 +193,13 @@ class PerfSamplesProfileTrack extends Track<Config, Data> {
right: number): number {
let index = -1;
if (left !== -1) {
- const centerX = timeScale.timeToPx(fromNs(data.tsStartsNs[left]));
+ const centerX = timeScale.secondsToPx(fromNs(data.tsStartsNs[left]));
if (this.isInMarker(x, y, centerX)) {
index = left;
}
}
if (right !== -1) {
- const centerX = timeScale.timeToPx(fromNs(data.tsStartsNs[right]));
+ const centerX = timeScale.secondsToPx(fromNs(data.tsStartsNs[right]));
if (this.isInMarker(x, y, centerX)) {
index = right;
}
diff --git a/ui/src/tracks/process_scheduling/index.ts b/ui/src/tracks/process_scheduling/index.ts
index 95302b6cd..d88bc71a2 100644
--- a/ui/src/tracks/process_scheduling/index.ts
+++ b/ui/src/tracks/process_scheduling/index.ts
@@ -12,13 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {BigintMath} from '../../base/bigint_math';
import {searchEq, searchRange, searchSegment} from '../../base/binary_search';
import {assertTrue} from '../../base/logging';
import {Actions} from '../../common/actions';
import {colorForThread} from '../../common/colorizer';
import {PluginContext} from '../../common/plugin_api';
import {NUM, QueryResult} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {
+ fromNs,
+ TPDuration,
+ TPTime,
+ tpTimeFromSeconds,
+ tpTimeToNanos,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {
TrackController,
@@ -91,22 +98,23 @@ class ProcessSchedulingTrackController extends TrackController<Config, Data> {
this.cachedBucketNs = bucketNs;
}
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
assertTrue(this.config.upid !== null);
// The resolution should always be a power of two for the logic of this
// function to make sense.
- const resolutionNs = toNs(resolution);
- assertTrue(Math.log2(resolutionNs) % 1 === 0);
+ assertTrue(
+ BigintMath.popcount(resolution) === 1,
+ `${resolution} is not a power of 2`);
- const startNs = toNs(start);
- const endNs = toNs(end);
+ const startNs = tpTimeToNanos(start);
+ const endNs = tpTimeToNanos(end);
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
const bucketNs =
- Math.max(Math.round(resolutionNs * this.pxSize() / 2) * 2, 1);
+ Math.max(Math.round(Number(resolution) * this.pxSize() / 2) * 2, 1);
const queryRes = await this.queryData(startNs, endNs, bucketNs);
const numRows = queryRes.numRows();
@@ -144,7 +152,8 @@ class ProcessSchedulingTrackController extends TrackController<Config, Data> {
slices.ends[row] = fromNs(endNsQ);
slices.cpus[row] = it.cpu;
slices.utids[row] = it.utid;
- slices.end = Math.max(slices.ends[row], slices.end);
+ slices.end =
+ BigintMath.max(tpTimeFromSeconds(slices.ends[row]), slices.end);
}
return slices;
}
@@ -208,7 +217,10 @@ class ProcessSchedulingTrack extends Track<Config, Data> {
renderCanvas(ctx: CanvasRenderingContext2D): void {
// TODO: fonts and colors should come from the CSS and not hardcoded here.
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {
+ visibleTimeScale,
+ visibleWindowTime,
+ } = globals.frontendLocalState;
const data = this.data();
if (data === undefined) return; // Can't possibly draw anything.
@@ -218,19 +230,20 @@ class ProcessSchedulingTrack extends Track<Config, Data> {
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(visibleWindowTime.start),
- timeScale.timeToPx(visibleWindowTime.end),
- timeScale.timeToPx(data.start),
- timeScale.timeToPx(data.end));
+ visibleTimeScale.hpTimeToPx(visibleWindowTime.start),
+ visibleTimeScale.hpTimeToPx(visibleWindowTime.end),
+ visibleTimeScale.tpTimeToPx(data.start),
+ visibleTimeScale.tpTimeToPx(data.end));
assertTrue(data.starts.length === data.ends.length);
assertTrue(data.starts.length === data.utids.length);
- const rawStartIdx =
- data.ends.findIndex((end) => end >= visibleWindowTime.start);
+ const startSeconds = visibleWindowTime.start.seconds;
+ const rawStartIdx = data.ends.findIndex((end) => end >= startSeconds);
const startIdx = rawStartIdx === -1 ? data.starts.length : rawStartIdx;
- const [, rawEndIdx] = searchSegment(data.starts, visibleWindowTime.end);
+ const [, rawEndIdx] =
+ searchSegment(data.starts, visibleWindowTime.end.seconds);
const endIdx = rawEndIdx === -1 ? data.starts.length : rawEndIdx;
const cpuTrackHeight = Math.floor(RECT_HEIGHT / data.maxCpu);
@@ -241,8 +254,8 @@ class ProcessSchedulingTrack extends Track<Config, Data> {
const utid = data.utids[i];
const cpu = data.cpus[i];
- const rectStart = timeScale.timeToPx(tStart);
- const rectEnd = timeScale.timeToPx(tEnd);
+ const rectStart = visibleTimeScale.secondsToPx(tStart);
+ const rectEnd = visibleTimeScale.secondsToPx(tEnd);
const rectWidth = rectEnd - rectStart;
if (rectWidth < 0.3) continue;
@@ -294,8 +307,8 @@ class ProcessSchedulingTrack extends Track<Config, Data> {
const cpuTrackHeight = Math.floor(RECT_HEIGHT / data.maxCpu);
const cpu = Math.floor((pos.y - MARGIN_TOP) / (cpuTrackHeight + 1));
- const {timeScale} = globals.frontendLocalState;
- const t = timeScale.pxToTime(pos.x);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const t = visibleTimeScale.pxToHpTime(pos.x).seconds;
const [i, j] = searchRange(data.starts, t, searchEq(data.cpus, cpu));
if (i === j || i >= data.starts.length || t > data.ends[i]) {
diff --git a/ui/src/tracks/process_summary/index.ts b/ui/src/tracks/process_summary/index.ts
index d2d0ee8fe..8b9251164 100644
--- a/ui/src/tracks/process_summary/index.ts
+++ b/ui/src/tracks/process_summary/index.ts
@@ -15,7 +15,14 @@
import {colorForTid} from '../../common/colorizer';
import {PluginContext} from '../../common/plugin_api';
import {NUM} from '../../common/query_result';
-import {fromNs, toNs} from '../../common/time';
+import {
+ fromNs,
+ TPDuration,
+ TPTime,
+ tpTimeFromNanos,
+ tpTimeToNanos,
+ tpTimeToSeconds,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {LIMIT} from '../../common/track_data';
import {
@@ -45,10 +52,10 @@ class ProcessSummaryTrackController extends TrackController<Config, Data> {
static readonly kind = PROCESS_SUMMARY_TRACK;
private setup = false;
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const startNs = toNs(start);
- const endNs = toNs(end);
+ const startNs = tpTimeToNanos(start);
+ const endNs = tpTimeToNanos(end);
if (this.setup === false) {
await this.query(
@@ -85,9 +92,9 @@ class ProcessSummaryTrackController extends TrackController<Config, Data> {
this.setup = true;
}
- // |resolution| is in s/px we want # ns for 10px window:
+ // |resolution| is in ns/px we want # ns for 10px window:
// Max value with 1 so we don't end up with resolution 0.
- const bucketSizeNs = Math.max(1, Math.round(resolution * 10 * 1e9));
+ const bucketSizeNs = Math.max(1, Math.round(Number(resolution) * 10));
const windowStartNs = Math.floor(startNs / bucketSizeNs) * bucketSizeNs;
const windowDurNs = Math.max(1, endNs - windowStartNs);
@@ -98,14 +105,14 @@ class ProcessSummaryTrackController extends TrackController<Config, Data> {
where rowid = 0;`);
return this.computeSummary(
- fromNs(windowStartNs), end, resolution, bucketSizeNs);
+ tpTimeFromNanos(windowStartNs), end, resolution, bucketSizeNs);
}
private async computeSummary(
- start: number, end: number, resolution: number,
+ start: TPTime, end: TPTime, resolution: TPDuration,
bucketSizeNs: number): Promise<Data> {
- const startNs = toNs(start);
- const endNs = toNs(end);
+ const startNs = Number(start);
+ const endNs = Number(end);
const numBuckets =
Math.min(Math.ceil((endNs - startNs) / bucketSizeNs), LIMIT);
@@ -167,25 +174,28 @@ class ProcessSummaryTrack extends Track<Config, Data> {
}
renderCanvas(ctx: CanvasRenderingContext2D): void {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {
+ visibleTimeScale,
+ windowSpan,
+ } = globals.frontendLocalState;
const data = this.data();
if (data === undefined) return; // Can't possibly draw anything.
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(visibleWindowTime.start),
- timeScale.timeToPx(visibleWindowTime.end),
- timeScale.timeToPx(data.start),
- timeScale.timeToPx(data.end));
+ windowSpan.start,
+ windowSpan.end,
+ visibleTimeScale.tpTimeToPx(data.start),
+ visibleTimeScale.tpTimeToPx(data.end));
this.renderSummary(ctx, data);
}
// TODO(dproy): Dedup with CPU slices.
renderSummary(ctx: CanvasRenderingContext2D, data: Data): void {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
- const startPx = Math.floor(timeScale.timeToPx(visibleWindowTime.start));
+ const {visibleTimeScale, windowSpan} = globals.frontendLocalState;
+ const startPx = windowSpan.start;
const bottomY = TRACK_HEIGHT;
let lastX = startPx;
@@ -202,9 +212,10 @@ class ProcessSummaryTrack extends Track<Config, Data> {
for (let i = 0; i < data.utilizations.length; i++) {
// TODO(dproy): Investigate why utilization is > 1 sometimes.
const utilization = Math.min(data.utilizations[i], 1);
- const startTime = i * data.bucketSizeSeconds + data.start;
+ const startTime =
+ i * data.bucketSizeSeconds + tpTimeToSeconds(data.start);
- lastX = Math.floor(timeScale.timeToPx(startTime));
+ lastX = Math.floor(visibleTimeScale.secondsToPx(startTime));
ctx.lineTo(lastX, lastY);
lastY = MARGIN_TOP + Math.round(SUMMARY_HEIGHT * (1 - utilization));
diff --git a/ui/src/tracks/scroll_jank/event_latency_track.ts b/ui/src/tracks/scroll_jank/event_latency_track.ts
new file mode 100644
index 000000000..d805e7487
--- /dev/null
+++ b/ui/src/tracks/scroll_jank/event_latency_track.ts
@@ -0,0 +1,83 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {v4 as uuidv4} from 'uuid';
+
+import {Engine} from '../../common/engine';
+import {
+ generateSqlWithInternalLayout,
+} from '../../common/internal_layout_utils';
+import {PrimaryTrackSortKey, SCROLLING_TRACK_GROUP} from '../../common/state';
+import {
+ NamedSliceTrack,
+ NamedSliceTrackTypes,
+} from '../../frontend/named_slice_track';
+import {NewTrackArgs, Track} from '../../frontend/track';
+import {DecideTracksResult} from '../chrome_scroll_jank';
+
+interface EventLatencyTrackTypes extends NamedSliceTrackTypes {}
+
+export class EventLatencyTrack extends NamedSliceTrack<EventLatencyTrackTypes> {
+ static readonly kind = 'org.chromium.ScrollJank.event_latencies';
+ createdModels = false;
+
+ static create(args: NewTrackArgs): Track {
+ return new EventLatencyTrack(args);
+ }
+
+ constructor(args: NewTrackArgs) {
+ super(args);
+ }
+
+ async initSqlTable(tableName: string) {
+ if (this.createdModels) {
+ return;
+ }
+ const sql = `CREATE VIEW ${tableName} AS ` + generateSqlWithInternalLayout({
+ columns: ['id', 'ts', 'dur', 'track_id', 'name'],
+ layoutParams: {ts: 'ts', dur: 'dur'},
+ sourceTable: 'slice',
+ whereClause: 'slice.id IN ' +
+ '(SELECT slice_id FROM event_latency_scroll_jank_cause)',
+ });
+ await this.engine.query(sql);
+ this.createdModels = true;
+ }
+
+ // At the moment we will just display the slice details. However, on select,
+ // this behavior should be customized to show jank-related data.
+}
+
+export async function addLatenciesTrack(engine: Engine):
+ Promise<DecideTracksResult> {
+ const result: DecideTracksResult = {
+ tracksToAdd: [],
+ };
+
+ await engine.query(`
+ SELECT RUN_METRIC('chrome/event_latency_scroll_jank_cause.sql');
+ `);
+
+ result.tracksToAdd.push({
+ id: uuidv4(),
+ engineId: engine.id,
+ kind: EventLatencyTrack.kind,
+ trackSortKey: PrimaryTrackSortKey.NULL_TRACK,
+ name: 'Scroll Janks',
+ config: {},
+ trackGroup: SCROLLING_TRACK_GROUP,
+ });
+
+ return result;
+}
diff --git a/ui/src/tracks/scroll_jank/index.ts b/ui/src/tracks/scroll_jank/index.ts
new file mode 100644
index 000000000..5f6d86b25
--- /dev/null
+++ b/ui/src/tracks/scroll_jank/index.ts
@@ -0,0 +1,63 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {featureFlags} from '../../common/feature_flags';
+import {PluginContext} from '../../common/plugin_api';
+import {Selection} from '../../common/state';
+import {CURRENT_SELECTION_TAG} from '../../frontend/details_panel';
+import {globals} from '../../frontend/globals';
+
+import {EventLatencyTrack} from './event_latency_track';
+import {TopLevelScrollDetailsTab} from './scroll_details_tab';
+import {
+ TOP_LEVEL_SCROLL_KIND,
+ TopLevelScrollTrack,
+} from './scroll_track';
+
+export const INPUT_LATENCY_TRACK = 'InputLatency::';
+export const SCROLL_JANK_PLUGIN_ID = 'perfetto.ScrollJank';
+export const ENABLE_SCROLL_JANK_PLUGIN_V2 = featureFlags.register({
+ id: 'enableScrollJankPluginV2',
+ name: 'Enable Scroll Jank plugin V2',
+ description: 'Adds new tracks and visualizations for scroll jank.',
+ defaultValue: false,
+});
+
+function onDetailsPanelSelectionChange(newSelection?: Selection) {
+ if (newSelection === undefined ||
+ newSelection.kind !== TOP_LEVEL_SCROLL_KIND) {
+ return;
+ }
+ const bottomTabList = globals.bottomTabList;
+ if (!bottomTabList) return;
+ bottomTabList.addTab({
+ kind: TopLevelScrollDetailsTab.kind,
+ tag: CURRENT_SELECTION_TAG,
+ config: {
+ sqlTableName: newSelection.sqlTableName,
+ id: newSelection.id,
+ },
+ });
+}
+
+function activate(ctx: PluginContext) {
+ ctx.registerTrack(TopLevelScrollTrack);
+ ctx.registerTrack(EventLatencyTrack);
+ ctx.registerOnDetailsPanelSelectionChange(onDetailsPanelSelectionChange);
+}
+
+export const plugin = {
+ pluginId: SCROLL_JANK_PLUGIN_ID,
+ activate,
+};
diff --git a/ui/src/tracks/scroll_jank/scroll_details_tab.ts b/ui/src/tracks/scroll_jank/scroll_details_tab.ts
new file mode 100644
index 000000000..b13fcae58
--- /dev/null
+++ b/ui/src/tracks/scroll_jank/scroll_details_tab.ts
@@ -0,0 +1,90 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Panel for the top-level scrolls. For now, just show the scroll id, but we
+// can add things like scroll event count, janks, etc. as needed.
+
+import m from 'mithril';
+
+import {ColumnType} from '../../common/query_result';
+import {tpDurationFromSql, tpTimeFromSql} from '../../common/time';
+import {
+ BottomTab,
+ bottomTabRegistry,
+ NewBottomTabArgs,
+} from '../../frontend/bottom_tab';
+import {globals} from '../../frontend/globals';
+import {asTPTimestamp} from '../../frontend/sql_types';
+import {Duration} from '../../frontend/widgets/duration';
+import {Timestamp} from '../../frontend/widgets/timestamp';
+import {dictToTree} from '../../frontend/widgets/tree';
+
+interface TopLevelScrollTabConfig {
+ sqlTableName: string;
+ id: number;
+}
+
+export class TopLevelScrollDetailsTab extends
+ BottomTab<TopLevelScrollTabConfig> {
+ static readonly kind = 'org.perfetto.TopLevelScrollDetailsTab';
+
+ data: {[key: string]: ColumnType}|undefined;
+
+ static create(args: NewBottomTabArgs): TopLevelScrollDetailsTab {
+ return new TopLevelScrollDetailsTab(args);
+ }
+
+ constructor(args: NewBottomTabArgs) {
+ super(args);
+
+ this.engine
+ .query(`select * from ${this.config.sqlTableName} where id = ${
+ this.config.id}`)
+ .then((queryResult) => {
+ this.data = queryResult.firstRow({});
+ globals.rafScheduler.scheduleFullRedraw();
+ });
+ }
+
+ viewTab() {
+ if (this.data === undefined) {
+ return m('h2', 'Loading');
+ }
+
+ const left = dictToTree({
+ 'Scroll Id (gesture_scroll_id)': `${this.data['id']}`,
+ 'Start time':
+ m(Timestamp, {ts: asTPTimestamp(tpTimeFromSql(this.data['ts']))}),
+ 'Duration': m(Duration, {dur: tpDurationFromSql(this.data['dur'])}),
+ });
+ return m(
+ '.details-panel',
+ m('header.overview', m('span', `${this.data['name']}`)),
+ m('.details-table-multicolumn', m('.half-width-panel', left)));
+ }
+
+ getTitle(): string {
+ return `Current Chrome Scroll`;
+ }
+
+ isLoading() {
+ return this.data === undefined;
+ }
+
+ renderTabCanvas() {
+ return;
+ }
+}
+
+bottomTabRegistry.register(TopLevelScrollDetailsTab);
diff --git a/ui/src/tracks/scroll_jank/scroll_track.ts b/ui/src/tracks/scroll_jank/scroll_track.ts
new file mode 100644
index 000000000..8532a452e
--- /dev/null
+++ b/ui/src/tracks/scroll_jank/scroll_track.ts
@@ -0,0 +1,116 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {TPTime} from 'src/common/time';
+import {v4 as uuidv4} from 'uuid';
+
+import {Actions} from '../../common/actions';
+import {Engine} from '../../common/engine';
+import {
+ generateSqlWithInternalLayout,
+} from '../../common/internal_layout_utils';
+import {
+ PrimaryTrackSortKey,
+ SCROLLING_TRACK_GROUP,
+ Selection,
+} from '../../common/state';
+import {OnSliceClickArgs} from '../../frontend/base_slice_track';
+import {globals} from '../../frontend/globals';
+import {
+ NamedSliceTrack,
+ NamedSliceTrackTypes,
+} from '../../frontend/named_slice_track';
+import {NewTrackArgs, Track} from '../../frontend/track';
+import {DecideTracksResult} from '../chrome_scroll_jank';
+
+export const TOP_LEVEL_SCROLL_KIND = 'TOP_LEVEL_SCROLL';
+
+export interface TopLevelScrollSelection {
+ kind: 'TOP_LEVEL_SCROLL';
+ id: number;
+ sqlTableName: string;
+ start: TPTime;
+ duration: TPTime;
+}
+
+export {Data} from '../chrome_slices';
+
+interface TopLevelScrollTrackTypes extends NamedSliceTrackTypes {}
+
+export class TopLevelScrollTrack extends
+ NamedSliceTrack<TopLevelScrollTrackTypes> {
+ static readonly kind = 'org.chromium.TopLevelScrolls.scrolls';
+ createdModels = false;
+
+ static create(args: NewTrackArgs): Track {
+ return new TopLevelScrollTrack(args);
+ }
+
+ constructor(args: NewTrackArgs) {
+ super(args);
+ }
+
+ async initSqlTable(tableName: string) {
+ if (this.createdModels) {
+ return;
+ }
+ const sql =
+ `CREATE VIEW ${tableName} AS ` + generateSqlWithInternalLayout({
+ columns: [`printf("Scroll %s", CAST(id AS STRING)) AS name`, '*'],
+ layoutParams: {ts: 'ts', dur: 'dur'},
+ sourceTable: 'chrome_scrolls',
+ orderByClause: 'ts',
+ });
+ await this.engine.query(sql);
+ this.createdModels = true;
+ }
+
+ isSelectionHandled(selection: Selection) {
+ if (selection.kind !== 'TOP_LEVEL_SCROLL') {
+ return false;
+ }
+ return selection.trackId === this.trackId;
+ }
+
+ onSliceClick(args: OnSliceClickArgs<TopLevelScrollTrackTypes['slice']>) {
+ globals.dispatch(Actions.selectTopLevelScrollSlice({
+ id: args.slice.id,
+ sqlTableName: this.tableName,
+ start: args.slice.start,
+ duration: args.slice.duration,
+ trackId: this.trackId,
+ }));
+ }
+}
+
+export async function addTopLevelScrollTrack(engine: Engine):
+ Promise<DecideTracksResult> {
+ const result: DecideTracksResult = {
+ tracksToAdd: [],
+ };
+
+ await engine.query(`SELECT IMPORT('chrome.chrome_scrolls');`);
+
+ result.tracksToAdd.push({
+ id: uuidv4(),
+ engineId: engine.id,
+ kind: TopLevelScrollTrack.kind,
+ trackSortKey: PrimaryTrackSortKey.ASYNC_SLICE_TRACK,
+ name: 'Top Level Scrolls',
+ config: {},
+ trackGroup: SCROLLING_TRACK_GROUP,
+ });
+
+ return result;
+}
diff --git a/ui/src/tracks/thread_state/index.ts b/ui/src/tracks/thread_state/index.ts
index 371399988..4ad1b4cdf 100644
--- a/ui/src/tracks/thread_state/index.ts
+++ b/ui/src/tracks/thread_state/index.ts
@@ -17,10 +17,18 @@ import {assertFalse} from '../../base/logging';
import {Actions} from '../../common/actions';
import {cropText} from '../../common/canvas_utils';
import {colorForState} from '../../common/colorizer';
+import {
+ HighPrecisionTime,
+ HighPrecisionTimeSpan,
+} from '../../common/high_precision_time';
import {PluginContext} from '../../common/plugin_api';
-import {NUM, NUM_NULL, STR_NULL} from '../../common/query_result';
+import {LONG, NUM, NUM_NULL, STR_NULL} from '../../common/query_result';
import {translateState} from '../../common/thread_state';
-import {fromNs, toNs} from '../../common/time';
+import {
+ fromNs,
+ TPDuration,
+ TPTime,
+} from '../../common/time';
import {TrackData} from '../../common/track_data';
import {TrackController} from '../../controller/track_controller';
import {checkerboardExcept} from '../../frontend/checkerboard';
@@ -46,7 +54,7 @@ export interface Config {
class ThreadStateTrackController extends TrackController<Config, Data> {
static readonly kind = THREAD_STATE_TRACK_KIND;
- private maxDurNs = 0;
+ private maxDurNs: TPDuration = 0n;
async onSetup() {
await this.query(`
@@ -66,19 +74,15 @@ class ThreadStateTrackController extends TrackController<Config, Data> {
select ifnull(max(dur), 0) as maxDur
from ${this.tableName('thread_state')}
`);
- this.maxDurNs = queryRes.firstRow({maxDur: NUM}).maxDur;
+ this.maxDurNs = queryRes.firstRow({maxDur: LONG}).maxDur;
}
- async onBoundsChange(start: number, end: number, resolution: number):
+ async onBoundsChange(start: TPTime, end: TPTime, resolution: TPDuration):
Promise<Data> {
- const resolutionNs = toNs(resolution);
- const startNs = toNs(start);
- const endNs = toNs(end);
-
// ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to
// be an even number, so we can snap in the middle.
const bucketNs =
- Math.max(Math.round(resolutionNs * this.pxSize() / 2) * 2, 1);
+ Math.max(Math.round(Number(resolution) * this.pxSize() / 2) * 2, 1);
const query = `
select
@@ -92,8 +96,8 @@ class ThreadStateTrackController extends TrackController<Config, Data> {
ifnull(id, -1) as id
from ${this.tableName('thread_state')}
where
- ts >= ${startNs - this.maxDurNs} and
- ts <= ${endNs}
+ ts >= ${start - this.maxDurNs} and
+ ts <= ${end}
group by tsq, is_sleep
order by tsq
`;
@@ -186,7 +190,11 @@ class ThreadStateTrack extends Track<Config, Data> {
}
renderCanvas(ctx: CanvasRenderingContext2D): void {
- const {timeScale, visibleWindowTime} = globals.frontendLocalState;
+ const {
+ visibleTimeScale: timeScale,
+ visibleWindowTime,
+ windowSpan,
+ } = globals.frontendLocalState;
const data = this.data();
const charWidth = ctx.measureText('dbpqaouk').width / 8;
@@ -199,10 +207,10 @@ class ThreadStateTrack extends Track<Config, Data> {
checkerboardExcept(
ctx,
this.getHeight(),
- timeScale.timeToPx(visibleWindowTime.start),
- timeScale.timeToPx(visibleWindowTime.end),
- timeScale.timeToPx(data.start),
- timeScale.timeToPx(data.end),
+ windowSpan.start,
+ windowSpan.end,
+ timeScale.tpTimeToPx(data.start),
+ timeScale.tpTimeToPx(data.end),
);
ctx.textAlign = 'center';
@@ -220,14 +228,19 @@ class ThreadStateTrack extends Track<Config, Data> {
const tStart = data.starts[i];
const tEnd = data.ends[i];
const state = data.strings[data.state[i]];
- if (tEnd <= visibleWindowTime.start || tStart >= visibleWindowTime.end) {
+ const timeSpan = new HighPrecisionTimeSpan(
+ HighPrecisionTime.fromSeconds(tStart),
+ HighPrecisionTime.fromSeconds(tEnd),
+ );
+
+ if (!visibleWindowTime.intersects(timeSpan)) {
continue;
}
// Don't display a slice for Task Dead.
if (state === 'x') continue;
- const rectStart = timeScale.timeToPx(tStart);
- const rectEnd = timeScale.timeToPx(tEnd);
+ const rectStart = timeScale.secondsToPx(tStart);
+ const rectEnd = timeScale.secondsToPx(tEnd);
const rectWidth = rectEnd - rectStart;
const currentSelection = globals.state.currentSelection;
@@ -255,10 +268,9 @@ class ThreadStateTrack extends Track<Config, Data> {
if (isSelected) {
drawRectOnSelected = () => {
const rectStart =
- Math.max(0 - EXCESS_WIDTH, timeScale.timeToPx(tStart));
+ Math.max(0 - EXCESS_WIDTH, timeScale.secondsToPx(tStart));
const rectEnd = Math.min(
- timeScale.timeToPx(visibleWindowTime.end) + EXCESS_WIDTH,
- timeScale.timeToPx(tEnd));
+ windowSpan.end + EXCESS_WIDTH, timeScale.secondsToPx(tEnd));
const color = colorForState(state);
ctx.strokeStyle = `hsl(${color.h},${color.s}%,${color.l * 0.7}%)`;
ctx.beginPath();
@@ -278,9 +290,9 @@ class ThreadStateTrack extends Track<Config, Data> {
onMouseClick({x}: {x: number}) {
const data = this.data();
if (data === undefined) return false;
- const {timeScale} = globals.frontendLocalState;
- const time = timeScale.pxToTime(x);
- const index = search(data.starts, time);
+ const {visibleTimeScale} = globals.frontendLocalState;
+ const time = visibleTimeScale.pxToHpTime(x);
+ const index = search(data.starts, time.seconds);
if (index === -1) return false;
const id = data.ids[index];