Merge "[stdlib]: Fix typo in oom_adjuster bucket" into main
diff --git a/Android.bp b/Android.bp
index a4b4894..4267433 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2323,10 +2323,9 @@
":perfetto_src_shared_lib_test_utils",
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_db_column_column",
- ":perfetto_src_trace_processor_db_column_make_chain",
":perfetto_src_trace_processor_db_db",
":perfetto_src_trace_processor_db_minimal",
- ":perfetto_src_trace_processor_export_json_sources",
+ ":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_common_common",
":perfetto_src_trace_processor_importers_common_parser_types",
@@ -2376,7 +2375,6 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
- ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
@@ -10956,14 +10954,6 @@
],
}
-// GN: //src/trace_processor/db/column:make_chain
-filegroup {
- name: "perfetto_src_trace_processor_db_column_make_chain",
- srcs: [
- "src/trace_processor/db/column/make_chain.cc",
- ],
-}
-
// GN: //src/trace_processor/db/column:unittests
filegroup {
name: "perfetto_src_trace_processor_db_column_unittests",
@@ -11008,7 +10998,6 @@
filegroup {
name: "perfetto_src_trace_processor_db_unittests",
srcs: [
- "src/trace_processor/db/column_storage_overlay_unittest.cc",
"src/trace_processor/db/compare_unittest.cc",
"src/trace_processor/db/query_executor_unittest.cc",
"src/trace_processor/db/runtime_table_unittest.cc",
@@ -11032,9 +11021,9 @@
],
}
-// GN: //src/trace_processor:export_json_sources
+// GN: //src/trace_processor:export_json
filegroup {
- name: "perfetto_src_trace_processor_export_json_sources",
+ name: "perfetto_src_trace_processor_export_json",
srcs: [
"src/trace_processor/export_json.cc",
],
@@ -11089,7 +11078,6 @@
"src/trace_processor/importers/common/process_tracker.cc",
"src/trace_processor/importers/common/slice_tracker.cc",
"src/trace_processor/importers/common/slice_translation_table.cc",
- "src/trace_processor/importers/common/stack_profile_tracker.cc",
"src/trace_processor/importers/common/system_info_tracker.cc",
"src/trace_processor/importers/common/trace_parser.cc",
"src/trace_processor/importers/common/track_tracker.cc",
@@ -11409,6 +11397,7 @@
"src/trace_processor/importers/proto/chrome_system_probes_module.cc",
"src/trace_processor/importers/proto/chrome_system_probes_parser.cc",
"src/trace_processor/importers/proto/default_modules.cc",
+ "src/trace_processor/importers/proto/heap_profile_tracker.cc",
"src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc",
"src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
"src/trace_processor/importers/proto/metadata_minimal_module.cc",
@@ -11417,12 +11406,12 @@
"src/trace_processor/importers/proto/packet_sequence_state_generation.cc",
"src/trace_processor/importers/proto/perf_sample_tracker.cc",
"src/trace_processor/importers/proto/profile_module.cc",
- "src/trace_processor/importers/proto/profile_packet_sequence_state.cc",
"src/trace_processor/importers/proto/profile_packet_utils.cc",
+ "src/trace_processor/importers/proto/profiler_util.cc",
"src/trace_processor/importers/proto/proto_trace_parser.cc",
"src/trace_processor/importers/proto/proto_trace_reader.cc",
"src/trace_processor/importers/proto/proto_trace_tokenizer.cc",
- "src/trace_processor/importers/proto/stack_profile_sequence_state.cc",
+ "src/trace_processor/importers/proto/stack_profile_tracker.cc",
"src/trace_processor/importers/proto/track_event_module.cc",
"src/trace_processor/importers/proto/track_event_parser.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.cc",
@@ -11449,9 +11438,9 @@
srcs: [
"src/trace_processor/importers/proto/active_chrome_processes_tracker_unittest.cc",
"src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc",
+ "src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc",
"src/trace_processor/importers/proto/network_trace_module_unittest.cc",
"src/trace_processor/importers/proto/perf_sample_tracker_unittest.cc",
- "src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc",
"src/trace_processor/importers/proto/proto_trace_parser_unittest.cc",
"src/trace_processor/importers/proto/string_encoding_utils_unittests.cc",
],
@@ -12331,14 +12320,6 @@
],
}
-// GN: //src/trace_processor/util:profiler_util
-filegroup {
- name: "perfetto_src_trace_processor_util_profiler_util",
- srcs: [
- "src/trace_processor/util/profiler_util.cc",
- ],
-}
-
// GN: //src/trace_processor/util:proto_profiler
filegroup {
name: "perfetto_src_trace_processor_util_proto_profiler",
@@ -13813,13 +13794,12 @@
":perfetto_src_trace_processor_containers_unittests",
":perfetto_src_trace_processor_db_column_column",
":perfetto_src_trace_processor_db_column_fake_storage",
- ":perfetto_src_trace_processor_db_column_make_chain",
":perfetto_src_trace_processor_db_column_unittests",
":perfetto_src_trace_processor_db_compare",
":perfetto_src_trace_processor_db_db",
":perfetto_src_trace_processor_db_minimal",
":perfetto_src_trace_processor_db_unittests",
- ":perfetto_src_trace_processor_export_json_sources",
+ ":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_android_bugreport_unittests",
":perfetto_src_trace_processor_importers_common_common",
@@ -13891,7 +13871,6 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
- ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
@@ -14534,10 +14513,9 @@
":perfetto_src_protozero_protozero",
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_db_column_column",
- ":perfetto_src_trace_processor_db_column_make_chain",
":perfetto_src_trace_processor_db_db",
":perfetto_src_trace_processor_db_minimal",
- ":perfetto_src_trace_processor_export_json_sources",
+ ":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_common_common",
":perfetto_src_trace_processor_importers_common_parser_types",
@@ -14590,7 +14568,6 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
- ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
@@ -14771,10 +14748,9 @@
":perfetto_src_protozero_protozero",
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_db_column_column",
- ":perfetto_src_trace_processor_db_column_make_chain",
":perfetto_src_trace_processor_db_db",
":perfetto_src_trace_processor_db_minimal",
- ":perfetto_src_trace_processor_export_json_sources",
+ ":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_common_common",
":perfetto_src_trace_processor_importers_common_parser_types",
@@ -14824,7 +14800,6 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
- ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
diff --git a/BUILD b/BUILD
index fe8598c..e6649d9 100644
--- a/BUILD
+++ b/BUILD
@@ -217,10 +217,9 @@
":src_kernel_utils_syscall_table",
":src_protozero_proto_ring_buffer",
":src_trace_processor_db_column_column",
- ":src_trace_processor_db_column_make_chain",
":src_trace_processor_db_db",
":src_trace_processor_db_minimal",
- ":src_trace_processor_export_json_sources",
+ ":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",
@@ -273,7 +272,6 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
- ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
@@ -1403,14 +1401,6 @@
],
)
-# GN target: //src/trace_processor/db/column:make_chain
-perfetto_filegroup(
- name = "src_trace_processor_db_column_make_chain",
- srcs = [
- "src/trace_processor/db/column/make_chain.cc",
- ],
-)
-
# GN target: //src/trace_processor/db:db
perfetto_filegroup(
name = "src_trace_processor_db_db",
@@ -1483,8 +1473,6 @@
"src/trace_processor/importers/common/slice_tracker.h",
"src/trace_processor/importers/common/slice_translation_table.cc",
"src/trace_processor/importers/common/slice_translation_table.h",
- "src/trace_processor/importers/common/stack_profile_tracker.cc",
- "src/trace_processor/importers/common/stack_profile_tracker.h",
"src/trace_processor/importers/common/system_info_tracker.cc",
"src/trace_processor/importers/common/system_info_tracker.h",
"src/trace_processor/importers/common/trace_parser.cc",
@@ -1833,6 +1821,8 @@
"src/trace_processor/importers/proto/chrome_system_probes_parser.h",
"src/trace_processor/importers/proto/default_modules.cc",
"src/trace_processor/importers/proto/default_modules.h",
+ "src/trace_processor/importers/proto/heap_profile_tracker.cc",
+ "src/trace_processor/importers/proto/heap_profile_tracker.h",
"src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc",
"src/trace_processor/importers/proto/memory_tracker_snapshot_module.h",
"src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
@@ -1849,10 +1839,10 @@
"src/trace_processor/importers/proto/perf_sample_tracker.h",
"src/trace_processor/importers/proto/profile_module.cc",
"src/trace_processor/importers/proto/profile_module.h",
- "src/trace_processor/importers/proto/profile_packet_sequence_state.cc",
- "src/trace_processor/importers/proto/profile_packet_sequence_state.h",
"src/trace_processor/importers/proto/profile_packet_utils.cc",
"src/trace_processor/importers/proto/profile_packet_utils.h",
+ "src/trace_processor/importers/proto/profiler_util.cc",
+ "src/trace_processor/importers/proto/profiler_util.h",
"src/trace_processor/importers/proto/proto_incremental_state.h",
"src/trace_processor/importers/proto/proto_trace_parser.cc",
"src/trace_processor/importers/proto/proto_trace_parser.h",
@@ -1860,8 +1850,8 @@
"src/trace_processor/importers/proto/proto_trace_reader.h",
"src/trace_processor/importers/proto/proto_trace_tokenizer.cc",
"src/trace_processor/importers/proto/proto_trace_tokenizer.h",
- "src/trace_processor/importers/proto/stack_profile_sequence_state.cc",
- "src/trace_processor/importers/proto/stack_profile_sequence_state.h",
+ "src/trace_processor/importers/proto/stack_profile_tracker.cc",
+ "src/trace_processor/importers/proto/stack_profile_tracker.h",
"src/trace_processor/importers/proto/track_event_module.cc",
"src/trace_processor/importers/proto/track_event_module.h",
"src/trace_processor/importers/proto/track_event_parser.cc",
@@ -2723,15 +2713,6 @@
],
)
-# GN target: //src/trace_processor/util:profiler_util
-perfetto_filegroup(
- name = "src_trace_processor_util_profiler_util",
- srcs = [
- "src/trace_processor/util/profiler_util.cc",
- "src/trace_processor/util/profiler_util.h",
- ],
-)
-
# GN target: //src/trace_processor/util:proto_profiler
perfetto_filegroup(
name = "src_trace_processor_util_proto_profiler",
@@ -2841,9 +2822,9 @@
linkstatic = True,
)
-# GN target: //src/trace_processor:export_json_sources
+# GN target: //src/trace_processor:export_json
perfetto_filegroup(
- name = "src_trace_processor_export_json_sources",
+ name = "src_trace_processor_export_json",
srcs = [
"src/trace_processor/export_json.cc",
"src/trace_processor/export_json.h",
@@ -5555,10 +5536,9 @@
srcs = [
":src_kernel_utils_syscall_table",
":src_trace_processor_db_column_column",
- ":src_trace_processor_db_column_make_chain",
":src_trace_processor_db_db",
":src_trace_processor_db_minimal",
- ":src_trace_processor_export_json_sources",
+ ":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",
@@ -5610,7 +5590,6 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
- ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
@@ -5723,10 +5702,9 @@
":src_profiling_symbolizer_symbolizer",
":src_protozero_proto_ring_buffer",
":src_trace_processor_db_column_column",
- ":src_trace_processor_db_column_make_chain",
":src_trace_processor_db_db",
":src_trace_processor_db_minimal",
- ":src_trace_processor_export_json_sources",
+ ":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",
@@ -5781,7 +5759,6 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
- ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
@@ -5949,10 +5926,9 @@
":src_profiling_symbolizer_symbolizer",
":src_protozero_proto_ring_buffer",
":src_trace_processor_db_column_column",
- ":src_trace_processor_db_column_make_chain",
":src_trace_processor_db_db",
":src_trace_processor_db_minimal",
- ":src_trace_processor_export_json_sources",
+ ":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",
@@ -6004,7 +5980,6 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
- ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
diff --git a/protos/perfetto/config/android/protolog_config.proto b/protos/perfetto/config/android/protolog_config.proto
index 6798bd3..c73256e 100644
--- a/protos/perfetto/config/android/protolog_config.proto
+++ b/protos/perfetto/config/android/protolog_config.proto
@@ -47,4 +47,7 @@
// e.g. if ProtoLogLevel.WARN is specified only warning, errors and fatal log
// message will be traced.
optional ProtoLogLevel log_from = 2;
+ // When set to true we will collect the stacktrace for each protolog message
+ // in this group that we are tracing.
+ optional bool collect_stacktrace = 3;
}
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index ab07107..d91246b 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -600,6 +600,9 @@
// e.g. if ProtoLogLevel.WARN is specified only warning, errors and fatal log
// message will be traced.
optional ProtoLogLevel log_from = 2;
+ // When set to true we will collect the stacktrace for each protolog message
+ // in this group that we are tracing.
+ optional bool collect_stacktrace = 3;
}
// End of protos/perfetto/config/android/protolog_config.proto
diff --git a/protos/perfetto/trace/android/protolog.proto b/protos/perfetto/trace/android/protolog.proto
index 49e5521..b520c7a 100644
--- a/protos/perfetto/trace/android/protolog.proto
+++ b/protos/perfetto/trace/android/protolog.proto
@@ -25,13 +25,16 @@
/* log statement identifier, created from message string and log level. */
optional fixed64 message_id = 1;
/* string parameters passed to the log call that have been interned. */
- repeated uint32 interned_str_params = 2;
+ repeated uint32 str_param_iids = 2;
/* integer parameters passed to the log call. */
repeated sint64 sint64_params = 3;
/* floating point parameters passed to the log call. */
repeated double double_params = 4;
/* boolean parameters passed to the log call. */
repeated int32 boolean_params = 5;
+ // id of the interned stacktrace string
+ // (only dumped if explicitly confuigured to do so)
+ optional uint32 stacktrace_iid = 6;
}
/* contains all the data required to fully decode the protolog messages */
diff --git a/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto b/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
index 99a6e26..5bfab9dd 100644
--- a/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
@@ -31,10 +31,6 @@
// Set to true if there was data loss between the last time we've read from
// the corresponding per-cpu kernel buffer, and the earliest event recorded
// in this bundle.
- // TODO(rsavitski): consider replicating in the newer FtraceError. This field
- // has been set since the original implementation, but used only for manual
- // debugging. Trace processor instead looks at the FtraceStats totals for the
- // tracing session.
optional bool lost_events = 3;
// Optionally-enabled compact encoding of a batch of scheduling events. Only
diff --git a/protos/perfetto/trace/ftrace/ftrace_stats.proto b/protos/perfetto/trace/ftrace/ftrace_stats.proto
index c5f06b9..f921779 100644
--- a/protos/perfetto/trace/ftrace/ftrace_stats.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_stats.proto
@@ -40,6 +40,8 @@
// Size of entries currently in the kernel buffer (see |entries|) in bytes.
// The field should be named "bytes", but is misnamed for historical reasons.
+ // This value has known inaccuracies before Linux v6.6:
+ // https://github.com/torvalds/linux/commit/45d99ea
optional uint64 bytes_read = 5;
// The timestamp for the oldest event still in the ring buffer.
diff --git a/protos/perfetto/trace/interned_data/interned_data.proto b/protos/perfetto/trace/interned_data/interned_data.proto
index 401ea13..2cae9c6 100644
--- a/protos/perfetto/trace/interned_data/interned_data.proto
+++ b/protos/perfetto/trace/interned_data/interned_data.proto
@@ -135,4 +135,6 @@
// Interned protolog strings args.
repeated InternedString protolog_string_args = 36;
+ // Interned protolog stacktraces.
+ repeated InternedString protolog_stacktrace = 37;
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 41a0a31..f9370cd 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -600,6 +600,9 @@
// e.g. if ProtoLogLevel.WARN is specified only warning, errors and fatal log
// message will be traced.
optional ProtoLogLevel log_from = 2;
+ // When set to true we will collect the stacktrace for each protolog message
+ // in this group that we are tracing.
+ optional bool collect_stacktrace = 3;
}
// End of protos/perfetto/config/android/protolog_config.proto
@@ -4848,13 +4851,16 @@
/* log statement identifier, created from message string and log level. */
optional fixed64 message_id = 1;
/* string parameters passed to the log call that have been interned. */
- repeated uint32 interned_str_params = 2;
+ repeated uint32 str_param_iids = 2;
/* integer parameters passed to the log call. */
repeated sint64 sint64_params = 3;
/* floating point parameters passed to the log call. */
repeated double double_params = 4;
/* boolean parameters passed to the log call. */
repeated int32 boolean_params = 5;
+ // id of the interned stacktrace string
+ // (only dumped if explicitly confuigured to do so)
+ optional uint32 stacktrace_iid = 6;
}
/* contains all the data required to fully decode the protolog messages */
@@ -10444,6 +10450,8 @@
// Size of entries currently in the kernel buffer (see |entries|) in bytes.
// The field should be named "bytes", but is misnamed for historical reasons.
+ // This value has known inaccuracies before Linux v6.6:
+ // https://github.com/torvalds/linux/commit/45d99ea
optional uint64 bytes_read = 5;
// The timestamp for the oldest event still in the ring buffer.
@@ -10555,10 +10563,6 @@
// Set to true if there was data loss between the last time we've read from
// the corresponding per-cpu kernel buffer, and the earliest event recorded
// in this bundle.
- // TODO(rsavitski): consider replicating in the newer FtraceError. This field
- // has been set since the original implementation, but used only for manual
- // debugging. Trace processor instead looks at the FtraceStats totals for the
- // tracing session.
optional bool lost_events = 3;
// Optionally-enabled compact encoding of a batch of scheduling events. Only
@@ -12455,6 +12459,8 @@
// Interned protolog strings args.
repeated InternedString protolog_string_args = 36;
+ // Interned protolog stacktraces.
+ repeated InternedString protolog_stacktrace = 37;
}
// End of protos/perfetto/trace/interned_data/interned_data.proto
diff --git a/python/generators/trace_processor_table/serialize.py b/python/generators/trace_processor_table/serialize.py
index 1f92f44..2881ce0 100644
--- a/python/generators/trace_processor_table/serialize.py
+++ b/python/generators/trace_processor_table/serialize.py
@@ -675,16 +675,14 @@
Iterator IterateRows() {{ return Iterator(this, Table::IterateRows()); }}
ConstIterator FilterToIterator(
- const std::vector<Constraint>& cs,
- RowMap::OptimizeFor opt = RowMap::OptimizeFor::kMemory) const {{
+ const std::vector<Constraint>& cs) const {{
return ConstIterator(
- this, ApplyAndIterateRows(QueryToRowMap(cs, {{}}, opt)));
+ this, ApplyAndIterateRows(QueryToRowMap(cs, {{}})));
}}
Iterator FilterToIterator(
- const std::vector<Constraint>& cs,
- RowMap::OptimizeFor opt = RowMap::OptimizeFor::kMemory) {{
- return Iterator(this, ApplyAndIterateRows(QueryToRowMap(cs, {{}}, opt)));
+ const std::vector<Constraint>& cs) {{
+ return Iterator(this, ApplyAndIterateRows(QueryToRowMap(cs, {{}})));
}}
void ShrinkToFit() {{
diff --git a/src/base/debug_crash_stack_trace.cc b/src/base/debug_crash_stack_trace.cc
index 4a16f29..9e1ef80 100644
--- a/src/base/debug_crash_stack_trace.cc
+++ b/src/base/debug_crash_stack_trace.cc
@@ -149,7 +149,11 @@
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- auto bt_error = [](void*, const char* msg, int) { Print(msg); };
+ auto bt_error = [](void*, const char* msg, int) {
+ Print("libbacktrace error: ");
+ perfetto::base::WriteAll(STDERR_FILENO, msg, strlen(msg));
+ Print("\n");
+ };
struct backtrace_state* bt_state =
backtrace_create_state(nullptr, 0, bt_error, nullptr);
#endif
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index dab8c3f..694b515 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -46,11 +46,19 @@
# Depended upon by Chrome to do proto -> JSON conversion of traces.
# Must be small binary size as all code here needs to be shipped in
# Chrome.
-static_library("export_json") {
+source_set("export_json") {
+ sources = [
+ "export_json.cc",
+ "export_json.h",
+ ]
deps = [
- ":export_json_sources",
+ ":storage_minimal",
"../../gn:default_deps",
- "db/column:make_chain_minimal",
+ "../../include/perfetto/ext/trace_processor:export_json",
+ "../base",
+ "importers/json:minimal",
+ "storage",
+ "types",
]
public_deps = [ "../../include/perfetto/ext/trace_processor:export_json" ]
}
@@ -129,22 +137,6 @@
public_deps = [ "../../include/perfetto/trace_processor:storage" ]
}
-source_set("export_json_sources") {
- sources = [
- "export_json.cc",
- "export_json.h",
- ]
- deps = [
- ":storage_minimal",
- "../../gn:default_deps",
- "../../include/perfetto/ext/trace_processor:export_json",
- "../base",
- "importers/json:minimal",
- "storage",
- "types",
- ]
-}
-
if (enable_perfetto_trace_processor_sqlite) {
source_set("lib") {
sources = [
@@ -168,7 +160,6 @@
"../base",
"../protozero",
"db",
- "db/column:make_chain",
"importers/android_bugreport",
"importers/common",
"importers/etw:full",
@@ -262,7 +253,7 @@
# windows.
sources += [ "export_json_unittest.cc" ]
deps += [
- ":export_json_sources",
+ ":export_json",
"../../gn:jsoncpp",
"../../include/perfetto/ext/trace_processor:export_json",
"containers",
@@ -364,6 +355,5 @@
":storage_minimal",
"../../gn:default_deps",
"../base",
- "db/column:make_chain_minimal",
]
}
diff --git a/src/trace_processor/containers/bit_vector.h b/src/trace_processor/containers/bit_vector.h
index 541bed2..884e1ca 100644
--- a/src/trace_processor/containers/bit_vector.h
+++ b/src/trace_processor/containers/bit_vector.h
@@ -299,11 +299,10 @@
// Creates a BitVector of size |end| with the bits between |start| and |end|
// filled by calling the filler function |f(index of bit)|.
//
- // As an example, suppose Range(3, 7, [](x) { return x < 5 }). This would
- // result in the following BitVector:
- // [0 0 0 1 1 0 0]
+ // As an example, suppose RangeForTesting(3, 7, [](x) { return x < 5 }). This
+ // would result in the following BitVector: [0 0 0 1 1 0 0]
template <typename Filler = bool(uint32_t)>
- static BitVector Range(uint32_t start, uint32_t end, Filler f) {
+ static BitVector RangeForTesting(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 = BlockCount(start);
diff --git a/src/trace_processor/containers/bit_vector_benchmark.cc b/src/trace_processor/containers/bit_vector_benchmark.cc
index 87d29af..fd723a6 100644
--- a/src/trace_processor/containers/bit_vector_benchmark.cc
+++ b/src/trace_processor/containers/bit_vector_benchmark.cc
@@ -222,28 +222,6 @@
}
BENCHMARK(BM_BitVectorResize);
-static void BM_BitVectorRangeFixedSize(benchmark::State& state) {
- static constexpr uint32_t kRandomSeed = 42;
- std::minstd_rand0 rnd_engine(kRandomSeed);
-
- uint32_t size = static_cast<uint32_t>(state.range(0));
- uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
-
- std::vector<uint32_t> resize_fill_pool(size);
- for (uint32_t i = 0; i < size; ++i) {
- resize_fill_pool[i] = rnd_engine() % 100 < set_percentage ? 90 : 100;
- }
-
- for (auto _ : state) {
- auto filler = [&resize_fill_pool](uint32_t i) PERFETTO_ALWAYS_INLINE {
- return resize_fill_pool[i] < 95;
- };
- BitVector bv = BitVector::Range(0, size, filler);
- benchmark::ClobberMemory();
- }
-}
-BENCHMARK(BM_BitVectorRangeFixedSize)->Apply(BitVectorArgs);
-
static void BM_BitVectorUpdateSetBits(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
diff --git a/src/trace_processor/containers/bit_vector_unittest.cc b/src/trace_processor/containers/bit_vector_unittest.cc
index 47a8aff..d803cef 100644
--- a/src/trace_processor/containers/bit_vector_unittest.cc
+++ b/src/trace_processor/containers/bit_vector_unittest.cc
@@ -455,7 +455,8 @@
}
TEST(BitVectorUnittest, IntersectRange) {
- BitVector bv = BitVector::Range(1, 20, [](uint32_t t) { return t % 2 == 0; });
+ BitVector bv =
+ BitVector::RangeForTesting(1, 20, [](uint32_t t) { return t % 2 == 0; });
BitVector intersected = bv.IntersectRange(3, 10);
ASSERT_EQ(intersected.IndexOfNthSet(0), 4u);
@@ -463,7 +464,8 @@
}
TEST(BitVectorUnittest, IntersectRangeFromStart) {
- BitVector bv = BitVector::Range(1, 20, [](uint32_t t) { return t % 2 == 0; });
+ BitVector bv =
+ BitVector::RangeForTesting(1, 20, [](uint32_t t) { return t % 2 == 0; });
BitVector intersected = bv.IntersectRange(0, 10);
ASSERT_EQ(intersected.IndexOfNthSet(0), 2u);
@@ -478,8 +480,8 @@
}
TEST(BitVectorUnittest, IntersectRangeAfterWord) {
- BitVector bv =
- BitVector::Range(64 + 1, 64 + 20, [](uint32_t t) { return t % 2 == 0; });
+ BitVector bv = BitVector::RangeForTesting(
+ 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);
@@ -487,7 +489,8 @@
}
TEST(BitVectorUnittest, IntersectRangeSetBitsBeforeRange) {
- BitVector bv = BitVector::Range(10, 30, [](uint32_t t) { return t < 15; });
+ BitVector bv =
+ BitVector::RangeForTesting(10, 30, [](uint32_t t) { return t < 15; });
BitVector intersected = bv.IntersectRange(16, 50);
ASSERT_FALSE(intersected.CountSetBits());
@@ -503,8 +506,8 @@
}
TEST(BitVectorUnittest, IntersectRangeStressTest) {
- BitVector bv =
- BitVector::Range(65, 1024 + 1, [](uint32_t t) { return t % 2 == 0; });
+ BitVector bv = BitVector::RangeForTesting(
+ 65, 1024 + 1, [](uint32_t t) { return t % 2 == 0; });
BitVector intersected = bv.IntersectRange(30, 500);
ASSERT_EQ(intersected.IndexOfNthSet(0), 66u);
@@ -512,7 +515,8 @@
}
TEST(BitVectorUnittest, Range) {
- BitVector bv = BitVector::Range(1, 9, [](uint32_t t) { return t % 3 == 0; });
+ BitVector bv =
+ BitVector::RangeForTesting(1, 9, [](uint32_t t) { return t % 3 == 0; });
ASSERT_EQ(bv.size(), 9u);
ASSERT_FALSE(bv.IsSet(0));
@@ -523,8 +527,8 @@
}
TEST(BitVectorUnittest, RangeStressTest) {
- BitVector bv =
- BitVector::Range(1, 1025, [](uint32_t t) { return t % 3 == 0; });
+ BitVector bv = BitVector::RangeForTesting(
+ 1, 1025, [](uint32_t t) { return t % 3 == 0; });
ASSERT_EQ(bv.size(), 1025u);
ASSERT_FALSE(bv.IsSet(0));
for (uint32_t i = 1; i < 1025; ++i) {
@@ -654,8 +658,8 @@
}
TEST(BitVectorUnittest, NotBig) {
- BitVector bv =
- BitVector::Range(0, 1026, [](uint32_t i) { return i % 5 == 0; });
+ BitVector bv = BitVector::RangeForTesting(
+ 0, 1026, [](uint32_t i) { return i % 5 == 0; });
bv.Not();
EXPECT_EQ(bv.CountSetBits(), 820u);
@@ -673,13 +677,13 @@
}
TEST(BitVectorUnittest, OrBig) {
- BitVector bv =
- BitVector::Range(0, 1025, [](uint32_t i) { return i % 5 == 0; });
- BitVector bv_sec =
- BitVector::Range(0, 1025, [](uint32_t i) { return i % 3 == 0; });
+ BitVector bv = BitVector::RangeForTesting(
+ 0, 1025, [](uint32_t i) { return i % 5 == 0; });
+ BitVector bv_sec = BitVector::RangeForTesting(
+ 0, 1025, [](uint32_t i) { return i % 3 == 0; });
bv.Or(bv_sec);
- BitVector bv_or = BitVector::Range(
+ BitVector bv_or = BitVector::RangeForTesting(
0, 1025, [](uint32_t i) { return i % 5 == 0 || i % 3 == 0; });
ASSERT_EQ(bv.CountSetBits(), bv_or.CountSetBits());
diff --git a/src/trace_processor/containers/row_map.cc b/src/trace_processor/containers/row_map.cc
index 4ec4e8d..f7925ae 100644
--- a/src/trace_processor/containers/row_map.cc
+++ b/src/trace_processor/containers/row_map.cc
@@ -217,8 +217,7 @@
RowMap::RowMap() : RowMap(Range()) {}
-RowMap::RowMap(uint32_t start, uint32_t end, OptimizeFor optimize_for)
- : data_(Range{start, end}), optimize_for_(optimize_for) {}
+RowMap::RowMap(uint32_t start, uint32_t end) : data_(Range{start, end}) {}
RowMap::RowMap(Variant def) : data_(std::move(def)) {}
diff --git a/src/trace_processor/containers/row_map.h b/src/trace_processor/containers/row_map.h
index a4e31b6..b8f1d3d 100644
--- a/src/trace_processor/containers/row_map.h
+++ b/src/trace_processor/containers/row_map.h
@@ -174,22 +174,13 @@
const RowMap* rm_ = nullptr;
};
- // Enum to allow users of RowMap to decide whether they want to optimize for
- // memory usage or for speed of lookups.
- enum class OptimizeFor {
- kMemory,
- kLookupSpeed,
- };
-
// Creates an empty RowMap.
// By default this will be implemented using a range.
RowMap();
// Creates a RowMap containing the range of indices between |start| and |end|
// i.e. all indices between |start| (inclusive) and |end| (exclusive).
- RowMap(OutputIndex start,
- OutputIndex end,
- OptimizeFor optimize_for = OptimizeFor::kMemory);
+ RowMap(OutputIndex start, OutputIndex end);
// Creates a RowMap backed by a BitVector.
explicit RowMap(BitVector);
@@ -514,58 +505,6 @@
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>
- 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.
- constexpr uint32_t kSmallRangeLimit = 2048;
- bool is_small_range = count < kSmallRangeLimit;
-
- // 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(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
- // index vector, use it instead. Alternatively, if we are optimizing for
- // lookup speed, we also want to use an index vector.
- if (is_small_range || index_vector_cost_ub <= bit_vector_cost ||
- optimize_for_ == OptimizeFor::kLookupSpeed) {
- // Try and strike a good balance between not making the vector too
- // big and good performance.
- IndexVector iv(std::min(kSmallRangeLimit, count));
-
- uint32_t out_i = 0;
- for (uint32_t i = 0; i < count; ++i) {
- // If we reach the capacity add another small set of indices.
- if (PERFETTO_UNLIKELY(out_i == iv.size()))
- iv.resize(iv.size() + kSmallRangeLimit);
-
- // 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 + r.start);
- iv[out_i] = i + r.start;
- out_i += value;
- }
-
- // Make the vector the correct size and as small as possible.
- iv.resize(out_i);
- iv.shrink_to_fit();
-
- 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.
- return BitVector::Range(r.start, r.end, p);
- }
-
PERFETTO_ALWAYS_INLINE static OutputIndex GetRange(Range r, InputRow row) {
return r.start + row;
}
@@ -596,7 +535,6 @@
}
Variant data_;
- OptimizeFor optimize_for_ = OptimizeFor::kMemory;
};
} // namespace trace_processor
diff --git a/src/trace_processor/containers/row_map_unittest.cc b/src/trace_processor/containers/row_map_unittest.cc
index 5af8b8c..28d5e0e 100644
--- a/src/trace_processor/containers/row_map_unittest.cc
+++ b/src/trace_processor/containers/row_map_unittest.cc
@@ -143,7 +143,7 @@
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; }));
+ BitVector::RangeForTesting(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);
@@ -158,7 +158,8 @@
}
TEST(RowMapUnittest, SelectRowsFromBVWithRange) {
- RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap rm(BitVector::RangeForTesting(10, 50,
+ [](uint32_t x) { return x % 2 == 0; }));
RowMap selector(4, 8);
RowMap selected = rm.SelectRows(selector);
@@ -167,17 +168,19 @@
}
TEST(RowMapUnittest, SelectRowsFromBVWithBV) {
- RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap rm(BitVector::RangeForTesting(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; }));
+ BitVector::RangeForTesting(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 rm(BitVector::RangeForTesting(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);
@@ -196,7 +199,7 @@
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; }));
+ BitVector::RangeForTesting(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);
diff --git a/src/trace_processor/db/BUILD.gn b/src/trace_processor/db/BUILD.gn
index cbd4304..7609e25 100644
--- a/src/trace_processor/db/BUILD.gn
+++ b/src/trace_processor/db/BUILD.gn
@@ -69,7 +69,6 @@
perfetto_unittest_source_set("unittests") {
testonly = true
sources = [
- "column_storage_overlay_unittest.cc",
"compare_unittest.cc",
"query_executor_unittest.cc",
"runtime_table_unittest.cc",
@@ -103,9 +102,6 @@
"../tables:tables_python",
"column",
]
- sources = [
- "column_storage_overlay_benchmark.cc",
- "query_executor_benchmark.cc",
- ]
+ sources = [ "query_executor_benchmark.cc" ]
}
}
diff --git a/src/trace_processor/db/column.cc b/src/trace_processor/db/column.cc
index b675695..1eb7c05 100644
--- a/src/trace_processor/db/column.cc
+++ b/src/trace_processor/db/column.cc
@@ -15,14 +15,16 @@
*/
#include "src/trace_processor/db/column.h"
-#include "perfetto/base/logging.h"
-#include "src/trace_processor/db/compare.h"
-#include "src/trace_processor/db/table.h"
-#include "src/trace_processor/util/glob.h"
-#include "src/trace_processor/util/regex.h"
+#include <cstdint>
+#include <limits>
-namespace perfetto {
-namespace trace_processor {
+#include "column/types.h"
+#include "column_storage.h"
+#include "column_storage_overlay.h"
+#include "perfetto/base/logging.h"
+#include "src/trace_processor/db/table.h"
+
+namespace perfetto::trace_processor {
ColumnLegacy::ColumnLegacy(const ColumnLegacy& column,
uint32_t col_idx,
@@ -50,446 +52,19 @@
ColumnLegacy ColumnLegacy::DummyColumn(const char* name,
uint32_t col_idx_in_table) {
- return ColumnLegacy(name, ColumnType::kDummy, Flag::kNoFlag, col_idx_in_table,
- std::numeric_limits<uint32_t>::max(), nullptr);
+ return {name,
+ ColumnType::kDummy,
+ Flag::kNoFlag,
+ col_idx_in_table,
+ std::numeric_limits<uint32_t>::max(),
+ nullptr};
}
ColumnLegacy ColumnLegacy::IdColumn(uint32_t col_idx,
uint32_t overlay_idx,
const char* name,
uint32_t flags) {
- return ColumnLegacy(name, ColumnType::kId, flags, col_idx, overlay_idx,
- nullptr);
-}
-
-void ColumnLegacy::StableSort(bool desc, std::vector<uint32_t>* idx) const {
- if (desc) {
- StableSort<true /* desc */>(idx);
- } else {
- StableSort<false /* desc */>(idx);
- }
-}
-
-void ColumnLegacy::FilterIntoSlow(FilterOp op,
- SqlValue value,
- RowMap* rm) const {
- switch (type_) {
- case ColumnType::kInt32: {
- if (IsNullable()) {
- FilterIntoNumericSlow<int32_t, true /* is_nullable */>(op, value, rm);
- } else {
- FilterIntoNumericSlow<int32_t, false /* is_nullable */>(op, value, rm);
- }
- break;
- }
- case ColumnType::kUint32: {
- if (IsNullable()) {
- FilterIntoNumericSlow<uint32_t, true /* is_nullable */>(op, value, rm);
- } else {
- FilterIntoNumericSlow<uint32_t, false /* is_nullable */>(op, value, rm);
- }
- break;
- }
- case ColumnType::kInt64: {
- if (IsNullable()) {
- FilterIntoNumericSlow<int64_t, true /* is_nullable */>(op, value, rm);
- } else {
- FilterIntoNumericSlow<int64_t, false /* is_nullable */>(op, value, rm);
- }
- break;
- }
- case ColumnType::kDouble: {
- if (IsNullable()) {
- FilterIntoNumericSlow<double, true /* is_nullable */>(op, value, rm);
- } else {
- FilterIntoNumericSlow<double, false /* is_nullable */>(op, value, rm);
- }
- break;
- }
- case ColumnType::kString: {
- FilterIntoStringSlow(op, value, rm);
- break;
- }
- case ColumnType::kId: {
- FilterIntoIdSlow(op, value, rm);
- break;
- }
- case ColumnType::kDummy:
- PERFETTO_FATAL("FilterIntoSlow not allowed on dummy column");
- }
-}
-
-template <typename T, bool is_nullable>
-void ColumnLegacy::FilterIntoNumericSlow(FilterOp op,
- SqlValue value,
- RowMap* rm) const {
- PERFETTO_DCHECK(IsNullable() == is_nullable);
- PERFETTO_DCHECK(type_ == ColumnTypeHelper<T>::ToColumnType());
- PERFETTO_DCHECK(std::is_arithmetic<T>::value);
-
- if (op == FilterOp::kIsNull) {
- PERFETTO_DCHECK(value.is_null());
- if (is_nullable) {
- overlay().FilterInto(rm, [this](uint32_t row) {
- return !storage<std::optional<T>>().Get(row).has_value();
- });
- } else {
- rm->Clear();
- }
- return;
- } else if (op == FilterOp::kIsNotNull) {
- PERFETTO_DCHECK(value.is_null());
- if (is_nullable) {
- overlay().FilterInto(rm, [this](uint32_t row) {
- return storage<std::optional<T>>().Get(row).has_value();
- });
- }
- return;
- }
-
- if (value.type == SqlValue::Type::kDouble) {
- double double_value = value.double_value;
- if (std::is_same<T, double>::value) {
- auto fn = [double_value](T v) {
- // We static cast here as this code will be compiled even when T ==
- // int64_t as we don't have if constexpr in C++11. In reality the cast
- // is a noop but we cannot statically verify that for the compiler.
- return compare::Numeric(static_cast<double>(v), double_value);
- };
- FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
- } else {
- auto fn = [double_value](T v) {
- // We static cast here as this code will be compiled even when T ==
- // double as we don't have if constexpr in C++11. In reality the cast
- // is a noop but we cannot statically verify that for the compiler.
- return compare::LongToDouble(static_cast<int64_t>(v), double_value);
- };
- FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
- }
- } else if (value.type == SqlValue::Type::kLong) {
- int64_t long_value = value.long_value;
- if (std::is_same<T, double>::value) {
- auto fn = [long_value](T v) {
- // We negate the return value as the long is always the first
- // parameter for this function even though the LHS of the comparator
- // should actually be |v|. This saves us having a duplicate
- // implementation of the comparision function.
- return -compare::LongToDouble(long_value, static_cast<double>(v));
- };
- FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
- } else {
- auto fn = [long_value](T v) {
- // We static cast here as this code will be compiled even when T ==
- // double as we don't have if constexpr in C++11. In reality the cast
- // is a noop but we cannot statically verify that for the compiler.
- return compare::Numeric(static_cast<int64_t>(v), long_value);
- };
- FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
- }
- } else {
- rm->Clear();
- }
-}
-
-template <typename T, bool is_nullable, typename Comparator>
-void ColumnLegacy::FilterIntoNumericWithComparatorSlow(FilterOp op,
- RowMap* rm,
- Comparator cmp) const {
- switch (op) {
- case FilterOp::kLt:
- overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
- if (is_nullable) {
- auto opt_value = storage<std::optional<T>>().Get(idx);
- return opt_value && cmp(*opt_value) < 0;
- }
- return cmp(storage<T>().Get(idx)) < 0;
- });
- break;
- case FilterOp::kEq:
- overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
- if (is_nullable) {
- auto opt_value = storage<std::optional<T>>().Get(idx);
- return opt_value && cmp(*opt_value) == 0;
- }
- return cmp(storage<T>().Get(idx)) == 0;
- });
- break;
- case FilterOp::kGt:
- overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
- if (is_nullable) {
- auto opt_value = storage<std::optional<T>>().Get(idx);
- return opt_value && cmp(*opt_value) > 0;
- }
- return cmp(storage<T>().Get(idx)) > 0;
- });
- break;
- case FilterOp::kNe:
- overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
- if (is_nullable) {
- auto opt_value = storage<std::optional<T>>().Get(idx);
- return opt_value && cmp(*opt_value) != 0;
- }
- return cmp(storage<T>().Get(idx)) != 0;
- });
- break;
- case FilterOp::kLe:
- overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
- if (is_nullable) {
- auto opt_value = storage<std::optional<T>>().Get(idx);
- return opt_value && cmp(*opt_value) <= 0;
- }
- return cmp(storage<T>().Get(idx)) <= 0;
- });
- break;
- case FilterOp::kGe:
- overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
- if (is_nullable) {
- auto opt_value = storage<std::optional<T>>().Get(idx);
- return opt_value && cmp(*opt_value) >= 0;
- }
- return cmp(storage<T>().Get(idx)) >= 0;
- });
- break;
- case FilterOp::kGlob:
- rm->Clear();
- break;
- case FilterOp::kRegex:
- case FilterOp::kIsNull:
- case FilterOp::kIsNotNull:
- PERFETTO_FATAL("Should be handled above");
- }
-}
-
-void ColumnLegacy::FilterIntoStringSlow(FilterOp op,
- SqlValue value,
- RowMap* rm) const {
- PERFETTO_DCHECK(type_ == ColumnType::kString);
-
- if (op == FilterOp::kIsNull) {
- PERFETTO_DCHECK(value.is_null());
- overlay().FilterInto(rm, [this](uint32_t row) {
- return GetStringPoolStringAtIdx(row).data() == nullptr;
- });
- return;
- } else if (op == FilterOp::kIsNotNull) {
- PERFETTO_DCHECK(value.is_null());
- overlay().FilterInto(rm, [this](uint32_t row) {
- return GetStringPoolStringAtIdx(row).data() != nullptr;
- });
- return;
- }
-
- if (value.type != SqlValue::Type::kString) {
- rm->Clear();
- return;
- }
-
- NullTermStringView str_value = value.string_value;
- PERFETTO_DCHECK(str_value.data() != nullptr);
-
- switch (op) {
- case FilterOp::kLt:
- overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && compare::String(v, str_value) < 0;
- });
- break;
- case FilterOp::kEq:
- overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && compare::String(v, str_value) == 0;
- });
- break;
- case FilterOp::kGt:
- overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && compare::String(v, str_value) > 0;
- });
- break;
- case FilterOp::kNe:
- overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && compare::String(v, str_value) != 0;
- });
- break;
- case FilterOp::kLe:
- overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && compare::String(v, str_value) <= 0;
- });
- break;
- case FilterOp::kGe:
- overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && compare::String(v, str_value) >= 0;
- });
- break;
- case FilterOp::kGlob: {
- util::GlobMatcher matcher = util::GlobMatcher::FromPattern(str_value);
- overlay().FilterInto(rm, [this, &matcher](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && matcher.Matches(v);
- });
- break;
- }
- case FilterOp::kRegex: {
- if constexpr (regex::IsRegexSupported()) {
- auto regex = regex::Regex::Create(str_value.c_str());
- if (!regex.status().ok()) {
- rm->Clear();
- break;
- }
- overlay().FilterInto(rm, [this, ®ex](uint32_t idx) {
- auto v = GetStringPoolStringAtIdx(idx);
- return v.data() != nullptr && regex->Search(v.c_str());
- });
- } else {
- PERFETTO_FATAL("Regex not supported");
- }
- break;
- }
- case FilterOp::kIsNull:
- case FilterOp::kIsNotNull:
- PERFETTO_FATAL("Should be handled above");
- }
-}
-
-void ColumnLegacy::FilterIntoIdSlow(FilterOp op,
- SqlValue value,
- RowMap* rm) const {
- PERFETTO_DCHECK(type_ == ColumnType::kId);
-
- if (op == FilterOp::kIsNull) {
- PERFETTO_DCHECK(value.is_null());
- rm->Clear();
- return;
- } else if (op == FilterOp::kIsNotNull) {
- PERFETTO_DCHECK(value.is_null());
- return;
- }
-
- if (value.type != SqlValue::Type::kLong) {
- rm->Clear();
- return;
- }
-
- uint32_t id_value = static_cast<uint32_t>(value.long_value);
- switch (op) {
- case FilterOp::kLt:
- overlay().FilterInto(rm, [id_value](uint32_t idx) {
- return compare::Numeric(idx, id_value) < 0;
- });
- break;
- case FilterOp::kEq:
- overlay().FilterInto(rm, [id_value](uint32_t idx) {
- return compare::Numeric(idx, id_value) == 0;
- });
- break;
- case FilterOp::kGt:
- overlay().FilterInto(rm, [id_value](uint32_t idx) {
- return compare::Numeric(idx, id_value) > 0;
- });
- break;
- case FilterOp::kNe:
- overlay().FilterInto(rm, [id_value](uint32_t idx) {
- return compare::Numeric(idx, id_value) != 0;
- });
- break;
- case FilterOp::kLe:
- overlay().FilterInto(rm, [id_value](uint32_t idx) {
- return compare::Numeric(idx, id_value) <= 0;
- });
- break;
- case FilterOp::kGe:
- overlay().FilterInto(rm, [id_value](uint32_t idx) {
- return compare::Numeric(idx, id_value) >= 0;
- });
- break;
- case FilterOp::kGlob:
- case FilterOp::kRegex:
- rm->Clear();
- break;
- case FilterOp::kIsNull:
- case FilterOp::kIsNotNull:
- PERFETTO_FATAL("Should be handled above");
- }
-}
-
-template <bool desc>
-void ColumnLegacy::StableSort(std::vector<uint32_t>* out) const {
- switch (type_) {
- case ColumnType::kInt32: {
- if (IsNullable()) {
- StableSortNumeric<desc, int32_t, true /* is_nullable */>(out);
- } else {
- StableSortNumeric<desc, int32_t, false /* is_nullable */>(out);
- }
- break;
- }
- case ColumnType::kUint32: {
- if (IsNullable()) {
- StableSortNumeric<desc, uint32_t, true /* is_nullable */>(out);
- } else {
- StableSortNumeric<desc, uint32_t, false /* is_nullable */>(out);
- }
- break;
- }
- case ColumnType::kInt64: {
- if (IsNullable()) {
- StableSortNumeric<desc, int64_t, true /* is_nullable */>(out);
- } else {
- StableSortNumeric<desc, int64_t, false /* is_nullable */>(out);
- }
- break;
- }
- case ColumnType::kDouble: {
- if (IsNullable()) {
- StableSortNumeric<desc, double, true /* is_nullable */>(out);
- } else {
- StableSortNumeric<desc, double, false /* is_nullable */>(out);
- }
- break;
- }
- case ColumnType::kString: {
- overlay().StableSort(out, [this](uint32_t a_idx, uint32_t b_idx) {
- auto a_str = GetStringPoolStringAtIdx(a_idx);
- auto b_str = GetStringPoolStringAtIdx(b_idx);
-
- int res = compare::NullableString(a_str, b_str);
- return desc ? res > 0 : res < 0;
- });
- break;
- }
- case ColumnType::kId:
- overlay().StableSort(out, [](uint32_t a_idx, uint32_t b_idx) {
- int res = compare::Numeric(a_idx, b_idx);
- return desc ? res > 0 : res < 0;
- });
- break;
- case ColumnType::kDummy:
- PERFETTO_FATAL("StableSort not allowed on dummy column");
- }
-}
-
-template <bool desc, typename T, bool is_nullable>
-void ColumnLegacy::StableSortNumeric(std::vector<uint32_t>* out) const {
- PERFETTO_DCHECK(IsNullable() == is_nullable);
- PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
-
- overlay().StableSort(out, [this](uint32_t a_idx, uint32_t b_idx) {
- if (is_nullable) {
- auto a_val = storage<std::optional<T>>().Get(a_idx);
- auto b_val = storage<std::optional<T>>().Get(b_idx);
-
- int res = compare::NullableNumeric(a_val, b_val);
- return desc ? res > 0 : res < 0;
- }
- auto a_val = storage<T>().Get(a_idx);
- auto b_val = storage<T>().Get(b_idx);
-
- int res = compare::Numeric(a_val, b_val);
- return desc ? res > 0 : res < 0;
- });
+ return {name, ColumnType::kId, flags, col_idx, overlay_idx, nullptr};
}
const ColumnStorageOverlay& ColumnLegacy::overlay() const {
@@ -497,5 +72,4 @@
return table_->overlays_[overlay_index()];
}
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/db/column.h b/src/trace_processor/db/column.h
index 988b12f..262b346 100644
--- a/src/trace_processor/db/column.h
+++ b/src/trace_processor/db/column.h
@@ -242,45 +242,6 @@
PERFETTO_FATAL("For GCC");
}
- // Sorts |idx| in ascending or descending order (determined by |desc|) based
- // on the contents of this column.
- void StableSort(bool desc, std::vector<uint32_t>* idx) const;
-
- // Updates the given RowMap by only keeping rows where this column meets the
- // given filter constraint.
- void FilterInto(FilterOp op, SqlValue value, RowMap* rm) const {
- if (IsId() && op == FilterOp::kEq) {
- // If this is an equality constraint on an id column, try and find the
- // single row with the id (if it exists).
- auto opt_idx = IndexOf(value);
- if (opt_idx) {
- rm->IntersectExact(*opt_idx);
- } else {
- rm->Clear();
- }
- return;
- }
-
- if (IsSetId() && op == FilterOp::kEq && value.type == SqlValue::kLong) {
- // If the column is sorted and the value has the same type as the column,
- // we should be able to just do a binary search to find the range of rows
- // instead of a full table scan.
- FilterIntoSetIdEq(value.AsLong(), rm);
- return;
- }
-
- if (IsSorted() && value.type == type()) {
- // If the column is sorted and the value has the same type as the column,
- // we should be able to just do a binary search to find the range of rows
- // instead of a full table scan.
- bool handled = FilterIntoSorted(op, value, rm);
- if (handled)
- return;
- }
-
- FilterIntoSlow(op, value, rm);
- }
-
// Returns the minimum value in this column. Returns std::nullopt if this
// column is empty.
std::optional<SqlValue> Min() const {
@@ -495,122 +456,6 @@
return ToSqlValue(storage<T>().Get(idx));
}
- // Optimized filter method for sorted columns.
- // Returns whether the constraint was handled by the method.
- bool FilterIntoSorted(FilterOp op, SqlValue value, RowMap* rm) const {
- PERFETTO_DCHECK(IsSorted());
- PERFETTO_DCHECK(value.type == type());
-
- Iterator b(this, 0);
- Iterator e(this, overlay().size());
- switch (op) {
- case FilterOp::kEq: {
- uint32_t beg = std::distance(
- 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});
- return true;
- }
- case FilterOp::kLe: {
- uint32_t end = std::distance(
- b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
- 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});
- return true;
- }
- case FilterOp::kGe: {
- uint32_t beg = std::distance(
- b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
- 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()});
- return true;
- }
- case FilterOp::kNe:
- case FilterOp::kIsNull:
- case FilterOp::kIsNotNull:
- case FilterOp::kGlob:
- case FilterOp::kRegex:
- break;
- }
- return false;
- }
-
- void FilterIntoSetIdEq(int64_t value, RowMap* rm) const {
- PERFETTO_DCHECK(!IsNullable());
-
- uint32_t filter_set_id = static_cast<uint32_t>(value);
- const auto& st = storage<uint32_t>();
- const ColumnStorageOverlay& ov = overlay();
-
- // If the set id is beyond the end of the column, there's no chance that
- // it exists.
- if (PERFETTO_UNLIKELY(filter_set_id >= st.size())) {
- rm->Clear();
- return;
- }
-
- uint32_t set_id = st.Get(ov.Get(filter_set_id));
-
- // If the set at that index does not equal the set id we're looking for, the
- // set id doesn't exist either.
- if (PERFETTO_UNLIKELY(set_id != filter_set_id)) {
- PERFETTO_DCHECK(set_id < filter_set_id);
- rm->Clear();
- return;
- }
-
- // 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) {
- RowMap r(set_id, i);
- rm->Intersect(r);
- return;
- }
- }
- RowMap r(set_id, ov.size());
- rm->Intersect(r);
- }
-
- // Slow path filter method which will perform a full table scan.
- void FilterIntoSlow(FilterOp op, SqlValue value, RowMap* rm) const;
-
- // Slow path filter method for numerics which will perform a full table scan.
- template <typename T, bool is_nullable>
- void FilterIntoNumericSlow(FilterOp op, SqlValue value, RowMap* rm) const;
-
- // Slow path filter method for numerics with a comparator which will perform a
- // full table scan.
- template <typename T, bool is_nullable, typename Comparator = int(T)>
- void FilterIntoNumericWithComparatorSlow(FilterOp op,
- RowMap* rm,
- Comparator cmp) const;
-
- // Slow path filter method for strings which will perform a full table scan.
- void FilterIntoStringSlow(FilterOp op, SqlValue value, RowMap* rm) const;
-
- // Slow path filter method for ids which will perform a full table scan.
- void FilterIntoIdSlow(FilterOp op, SqlValue value, RowMap* rm) const;
-
- // Stable sorts this column storing the result in |out|.
- template <bool desc>
- void StableSort(std::vector<uint32_t>* out) const;
-
- // Stable sorts this column storing the result in |out|.
- // |T| and |is_nullable| should match the type and nullability of this column.
- template <bool desc, typename T, bool is_nullable>
- void StableSortNumeric(std::vector<uint32_t>* out) const;
-
static constexpr bool IsDense(uint32_t flags) {
return (flags & Flag::kDense) != 0;
}
diff --git a/src/trace_processor/db/column/BUILD.gn b/src/trace_processor/db/column/BUILD.gn
index 786fb91..74d1611 100644
--- a/src/trace_processor/db/column/BUILD.gn
+++ b/src/trace_processor/db/column/BUILD.gn
@@ -55,22 +55,6 @@
]
}
-source_set("make_chain_minimal") {
- sources = [ "make_chain_minimal.cc" ]
- deps = [
- ":column",
- "../../../../gn:default_deps",
- ]
-}
-
-source_set("make_chain") {
- sources = [ "make_chain.cc" ]
- deps = [
- ":column",
- "../../../../gn:default_deps",
- ]
-}
-
perfetto_unittest_source_set("fake_storage") {
testonly = true
sources = [
diff --git a/src/trace_processor/db/column/arrangement_overlay.cc b/src/trace_processor/db/column/arrangement_overlay.cc
index 7325689..281071f 100644
--- a/src/trace_processor/db/column/arrangement_overlay.cc
+++ b/src/trace_processor/db/column/arrangement_overlay.cc
@@ -34,10 +34,6 @@
namespace perfetto::trace_processor::column {
-ArrangementOverlay::ArrangementOverlay(const std::vector<uint32_t>* arrangement,
- Indices::State arrangement_state)
- : arrangement_(arrangement), arrangement_state_(arrangement_state) {}
-
ArrangementOverlay::ChainImpl::ChainImpl(
std::unique_ptr<DataLayerChain> inner,
const std::vector<uint32_t>* arrangement,
@@ -58,6 +54,13 @@
return inner_->SingleSearch(op, sql_val, (*arrangement_)[index]);
}
+UniqueSearchResult ArrangementOverlay::ChainImpl::UniqueSearch(
+ FilterOp,
+ SqlValue,
+ uint32_t*) const {
+ return UniqueSearchResult::kNeedsFullSearch;
+}
+
SearchValidationResult ArrangementOverlay::ChainImpl::ValidateSearchConstraints(
FilterOp op,
SqlValue value) const {
diff --git a/src/trace_processor/db/column/arrangement_overlay.h b/src/trace_processor/db/column/arrangement_overlay.h
index 9a52aa0..6138918 100644
--- a/src/trace_processor/db/column/arrangement_overlay.h
+++ b/src/trace_processor/db/column/arrangement_overlay.h
@@ -36,10 +36,11 @@
public:
ArrangementOverlay(const std::vector<uint32_t>* arrangement,
Indices::State arrangement_state);
+ ~ArrangementOverlay() override;
std::unique_ptr<DataLayerChain> MakeChain(
std::unique_ptr<DataLayerChain>,
- ChainCreationArgs = ChainCreationArgs()) override;
+ ChainCreationArgs = ChainCreationArgs());
private:
class ChainImpl : public DataLayerChain {
@@ -53,6 +54,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/arrangement_overlay_unittest.cc b/src/trace_processor/db/column/arrangement_overlay_unittest.cc
index dd9a28e..07f13c0 100644
--- a/src/trace_processor/db/column/arrangement_overlay_unittest.cc
+++ b/src/trace_processor/db/column/arrangement_overlay_unittest.cc
@@ -37,9 +37,9 @@
TEST(ArrangementOverlay, SingleSearch) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- auto fake = FakeStorage::SearchSubset(5, std::vector<uint32_t>{1, 2});
+ auto fake = FakeStorageChain::SearchSubset(5, std::vector<uint32_t>{1, 2});
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kGe, SqlValue::Long(0u), 8),
SingleSearchResult::kMatch);
@@ -49,9 +49,9 @@
TEST(ArrangementOverlay, SearchAll) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- auto fake = FakeStorage::SearchAll(5);
+ auto fake = FakeStorageChain::SearchAll(5);
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2u, 3u));
@@ -59,9 +59,9 @@
TEST(ArrangementOverlay, SearchNone) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- auto fake = FakeStorage::SearchNone(5);
+ auto fake = FakeStorageChain::SearchNone(5);
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
@@ -69,9 +69,9 @@
TEST(ArrangementOverlay, DISABLED_SearchLimited) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- auto fake = FakeStorage::SearchSubset(5, Range(4, 5));
+ auto fake = FakeStorageChain::SearchSubset(5, Range(4, 5));
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 7));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(6u));
@@ -79,10 +79,10 @@
TEST(ArrangementOverlay, SearchBitVector) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- auto fake = FakeStorage::SearchSubset(
+ auto fake = FakeStorageChain::SearchSubset(
5, BitVector({false, true, false, true, false}));
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
// Table bv:
// 1, 1, 0, 0, 1, 1, 0, 0, 1, 1
@@ -92,10 +92,10 @@
TEST(ArrangementOverlay, IndexSearch) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- auto fake = FakeStorage::SearchSubset(
+ auto fake = FakeStorageChain::SearchSubset(
5, BitVector({false, true, false, true, false}));
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{7u, 1u, 3u};
RangeOrBitVector res = chain->IndexSearch(
@@ -108,11 +108,11 @@
TEST(ArrangementOverlay, OrderingSearch) {
std::vector<uint32_t> arrangement{0, 2, 4, 1, 3};
- auto fake = FakeStorage::SearchSubset(
+ auto fake = FakeStorageChain::SearchSubset(
5, BitVector({false, true, false, true, false}));
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
auto chain =
- storage.MakeChain(fake->MakeChain(), DataLayer::ChainCreationArgs(true));
+ storage.MakeChain(std::move(fake), DataLayer::ChainCreationArgs(true));
RangeOrBitVector res =
chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 5));
diff --git a/src/trace_processor/db/column/data_layer.cc b/src/trace_processor/db/column/data_layer.cc
index d4bbcba..c8f8b68 100644
--- a/src/trace_processor/db/column/data_layer.cc
+++ b/src/trace_processor/db/column/data_layer.cc
@@ -16,9 +16,213 @@
#include "src/trace_processor/db/column/data_layer.h"
+#include <cstdint>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/logging.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/string_pool.h"
+#include "src/trace_processor/db/column/arrangement_overlay.h"
+#include "src/trace_processor/db/column/dense_null_overlay.h"
+#include "src/trace_processor/db/column/dummy_storage.h"
+#include "src/trace_processor/db/column/id_storage.h"
+#include "src/trace_processor/db/column/null_overlay.h"
+#include "src/trace_processor/db/column/numeric_storage.h"
+#include "src/trace_processor/db/column/range_overlay.h"
+#include "src/trace_processor/db/column/selector_overlay.h"
+#include "src/trace_processor/db/column/set_id_storage.h"
+#include "src/trace_processor/db/column/string_storage.h"
+#include "src/trace_processor/db/column/types.h"
+
namespace perfetto::trace_processor::column {
DataLayer::~DataLayer() = default;
DataLayerChain::~DataLayerChain() = default;
+// All the below code exists as machinery to allow dead-code-elimination
+// and linker symbol stripping to work for trace processor built into Chrome. It
+// is ugly and hacky but is the only way we could come up with to actually meet
+// both performance constraints and saving binary size in Chrome.
+//
+// TODO(b/325583551): investigate whether we can improve this at some point,
+// potentially removing this if Chrome no longer relies on trace processor for
+// JSON export.
+
+std::unique_ptr<DataLayerChain> DataLayer::MakeChain() {
+ switch (impl_) {
+ case Impl::kDummy:
+ return static_cast<DummyStorage*>(this)->MakeChain();
+ case Impl::kId:
+ return static_cast<IdStorage*>(this)->MakeChain();
+ case Impl::kNumericDouble:
+ return static_cast<NumericStorage<double>*>(this)->MakeChain();
+ case Impl::kNumericUint32:
+ return static_cast<NumericStorage<uint32_t>*>(this)->MakeChain();
+ case Impl::kNumericInt32:
+ return static_cast<NumericStorage<int32_t>*>(this)->MakeChain();
+ case Impl::kNumericInt64:
+ return static_cast<NumericStorage<int64_t>*>(this)->MakeChain();
+ case Impl::kSetId:
+ return static_cast<SetIdStorage*>(this)->MakeChain();
+ case Impl::kString:
+ return static_cast<StringStorage*>(this)->MakeChain();
+ case Impl::kArrangement:
+ case Impl::kDenseNull:
+ case Impl::kNull:
+ case Impl::kRange:
+ case Impl::kSelector:
+ PERFETTO_FATAL(
+ "Unexpected call to MakeChain(). MakeChain(DataLayerChain) should be "
+ "called instead");
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+std::unique_ptr<DataLayerChain> DataLayer::MakeChain(
+ std::unique_ptr<DataLayerChain> inner,
+ ChainCreationArgs args) {
+ switch (impl_) {
+ case Impl::kArrangement:
+ return static_cast<ArrangementOverlay*>(this)->MakeChain(std::move(inner),
+ args);
+ case Impl::kDenseNull:
+ return static_cast<DenseNullOverlay*>(this)->MakeChain(std::move(inner),
+ args);
+ case Impl::kNull:
+ return static_cast<NullOverlay*>(this)->MakeChain(std::move(inner), args);
+ case Impl::kRange:
+ return static_cast<RangeOverlay*>(this)->MakeChain(std::move(inner),
+ args);
+ case Impl::kSelector:
+ return static_cast<SelectorOverlay*>(this)->MakeChain(std::move(inner),
+ args);
+ case Impl::kDummy:
+ case Impl::kId:
+ case Impl::kNumericDouble:
+ case Impl::kNumericUint32:
+ case Impl::kNumericInt32:
+ case Impl::kNumericInt64:
+ case Impl::kSetId:
+ case Impl::kString:
+ PERFETTO_FATAL(
+ "Unexpected call to MakeChain(DataLayerChain). MakeChain() should be "
+ "called instead");
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+ArrangementOverlay::ArrangementOverlay(const std::vector<uint32_t>* arrangement,
+ Indices::State arrangement_state)
+ : DataLayer(Impl::kArrangement),
+ arrangement_(arrangement),
+ arrangement_state_(arrangement_state) {}
+ArrangementOverlay::~ArrangementOverlay() = default;
+
+std::unique_ptr<DataLayerChain> ArrangementOverlay::MakeChain(
+ std::unique_ptr<DataLayerChain> inner,
+ ChainCreationArgs args) {
+ return std::make_unique<ChainImpl>(std::move(inner), arrangement_,
+ arrangement_state_,
+ args.does_layer_order_chain_contents);
+}
+
+DenseNullOverlay::DenseNullOverlay(const BitVector* non_null)
+ : DataLayer(Impl::kDenseNull), non_null_(non_null) {}
+DenseNullOverlay::~DenseNullOverlay() = default;
+
+std::unique_ptr<DataLayerChain> DenseNullOverlay::MakeChain(
+ std::unique_ptr<DataLayerChain> inner,
+ ChainCreationArgs) {
+ return std::make_unique<ChainImpl>(std::move(inner), non_null_);
+}
+
+std::unique_ptr<DataLayerChain> DummyStorage::MakeChain() {
+ return std::make_unique<ChainImpl>();
+}
+
+IdStorage::IdStorage() : DataLayer(Impl::kId) {}
+IdStorage::~IdStorage() = default;
+
+std::unique_ptr<DataLayerChain> IdStorage::MakeChain() {
+ return std::make_unique<ChainImpl>();
+}
+
+NullOverlay::NullOverlay(const BitVector* non_null)
+ : DataLayer(Impl::kNull), non_null_(non_null) {}
+NullOverlay::~NullOverlay() = default;
+
+std::unique_ptr<DataLayerChain> NullOverlay::MakeChain(
+ std::unique_ptr<DataLayerChain> inner,
+ ChainCreationArgs) {
+ return std::make_unique<ChainImpl>(std::move(inner), non_null_);
+}
+
+NumericStorageBase::NumericStorageBase(ColumnType type,
+ bool is_sorted,
+ Impl impl)
+ : DataLayer(impl), storage_type_(type), is_sorted_(is_sorted) {}
+
+NumericStorageBase::~NumericStorageBase() = default;
+
+template <typename T>
+std::unique_ptr<DataLayerChain> NumericStorage<T>::MakeChain() {
+ return std::make_unique<ChainImpl>(vector_, storage_type_, is_sorted_);
+}
+
+template <typename T>
+NumericStorage<T>::NumericStorage(const std::vector<T>* vec,
+ ColumnType type,
+ bool is_sorted)
+ : NumericStorageBase(type, is_sorted, GetImpl()), vector_(vec) {}
+
+// Define explicit instantiation of the necessary templates here to reduce
+// binary size bloat.
+template class NumericStorage<double>;
+template class NumericStorage<uint32_t>;
+template class NumericStorage<int32_t>;
+template class NumericStorage<int64_t>;
+
+RangeOverlay::RangeOverlay(const Range* range)
+ : DataLayer(Impl::kRange), range_(range) {}
+RangeOverlay::~RangeOverlay() = default;
+
+std::unique_ptr<DataLayerChain> RangeOverlay::MakeChain(
+ std::unique_ptr<DataLayerChain> inner,
+ ChainCreationArgs) {
+ return std::make_unique<ChainImpl>(std::move(inner), range_);
+}
+
+SelectorOverlay::SelectorOverlay(const BitVector* selector)
+ : DataLayer(Impl::kSelector), selector_(selector) {}
+SelectorOverlay::~SelectorOverlay() = default;
+
+std::unique_ptr<DataLayerChain> SelectorOverlay::MakeChain(
+ std::unique_ptr<DataLayerChain> inner,
+ ChainCreationArgs) {
+ return std::make_unique<ChainImpl>(std::move(inner), selector_);
+}
+
+SetIdStorage::SetIdStorage(const std::vector<uint32_t>* values)
+ : DataLayer(Impl::kSetId), values_(values) {}
+SetIdStorage::~SetIdStorage() = default;
+
+std::unique_ptr<DataLayerChain> SetIdStorage::MakeChain() {
+ return std::make_unique<ChainImpl>(values_);
+}
+
+StringStorage::StringStorage(StringPool* string_pool,
+ const std::vector<StringPool::Id>* data,
+ bool is_sorted)
+ : DataLayer(Impl::kString),
+ data_(data),
+ string_pool_(string_pool),
+ is_sorted_(is_sorted) {}
+StringStorage::~StringStorage() = default;
+
+std::unique_ptr<DataLayerChain> StringStorage::MakeChain() {
+ return std::make_unique<ChainImpl>(string_pool_, data_, is_sorted_);
+}
+
} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/data_layer.h b/src/trace_processor/db/column/data_layer.h
index 809a4e3..5ec7909 100644
--- a/src/trace_processor/db/column/data_layer.h
+++ b/src/trace_processor/db/column/data_layer.h
@@ -50,22 +50,39 @@
// orders a given chain.
bool does_layer_order_chain_contents;
};
-
virtual ~DataLayer();
// Creates a DataLayerChain for a terminal DataLayer. This means the
// DataLayer directly should return the data it contains inside.
- virtual std::unique_ptr<DataLayerChain> MakeChain() {
- PERFETTO_FATAL("Unimplemented");
- }
+ std::unique_ptr<DataLayerChain> MakeChain();
// Creates a DataLayerChain for a non-terminal DataLayer. This means
// the DataLayer should transform the contents of the inner chain.
- virtual std::unique_ptr<DataLayerChain> MakeChain(
+ std::unique_ptr<DataLayerChain> MakeChain(
std::unique_ptr<DataLayerChain>,
- ChainCreationArgs = ChainCreationArgs()) {
- PERFETTO_FATAL("Unimplemented");
- }
+ ChainCreationArgs = ChainCreationArgs());
+
+ protected:
+ // TODO(b/325583551): remove this when possible.
+ enum class Impl {
+ kArrangement,
+ kDenseNull,
+ kDummy,
+ kId,
+ kNull,
+ kNumericDouble,
+ kNumericUint32,
+ kNumericInt32,
+ kNumericInt64,
+ kRange,
+ kSelector,
+ kSetId,
+ kString,
+ };
+ explicit DataLayer(Impl impl) : impl_(impl) {}
+
+ private:
+ Impl impl_;
};
// Corresponds to a series of DataLayer chained together. Provides
@@ -96,11 +113,27 @@
// Checks whether element at the the provided index match |op| and |value|.
//
- // Returns true if the element matches, false otherwise.
+ // Returns one of the following:
+ // * kMatch if the element matches.
+ // * kNoMatch if the element does not match.
+ // * kNeedsFullSearch if one of the "full" search algorithms need to be
+ // run to determine if the element matches.
virtual SingleSearchResult SingleSearch(FilterOp op,
SqlValue value,
uint32_t row) const = 0;
+ // Searches for a *unique* element in chain which matches |op| and |value|.
+ //
+ // The return value is one of the following:
+ // * kMatch if an element matches. |row| should be set to the index of
+ // the element.
+ // * kNoMatch if no element matches.
+ // * kNeedsFullSearch if one of the "full" search algorithms need to be
+ // run for this constraint.
+ virtual UniqueSearchResult UniqueSearch(FilterOp op,
+ SqlValue value,
+ uint32_t* row) const = 0;
+
// Searches for elements which match |op| and |value| between |range.start|
// and |range.end|.
//
diff --git a/src/trace_processor/db/column/dense_null_overlay.cc b/src/trace_processor/db/column/dense_null_overlay.cc
index fcd22bb..e7251a3 100644
--- a/src/trace_processor/db/column/dense_null_overlay.cc
+++ b/src/trace_processor/db/column/dense_null_overlay.cc
@@ -34,9 +34,6 @@
namespace perfetto::trace_processor::column {
-DenseNullOverlay::DenseNullOverlay(const BitVector* non_null)
- : non_null_(non_null) {}
-
DenseNullOverlay::ChainImpl::ChainImpl(std::unique_ptr<DataLayerChain> inner,
const BitVector* non_null)
: inner_(std::move(inner)), non_null_(non_null) {}
@@ -64,6 +61,27 @@
PERFETTO_FATAL("For GCC");
}
+UniqueSearchResult DenseNullOverlay::ChainImpl::UniqueSearch(
+ FilterOp op,
+ SqlValue sql_val,
+ uint32_t* index) const {
+ switch (inner_->UniqueSearch(op, sql_val, index)) {
+ case UniqueSearchResult::kMatch:
+ if (*index >= non_null_->size()) {
+ return UniqueSearchResult::kNoMatch;
+ }
+ // If non_null_[index] is not set, then any result returned by |inner_| is
+ // meaningless as the value in |inner_| is not a "real" value.
+ return non_null_->IsSet(*index) ? UniqueSearchResult::kMatch
+ : UniqueSearchResult::kNeedsFullSearch;
+ case UniqueSearchResult::kNoMatch:
+ return UniqueSearchResult::kNoMatch;
+ case UniqueSearchResult::kNeedsFullSearch:
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
SearchValidationResult DenseNullOverlay::ChainImpl::ValidateSearchConstraints(
FilterOp op,
SqlValue sql_val) const {
diff --git a/src/trace_processor/db/column/dense_null_overlay.h b/src/trace_processor/db/column/dense_null_overlay.h
index f2e4480..4acec46 100644
--- a/src/trace_processor/db/column/dense_null_overlay.h
+++ b/src/trace_processor/db/column/dense_null_overlay.h
@@ -34,10 +34,11 @@
class DenseNullOverlay final : public DataLayer {
public:
explicit DenseNullOverlay(const BitVector* non_null);
+ ~DenseNullOverlay() override;
std::unique_ptr<DataLayerChain> MakeChain(
std::unique_ptr<DataLayerChain>,
- ChainCreationArgs = ChainCreationArgs()) override;
+ ChainCreationArgs = ChainCreationArgs());
private:
class ChainImpl : public DataLayerChain {
@@ -48,6 +49,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/dense_null_overlay_unittest.cc b/src/trace_processor/db/column/dense_null_overlay_unittest.cc
index af6c9c7..1678857 100644
--- a/src/trace_processor/db/column/dense_null_overlay_unittest.cc
+++ b/src/trace_processor/db/column/dense_null_overlay_unittest.cc
@@ -17,6 +17,7 @@
#include "src/trace_processor/db/column/dense_null_overlay.h"
#include <cstdint>
+#include <limits>
#include <memory>
#include <vector>
@@ -62,33 +63,33 @@
}
TEST(DenseNullOverlay, RangeFilterSearch) {
- auto fake = FakeStorage::SearchSubset(5, Range(1, 3));
+ auto fake = FakeStorageChain::SearchSubset(5, Range(1, 3));
BitVector bv{0, 1, 0, 1, 0};
DenseNullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
}
TEST(DenseNullOverlay, BitvectorFilterSearch) {
- auto fake = FakeStorage::SearchSubset(5, BitVector({0, 1, 1, 0, 0}));
+ auto fake = FakeStorageChain::SearchSubset(5, BitVector({0, 1, 1, 0, 0}));
BitVector bv{0, 1, 0, 1, 0};
DenseNullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
}
TEST(DenseNullOverlay, IsNullSearch) {
- auto fake = FakeStorage::SearchSubset(5, BitVector({1, 1, 0, 0, 1}));
+ auto fake = FakeStorageChain::SearchSubset(5, BitVector({1, 1, 0, 0, 1}));
BitVector bv{1, 0, 0, 1, 1};
DenseNullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kIsNull, SqlValue(), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4));
@@ -112,11 +113,11 @@
}
TEST(DenseNullOverlay, IsNullIndexSearch) {
- auto fake = FakeStorage::SearchSubset(6, BitVector({0, 0, 0, 1, 1, 1}));
+ auto fake = FakeStorageChain::SearchSubset(6, BitVector({0, 0, 0, 1, 1, 1}));
BitVector bv{0, 1, 0, 1, 1, 1};
DenseNullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> index({5, 2, 3, 4, 1});
auto res = chain->IndexSearch(
@@ -127,11 +128,11 @@
}
TEST(DenseNullOverlay, OrderedIndexSearch) {
- auto fake = FakeStorage::SearchSubset(6, BitVector({0, 1, 0, 1, 0, 1}));
+ auto fake = FakeStorageChain::SearchSubset(6, BitVector({0, 1, 0, 1, 0, 1}));
BitVector bv{0, 1, 0, 1, 0, 1};
DenseNullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> indices_vec({0, 2, 4, 1, 3, 5});
Indices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
@@ -168,8 +169,8 @@
TEST(DenseNullOverlay, SingleSearch) {
BitVector bv{0, 1, 0, 1, 1, 1};
DenseNullOverlay storage(&bv);
- auto fake = FakeStorage::SearchSubset(5, std::vector<uint32_t>{1, 2});
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto fake = FakeStorageChain::SearchSubset(5, std::vector<uint32_t>{1, 2});
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kGe, SqlValue::Long(0u), 1),
SingleSearchResult::kMatch);
@@ -180,8 +181,8 @@
TEST(DenseNullOverlay, SingleSearchIsNull) {
BitVector bv{0, 1, 0, 1, 1, 1};
DenseNullOverlay storage(&bv);
- auto fake = FakeStorage::SearchNone(5);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto fake = FakeStorageChain::SearchNone(5);
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kIsNull, SqlValue(), 0),
SingleSearchResult::kMatch);
@@ -192,8 +193,8 @@
TEST(DenseNullOverlay, SingleSearchIsNotNull) {
BitVector bv{0, 1, 0, 1, 1, 1};
DenseNullOverlay storage(&bv);
- auto fake = FakeStorage::SearchAll(5);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto fake = FakeStorageChain::SearchAll(5);
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kIsNotNull, SqlValue(), 0),
SingleSearchResult::kNoMatch);
@@ -201,6 +202,40 @@
SingleSearchResult::kMatch);
}
+TEST(DenseNullOverlay, UniqueSearchNonNull) {
+ BitVector bv{0, 1, 0, 1, 1};
+ DenseNullOverlay storage(&bv);
+ auto fake = FakeStorageChain::SearchSubset(5, Range(1, 2));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kMatch);
+ ASSERT_EQ(row, 1u);
+}
+
+TEST(DenseNullOverlay, UniqueSearchNull) {
+ BitVector bv{0, 0, 0, 1, 1};
+ DenseNullOverlay storage(&bv);
+ auto fake = FakeStorageChain::SearchSubset(5, Range(1, 2));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kNeedsFullSearch);
+}
+
+TEST(DenseNullOverlay, UniqueSearchOutOfBounds) {
+ BitVector bv{0, 0, 0, 1, 1};
+ DenseNullOverlay storage(&bv);
+ auto fake = FakeStorageChain::SearchSubset(6, Range(5, 6));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kNoMatch);
+}
+
TEST(DenseNullOverlay, StableSort) {
std::vector<uint32_t> numeric_data{0, 3, 0, 1, 0, 2, 4};
NumericStorage<uint32_t> numeric(&numeric_data, ColumnType::kUint32, false);
diff --git a/src/trace_processor/db/column/dummy_storage.cc b/src/trace_processor/db/column/dummy_storage.cc
index 71a3a5c..0f182f8 100644
--- a/src/trace_processor/db/column/dummy_storage.cc
+++ b/src/trace_processor/db/column/dummy_storage.cc
@@ -17,7 +17,6 @@
#include "src/trace_processor/db/column/dummy_storage.h"
#include <cstdint>
-#include <memory>
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
@@ -32,6 +31,12 @@
PERFETTO_FATAL("Shouldn't be called");
}
+UniqueSearchResult DummyStorage::ChainImpl::UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const {
+ PERFETTO_FATAL("Shouldn't be called");
+}
+
SearchValidationResult DummyStorage::ChainImpl::ValidateSearchConstraints(
FilterOp,
SqlValue) const {
diff --git a/src/trace_processor/db/column/dummy_storage.h b/src/trace_processor/db/column/dummy_storage.h
index b723c2e..286c1ea 100644
--- a/src/trace_processor/db/column/dummy_storage.h
+++ b/src/trace_processor/db/column/dummy_storage.h
@@ -38,6 +38,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
@@ -61,7 +65,7 @@
std::string DebugString() const override { return "DummyStorage"; }
};
- std::unique_ptr<DataLayerChain> MakeChain() override;
+ std::unique_ptr<DataLayerChain> MakeChain();
};
} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/fake_storage.cc b/src/trace_processor/db/column/fake_storage.cc
index efe7bee..1bab025 100644
--- a/src/trace_processor/db/column/fake_storage.cc
+++ b/src/trace_processor/db/column/fake_storage.cc
@@ -19,7 +19,6 @@
#include <algorithm>
#include <cstdint>
#include <iterator>
-#include <memory>
#include <utility>
#include "perfetto/base/logging.h"
@@ -30,26 +29,18 @@
namespace perfetto::trace_processor::column {
-FakeStorage::FakeStorage(uint32_t size, SearchStrategy strategy)
- : size_(size), strategy_(strategy) {}
-
-std::unique_ptr<DataLayerChain> FakeStorage::MakeChain() {
- return std::make_unique<ChainImpl>(size_, strategy_, range_,
- bit_vector_.Copy());
-}
-
-FakeStorage::ChainImpl::ChainImpl(uint32_t size,
- SearchStrategy strategy,
- Range range,
- BitVector bv)
+FakeStorageChain::FakeStorageChain(uint32_t size,
+ SearchStrategy strategy,
+ Range range,
+ BitVector bv)
: size_(size),
strategy_(strategy),
range_(range),
bit_vector_(std::move(bv)) {}
-SingleSearchResult FakeStorage::ChainImpl::SingleSearch(FilterOp,
- SqlValue,
- uint32_t i) const {
+SingleSearchResult FakeStorageChain::SingleSearch(FilterOp,
+ SqlValue,
+ uint32_t i) const {
switch (strategy_) {
case kAll:
return SingleSearchResult::kMatch;
@@ -65,15 +56,43 @@
PERFETTO_FATAL("For GCC");
}
-SearchValidationResult FakeStorage::ChainImpl::ValidateSearchConstraints(
+UniqueSearchResult FakeStorageChain::UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t* i) const {
+ switch (strategy_) {
+ case kAll:
+ if (size_ != 1) {
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ *i = 0;
+ return UniqueSearchResult::kMatch;
+ case kNone:
+ return UniqueSearchResult::kNoMatch;
+ case kBitVector:
+ if (bit_vector_.CountSetBits() != 1) {
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ *i = bit_vector_.IndexOfNthSet(0);
+ return UniqueSearchResult::kMatch;
+ case kRange:
+ if (range_.size() != 1) {
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ *i = range_.start;
+ return UniqueSearchResult::kMatch;
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
+SearchValidationResult FakeStorageChain::ValidateSearchConstraints(
FilterOp,
SqlValue) const {
return SearchValidationResult::kOk;
}
-RangeOrBitVector FakeStorage::ChainImpl::SearchValidated(FilterOp,
- SqlValue,
- Range in) const {
+RangeOrBitVector FakeStorageChain::SearchValidated(FilterOp,
+ SqlValue,
+ Range in) const {
switch (strategy_) {
case kAll:
return RangeOrBitVector(in);
@@ -91,10 +110,9 @@
PERFETTO_FATAL("For GCC");
}
-RangeOrBitVector FakeStorage::ChainImpl::IndexSearchValidated(
- FilterOp,
- SqlValue,
- Indices indices) const {
+RangeOrBitVector FakeStorageChain::IndexSearchValidated(FilterOp,
+ SqlValue,
+ Indices indices) const {
switch (strategy_) {
case kAll:
return RangeOrBitVector(Range(0, indices.size));
@@ -115,10 +133,9 @@
PERFETTO_FATAL("For GCC");
}
-Range FakeStorage::ChainImpl::OrderedIndexSearchValidated(
- FilterOp,
- SqlValue,
- Indices indices) const {
+Range FakeStorageChain::OrderedIndexSearchValidated(FilterOp,
+ SqlValue,
+ Indices indices) const {
if (strategy_ == kAll) {
return {0, indices.size};
}
@@ -152,13 +169,11 @@
static_cast<uint32_t>(std::distance(indices.data, first_non_set))};
}
-void FakeStorage::ChainImpl::StableSort(SortToken*,
- SortToken*,
- SortDirection) const {
+void FakeStorageChain::StableSort(SortToken*, SortToken*, SortDirection) const {
PERFETTO_FATAL("Not implemented");
}
-void FakeStorage::ChainImpl::Serialize(StorageProto*) const {
+void FakeStorageChain::Serialize(StorageProto*) const {
// FakeStorage doesn't really make sense to serialize.
PERFETTO_FATAL("Not implemented");
}
diff --git a/src/trace_processor/db/column/fake_storage.h b/src/trace_processor/db/column/fake_storage.h
index 07323fa..8d4d6b5 100644
--- a/src/trace_processor/db/column/fake_storage.h
+++ b/src/trace_processor/db/column/fake_storage.h
@@ -30,90 +30,80 @@
namespace perfetto::trace_processor::column {
-// Fake implementation of Storage for use in tests.
-class FakeStorage final : public DataLayer {
+// Fake implementation of DataLayerChain which can be used in unittests.
+class FakeStorageChain : public DataLayerChain {
public:
- std::unique_ptr<DataLayerChain> MakeChain() override;
-
- static std::unique_ptr<DataLayer> SearchAll(uint32_t size) {
- return std::unique_ptr<DataLayer>(
- new FakeStorage(size, SearchStrategy::kAll));
+ // Factory function for creating a DataLayerChain which matches all rows from
+ // [0, size).
+ static std::unique_ptr<DataLayerChain> SearchAll(uint32_t size) {
+ return std::unique_ptr<DataLayerChain>(
+ new FakeStorageChain(size, SearchStrategy::kAll, Range(), BitVector()));
}
- static std::unique_ptr<DataLayer> SearchNone(uint32_t size) {
- return std::unique_ptr<DataLayer>(
- new FakeStorage(size, SearchStrategy::kNone));
+ // Factory function for creating a DataLayerChain which matches zero rows.
+ static std::unique_ptr<DataLayerChain> SearchNone(uint32_t size) {
+ return std::unique_ptr<DataLayerChain>(new FakeStorageChain(
+ size, SearchStrategy::kNone, Range(), BitVector()));
}
- static std::unique_ptr<DataLayer> SearchSubset(uint32_t size, Range r) {
- std::unique_ptr<FakeStorage> storage(
- new FakeStorage(size, SearchStrategy::kRange));
- storage->range_ = r;
- return std::move(storage);
+ // Factory function for creating a DataLayerChain which matches rows [r.start,
+ // r.end).
+ static std::unique_ptr<DataLayerChain> SearchSubset(uint32_t size, Range r) {
+ return std::unique_ptr<DataLayerChain>(
+ new FakeStorageChain(size, SearchStrategy::kRange, r, BitVector()));
}
- static std::unique_ptr<DataLayer> SearchSubset(uint32_t size, BitVector bv) {
- std::unique_ptr<FakeStorage> storage(
- new FakeStorage(size, SearchStrategy::kBitVector));
- storage->bit_vector_ = std::move(bv);
- return std::move(storage);
+ // Factory function for creating a DataLayerChain which matches rows of the
+ // set bit positions of |bv|.
+ static std::unique_ptr<DataLayerChain> SearchSubset(uint32_t size,
+ BitVector bv) {
+ return std::unique_ptr<DataLayerChain>(new FakeStorageChain(
+ size, SearchStrategy::kBitVector, Range(), std::move(bv)));
}
- static std::unique_ptr<DataLayer> SearchSubset(
+ // Factory function for creating a DataLayerChain which matches rows specified
+ // by |index_vec|.
+ static std::unique_ptr<DataLayerChain> SearchSubset(
uint32_t size,
const std::vector<uint32_t>& index_vec) {
- std::unique_ptr<FakeStorage> storage(
- new FakeStorage(size, SearchStrategy::kBitVector));
BitVector bv(size);
for (uint32_t i : index_vec) {
bv.Set(i);
}
- storage->bit_vector_ = std::move(bv);
- return std::move(storage);
+ return std::unique_ptr<DataLayerChain>(new FakeStorageChain(
+ size, SearchStrategy::kBitVector, Range(), std::move(bv)));
}
+ // Implementation of DataLayerChain.
+ SingleSearchResult SingleSearch(FilterOp, SqlValue, uint32_t) const override;
+
+ UniqueSearchResult UniqueSearch(FilterOp, SqlValue, uint32_t*) const override;
+
+ SearchValidationResult ValidateSearchConstraints(FilterOp,
+ SqlValue) const override;
+
+ RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearchValidated(FilterOp,
+ SqlValue,
+ Indices) const override;
+
+ Range OrderedIndexSearchValidated(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(SortToken* start,
+ SortToken* end,
+ SortDirection) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return size_; }
+
+ std::string DebugString() const override { return "FakeStorage"; }
+
private:
enum SearchStrategy { kNone, kAll, kRange, kBitVector };
- class ChainImpl : public DataLayerChain {
- public:
- ChainImpl(uint32_t, SearchStrategy, Range, BitVector);
-
- SingleSearchResult SingleSearch(FilterOp,
- SqlValue,
- uint32_t) const override;
-
- SearchValidationResult ValidateSearchConstraints(FilterOp,
- SqlValue) const override;
-
- RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
-
- Range OrderedIndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
-
- void StableSort(SortToken* start,
- SortToken* end,
- SortDirection) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override { return size_; }
-
- std::string DebugString() const override { return "FakeStorage"; }
-
- private:
- uint32_t size_ = 0;
- SearchStrategy strategy_ = SearchStrategy::kNone;
- Range range_;
- BitVector bit_vector_;
- };
-
- FakeStorage(uint32_t size, SearchStrategy strategy);
+ FakeStorageChain(uint32_t, SearchStrategy, Range, BitVector);
uint32_t size_ = 0;
SearchStrategy strategy_ = SearchStrategy::kNone;
diff --git a/src/trace_processor/db/column/id_storage.cc b/src/trace_processor/db/column/id_storage.cc
index 6fdb800..1c32194 100644
--- a/src/trace_processor/db/column/id_storage.cc
+++ b/src/trace_processor/db/column/id_storage.cc
@@ -191,6 +191,19 @@
PERFETTO_FATAL("For GCC");
}
+UniqueSearchResult IdStorage::ChainImpl::UniqueSearch(FilterOp op,
+ SqlValue sql_val,
+ uint32_t* index) const {
+ if (sql_val.type != SqlValue::kLong ||
+ sql_val.long_value >= std::numeric_limits<uint32_t>::max() ||
+ sql_val.long_value <= std::numeric_limits<uint32_t>::min() ||
+ op != FilterOp::kEq) {
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ *index = static_cast<uint32_t>(sql_val.long_value);
+ return UniqueSearchResult::kMatch;
+}
+
RangeOrBitVector IdStorage::ChainImpl::SearchValidated(
FilterOp op,
SqlValue sql_val,
diff --git a/src/trace_processor/db/column/id_storage.h b/src/trace_processor/db/column/id_storage.h
index fd8ba95..bb0d7d5 100644
--- a/src/trace_processor/db/column/id_storage.h
+++ b/src/trace_processor/db/column/id_storage.h
@@ -36,7 +36,10 @@
// included in the column.
class IdStorage final : public DataLayer {
public:
- std::unique_ptr<DataLayerChain> MakeChain() override;
+ IdStorage();
+ ~IdStorage() override;
+
+ std::unique_ptr<DataLayerChain> MakeChain();
private:
class ChainImpl : public DataLayerChain {
@@ -45,6 +48,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/id_storage_unittest.cc b/src/trace_processor/db/column/id_storage_unittest.cc
index 48ce18e..32b0583 100644
--- a/src/trace_processor/db/column/id_storage_unittest.cc
+++ b/src/trace_processor/db/column/id_storage_unittest.cc
@@ -145,6 +145,25 @@
SingleSearchResult::kNoMatch);
}
+TEST(IdStorage, UniqueSearch) {
+ IdStorage storage;
+ auto chain = storage.MakeChain();
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kEq, SqlValue::Long(5), &row),
+ UniqueSearchResult::kMatch);
+ ASSERT_EQ(row, 5u);
+
+ row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(
+ chain->UniqueSearch(
+ FilterOp::kEq,
+ SqlValue::Long(std::numeric_limits<uint32_t>::max() + 1ll), &row),
+ UniqueSearchResult::kNeedsFullSearch);
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kEq, SqlValue::Double(0), &row),
+ UniqueSearchResult::kNeedsFullSearch);
+}
+
TEST(IdStorage, SearchEqSimple) {
IdStorage storage;
auto chain = storage.MakeChain();
diff --git a/src/trace_processor/db/column/make_chain.cc b/src/trace_processor/db/column/make_chain.cc
deleted file mode 100644
index 15ee387..0000000
--- a/src/trace_processor/db/column/make_chain.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2024 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 <memory>
-#include <utility>
-
-#include "src/trace_processor/db/column/arrangement_overlay.h"
-#include "src/trace_processor/db/column/data_layer.h"
-#include "src/trace_processor/db/column/dense_null_overlay.h"
-#include "src/trace_processor/db/column/dummy_storage.h"
-#include "src/trace_processor/db/column/id_storage.h"
-#include "src/trace_processor/db/column/null_overlay.h"
-#include "src/trace_processor/db/column/numeric_storage.h"
-#include "src/trace_processor/db/column/range_overlay.h"
-#include "src/trace_processor/db/column/selector_overlay.h"
-#include "src/trace_processor/db/column/set_id_storage.h"
-#include "src/trace_processor/db/column/string_storage.h"
-
-// This file contains the implementation of MakeChain for all the
-// DataLayer implementations. They are all centralised here because
-// there is an alternative set of implementations (see make_chain_minimal.cc)
-// the "minimal" target used by export_json in Chrome.
-
-namespace perfetto::trace_processor::column {
-
-std::unique_ptr<DataLayerChain> ArrangementOverlay::MakeChain(
- std::unique_ptr<DataLayerChain> inner,
- ChainCreationArgs args) {
- return std::make_unique<ChainImpl>(std::move(inner), arrangement_,
- arrangement_state_,
- args.does_layer_order_chain_contents);
-}
-
-std::unique_ptr<DataLayerChain> DenseNullOverlay::MakeChain(
- std::unique_ptr<DataLayerChain> inner,
- ChainCreationArgs) {
- return std::make_unique<ChainImpl>(std::move(inner), non_null_);
-}
-
-std::unique_ptr<DataLayerChain> DummyStorage::MakeChain() {
- return std::make_unique<ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> IdStorage::MakeChain() {
- return std::make_unique<ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> NullOverlay::MakeChain(
- std::unique_ptr<DataLayerChain> inner,
- ChainCreationArgs) {
- return std::make_unique<ChainImpl>(std::move(inner), non_null_);
-}
-
-template <typename T>
-std::unique_ptr<DataLayerChain> NumericStorage<T>::MakeChain() {
- return std::make_unique<ChainImpl>(vector_, storage_type_, is_sorted_);
-}
-template std::unique_ptr<DataLayerChain> NumericStorage<double>::MakeChain();
-template std::unique_ptr<DataLayerChain> NumericStorage<uint32_t>::MakeChain();
-template std::unique_ptr<DataLayerChain> NumericStorage<int32_t>::MakeChain();
-template std::unique_ptr<DataLayerChain> NumericStorage<int64_t>::MakeChain();
-
-std::unique_ptr<DataLayerChain> RangeOverlay::MakeChain(
- std::unique_ptr<DataLayerChain> inner,
- ChainCreationArgs) {
- return std::make_unique<ChainImpl>(std::move(inner), range_);
-}
-
-std::unique_ptr<DataLayerChain> SelectorOverlay::MakeChain(
- std::unique_ptr<DataLayerChain> inner,
- ChainCreationArgs) {
- return std::make_unique<ChainImpl>(std::move(inner), selector_);
-}
-
-std::unique_ptr<DataLayerChain> SetIdStorage::MakeChain() {
- return std::make_unique<ChainImpl>(values_);
-}
-
-std::unique_ptr<DataLayerChain> StringStorage::MakeChain() {
- return std::make_unique<ChainImpl>(string_pool_, data_, is_sorted_);
-}
-
-} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/make_chain_minimal.cc b/src/trace_processor/db/column/make_chain_minimal.cc
deleted file mode 100644
index 7a23549..0000000
--- a/src/trace_processor/db/column/make_chain_minimal.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2024 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 <memory>
-
-#include "src/trace_processor/db/column/arrangement_overlay.h"
-#include "src/trace_processor/db/column/data_layer.h"
-#include "src/trace_processor/db/column/dense_null_overlay.h"
-#include "src/trace_processor/db/column/dummy_storage.h"
-#include "src/trace_processor/db/column/id_storage.h"
-#include "src/trace_processor/db/column/null_overlay.h"
-#include "src/trace_processor/db/column/numeric_storage.h"
-#include "src/trace_processor/db/column/range_overlay.h"
-#include "src/trace_processor/db/column/selector_overlay.h"
-#include "src/trace_processor/db/column/set_id_storage.h"
-#include "src/trace_processor/db/column/string_storage.h"
-
-// This file contains the implementation of MakeChain for all the
-// DataLayer implementations the "minimal" target used by export_json in Chrome.
-// See make_chain.cc for the real implementations for these functions.
-
-namespace perfetto::trace_processor::column {
-
-std::unique_ptr<DataLayerChain> ArrangementOverlay::MakeChain(
- std::unique_ptr<DataLayerChain>,
- ChainCreationArgs) {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> DenseNullOverlay::MakeChain(
- std::unique_ptr<DataLayerChain>,
- ChainCreationArgs) {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> DummyStorage::MakeChain() {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> IdStorage::MakeChain() {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> NullOverlay::MakeChain(
- std::unique_ptr<DataLayerChain>,
- ChainCreationArgs) {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-template <typename T>
-std::unique_ptr<DataLayerChain> NumericStorage<T>::MakeChain() {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-template std::unique_ptr<DataLayerChain> NumericStorage<double>::MakeChain();
-template std::unique_ptr<DataLayerChain> NumericStorage<uint32_t>::MakeChain();
-template std::unique_ptr<DataLayerChain> NumericStorage<int32_t>::MakeChain();
-template std::unique_ptr<DataLayerChain> NumericStorage<int64_t>::MakeChain();
-
-std::unique_ptr<DataLayerChain> RangeOverlay::MakeChain(
- std::unique_ptr<DataLayerChain>,
- ChainCreationArgs) {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> SelectorOverlay::MakeChain(
- std::unique_ptr<DataLayerChain>,
- ChainCreationArgs) {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> SetIdStorage::MakeChain() {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-std::unique_ptr<DataLayerChain> StringStorage::MakeChain() {
- return std::make_unique<DummyStorage::ChainImpl>();
-}
-
-} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/null_overlay.cc b/src/trace_processor/db/column/null_overlay.cc
index 2ddc004..fe489e4 100644
--- a/src/trace_processor/db/column/null_overlay.cc
+++ b/src/trace_processor/db/column/null_overlay.cc
@@ -78,8 +78,6 @@
} // namespace
-NullOverlay::NullOverlay(const BitVector* non_null) : non_null_(non_null) {}
-
SingleSearchResult NullOverlay::ChainImpl::SingleSearch(FilterOp op,
SqlValue sql_val,
uint32_t index) const {
@@ -106,6 +104,24 @@
PERFETTO_FATAL("For GCC");
}
+UniqueSearchResult NullOverlay::ChainImpl::UniqueSearch(FilterOp op,
+ SqlValue sql_val,
+ uint32_t* index) const {
+ switch (inner_->UniqueSearch(op, sql_val, index)) {
+ case UniqueSearchResult::kMatch:
+ if (*index >= non_null_->CountSetBits()) {
+ return UniqueSearchResult::kNoMatch;
+ }
+ *index = non_null_->IndexOfNthSet(*index);
+ return UniqueSearchResult::kMatch;
+ case UniqueSearchResult::kNoMatch:
+ return UniqueSearchResult::kNoMatch;
+ case UniqueSearchResult::kNeedsFullSearch:
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
NullOverlay::ChainImpl::ChainImpl(std::unique_ptr<DataLayerChain> innner,
const BitVector* non_null)
: inner_(std::move(innner)), non_null_(non_null) {
diff --git a/src/trace_processor/db/column/null_overlay.h b/src/trace_processor/db/column/null_overlay.h
index 8609251..35c5e52 100644
--- a/src/trace_processor/db/column/null_overlay.h
+++ b/src/trace_processor/db/column/null_overlay.h
@@ -33,10 +33,11 @@
class NullOverlay final : public DataLayer {
public:
explicit NullOverlay(const BitVector* non_null);
+ ~NullOverlay() override;
std::unique_ptr<DataLayerChain> MakeChain(
std::unique_ptr<DataLayerChain>,
- ChainCreationArgs = ChainCreationArgs()) override;
+ ChainCreationArgs = ChainCreationArgs());
private:
class ChainImpl : public DataLayerChain {
@@ -47,6 +48,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/null_overlay_unittest.cc b/src/trace_processor/db/column/null_overlay_unittest.cc
index eb7c2bf..73934a6 100644
--- a/src/trace_processor/db/column/null_overlay_unittest.cc
+++ b/src/trace_processor/db/column/null_overlay_unittest.cc
@@ -17,6 +17,7 @@
#include "src/trace_processor/db/column/null_overlay.h"
#include <cstdint>
+#include <limits>
#include <memory>
#include <vector>
@@ -37,9 +38,9 @@
TEST(NullOverlay, SingleSearch) {
BitVector bv{0, 1, 0, 1, 1, 1};
- auto fake = FakeStorage::SearchSubset(4, std::vector<uint32_t>{1, 2});
+ auto fake = FakeStorageChain::SearchSubset(4, std::vector<uint32_t>{1, 2});
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kGe, SqlValue::Long(0u), 3),
SingleSearchResult::kMatch);
@@ -51,9 +52,9 @@
TEST(NullOverlay, SingleSearchIsNull) {
BitVector bv{0, 1, 0, 1, 1, 1};
- auto fake = FakeStorage::SearchNone(4);
+ auto fake = FakeStorageChain::SearchNone(4);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kIsNull, SqlValue(), 0),
SingleSearchResult::kMatch);
@@ -63,9 +64,9 @@
TEST(NullOverlay, SingleSearchIsNotNull) {
BitVector bv{0, 1, 0, 1, 1, 1};
- auto fake = FakeStorage::SearchAll(4);
+ auto fake = FakeStorageChain::SearchAll(4);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kIsNotNull, SqlValue(), 1),
SingleSearchResult::kMatch);
@@ -73,11 +74,34 @@
SingleSearchResult::kNoMatch);
}
+TEST(NullOverlay, UniqueSearch) {
+ BitVector bv{0, 0, 0, 1, 1};
+ NullOverlay storage(&bv);
+ auto fake = FakeStorageChain::SearchSubset(5, Range(1, 2));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kMatch);
+ ASSERT_EQ(row, 4u);
+}
+
+TEST(NullOverlay, UniqueSearchOutOfBounds) {
+ BitVector bv{0, 0, 0, 1, 1};
+ NullOverlay storage(&bv);
+ auto fake = FakeStorageChain::SearchSubset(5, Range(4, 5));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kNoMatch);
+}
+
TEST(NullOverlay, SearchInputInsideBoundary) {
BitVector bv{0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- auto fake = FakeStorage::SearchAll(4u);
+ auto fake = FakeStorageChain::SearchAll(4u);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGt, SqlValue::Long(0), Range(1, 6));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
@@ -85,9 +109,9 @@
TEST(NullOverlay, SearchInputOutsideBoundary) {
BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- auto fake = FakeStorage::SearchAll(5u);
+ auto fake = FakeStorageChain::SearchAll(5u);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGt, SqlValue::Long(0), Range(3, 8));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 7));
@@ -95,9 +119,9 @@
TEST(NullOverlay, SubsetResultOutsideBoundary) {
BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- auto fake = FakeStorage::SearchSubset(5u, Range(1, 3));
+ auto fake = FakeStorageChain::SearchSubset(5u, Range(1, 3));
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
@@ -105,9 +129,9 @@
TEST(NullOverlay, SubsetResultOnBoundary) {
BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- auto fake = FakeStorage::SearchAll(5u);
+ auto fake = FakeStorageChain::SearchAll(5u);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3, 4, 7, 8));
@@ -115,9 +139,9 @@
TEST(NullOverlay, BitVectorSubset) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1});
+ auto fake = FakeStorageChain::SearchSubset(4u, BitVector{0, 1, 0, 1});
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 8));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 6));
@@ -125,9 +149,9 @@
TEST(NullOverlay, BitVectorSubsetIsNull) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1});
+ auto fake = FakeStorageChain::SearchSubset(4u, BitVector{0, 1, 0, 1});
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kIsNull, SqlValue(), Range(0, 8));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2, 3, 4, 6, 7));
@@ -135,9 +159,9 @@
TEST(NullOverlay, IndexSearchAllElements) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchAll(4u);
+ auto fake = FakeStorageChain::SearchAll(4u);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{1, 5, 2};
auto res =
@@ -149,9 +173,9 @@
TEST(NullOverlay, IndexSearchPartialElements) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchAll(4u);
+ auto fake = FakeStorageChain::SearchAll(4u);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{1, 4, 2};
auto res =
@@ -163,9 +187,9 @@
TEST(NullOverlay, IndexSearchIsNullOpEmptyRes) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchNone(4u);
+ auto fake = FakeStorageChain::SearchNone(4u);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{0, 3, 5, 4, 2};
auto res =
@@ -177,9 +201,9 @@
TEST(NullOverlay, IndexSearchIsNullOp) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchSubset(4u, Range(2, 3));
+ auto fake = FakeStorageChain::SearchSubset(4u, Range(2, 3));
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{0, 3, 2, 4, 5};
auto res =
@@ -191,9 +215,9 @@
TEST(NullOverlay, IndexSearchIsNotNullOp) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchAll(4u);
+ auto fake = FakeStorageChain::SearchAll(4u);
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{0, 3, 4};
auto res =
@@ -207,9 +231,9 @@
BitVector bv{0, 1, 1, 1, 0, 1};
// Passing values in final storage (on normal operations)
// 0, 1, 0, 1, 0, 0
- auto fake = FakeStorage::SearchSubset(4, BitVector{1, 0, 1, 0});
+ auto fake = FakeStorageChain::SearchSubset(4, BitVector{1, 0, 1, 0});
NullOverlay storage(&bv);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
// Passing values on final data
// NULL, NULL, 0, 1, 1
diff --git a/src/trace_processor/db/column/numeric_storage.cc b/src/trace_processor/db/column/numeric_storage.cc
index 2c88b38..27f6204 100644
--- a/src/trace_processor/db/column/numeric_storage.cc
+++ b/src/trace_processor/db/column/numeric_storage.cc
@@ -27,6 +27,7 @@
#include <string>
#include <utility>
#include <variant>
+#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/public/compiler.h"
@@ -258,7 +259,7 @@
auto i_as_d = static_cast<double>(i);
// Case when |sql_val| can be interpreted as a SqlValue::Long.
- if (std::equal_to<int64_t>()(i, static_cast<int64_t>(i_as_d))) {
+ if (std::equal_to<>()(i, static_cast<int64_t>(i_as_d))) {
*sql_val = SqlValue::Double(i_as_d);
return SearchValidationResult::kOk;
}
@@ -293,16 +294,18 @@
} // namespace
-NumericStorageBase::NumericStorageBase(ColumnType type, bool is_sorted)
- : storage_type_(type), is_sorted_(is_sorted) {}
-
-NumericStorageBase::~NumericStorageBase() = default;
-
NumericStorageBase::ChainImpl::ChainImpl(const void* vector_ptr,
ColumnType type,
bool is_sorted)
: vector_ptr_(vector_ptr), storage_type_(type), is_sorted_(is_sorted) {}
+UniqueSearchResult NumericStorageBase::ChainImpl::UniqueSearch(
+ FilterOp,
+ SqlValue,
+ uint32_t*) const {
+ return UniqueSearchResult::kNeedsFullSearch;
+}
+
SearchValidationResult NumericStorageBase::ChainImpl::ValidateSearchConstraints(
FilterOp op,
SqlValue val) const {
@@ -701,11 +704,4 @@
}
}
-// Define explicit instantiation of the necessary templates here to reduce
-// binary size bloat.
-template class NumericStorage<double>;
-template class NumericStorage<uint32_t>;
-template class NumericStorage<int32_t>;
-template class NumericStorage<int64_t>;
-
} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/numeric_storage.h b/src/trace_processor/db/column/numeric_storage.h
index f6f450a..af69e28 100644
--- a/src/trace_processor/db/column/numeric_storage.h
+++ b/src/trace_processor/db/column/numeric_storage.h
@@ -37,6 +37,10 @@
protected:
class ChainImpl : public DataLayerChain {
public:
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
@@ -77,7 +81,7 @@
const bool is_sorted_ = false;
};
- NumericStorageBase(ColumnType type, bool is_sorted);
+ NumericStorageBase(ColumnType type, bool is_sorted, Impl impl);
~NumericStorageBase() override;
const ColumnType storage_type_ = ColumnType::kDummy;
@@ -90,13 +94,12 @@
public:
PERFETTO_NO_INLINE NumericStorage(const std::vector<T>* vec,
ColumnType type,
- bool is_sorted)
- : NumericStorageBase(type, is_sorted), vector_(vec) {}
+ bool is_sorted);
// The implementation of this function is given by
// make_chain.cc/make_chain_minimal.cc depending on whether this is a minimal
// or full build of trace processor.
- std::unique_ptr<DataLayerChain> MakeChain() override;
+ std::unique_ptr<DataLayerChain> MakeChain();
private:
class ChainImpl : public NumericStorageBase::ChainImpl {
@@ -152,6 +155,21 @@
private:
const std::vector<T>* vector_;
};
+ Impl GetImpl() {
+ if constexpr (std::is_same_v<T, double>) {
+ return Impl::kNumericDouble;
+ } else if constexpr (std::is_same_v<T, uint32_t>) {
+ return Impl::kNumericUint32;
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ return Impl::kNumericInt32;
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return Impl::kNumericInt64;
+ } else {
+ // false doesn't work as expression has to depend on the template
+ // parameter
+ static_assert(sizeof(T*) == 0, "T is not supported");
+ }
+ }
const std::vector<T>* vector_;
};
diff --git a/src/trace_processor/db/column/range_overlay.cc b/src/trace_processor/db/column/range_overlay.cc
index 5a92138..308bf1c 100644
--- a/src/trace_processor/db/column/range_overlay.cc
+++ b/src/trace_processor/db/column/range_overlay.cc
@@ -34,8 +34,6 @@
using Range = Range;
-RangeOverlay::RangeOverlay(const Range* range) : range_(range) {}
-
RangeOverlay::ChainImpl::ChainImpl(std::unique_ptr<DataLayerChain> inner,
const Range* range)
: inner_(std::move(inner)), range_(range) {
@@ -49,6 +47,25 @@
return inner_->SingleSearch(op, sql_val, i + range_->start);
}
+UniqueSearchResult RangeOverlay::ChainImpl::UniqueSearch(
+ FilterOp op,
+ SqlValue sql_val,
+ uint32_t* index) const {
+ switch (inner_->UniqueSearch(op, sql_val, index)) {
+ case UniqueSearchResult::kMatch:
+ if (!range_->Contains(*index)) {
+ return UniqueSearchResult::kNoMatch;
+ }
+ *index -= range_->start;
+ return UniqueSearchResult::kMatch;
+ case UniqueSearchResult::kNoMatch:
+ return UniqueSearchResult::kNoMatch;
+ case UniqueSearchResult::kNeedsFullSearch:
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
SearchValidationResult RangeOverlay::ChainImpl::ValidateSearchConstraints(
FilterOp op,
SqlValue sql_val) const {
diff --git a/src/trace_processor/db/column/range_overlay.h b/src/trace_processor/db/column/range_overlay.h
index 1f53acb..366b2d3 100644
--- a/src/trace_processor/db/column/range_overlay.h
+++ b/src/trace_processor/db/column/range_overlay.h
@@ -30,10 +30,11 @@
class RangeOverlay final : public DataLayer {
public:
explicit RangeOverlay(const Range*);
+ ~RangeOverlay() override;
std::unique_ptr<DataLayerChain> MakeChain(
std::unique_ptr<DataLayerChain>,
- ChainCreationArgs = ChainCreationArgs()) override;
+ ChainCreationArgs = ChainCreationArgs());
private:
class ChainImpl : public DataLayerChain {
@@ -44,6 +45,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/range_overlay_unittest.cc b/src/trace_processor/db/column/range_overlay_unittest.cc
index ee493dd..bf13cbb 100644
--- a/src/trace_processor/db/column/range_overlay_unittest.cc
+++ b/src/trace_processor/db/column/range_overlay_unittest.cc
@@ -17,6 +17,8 @@
#include "src/trace_processor/db/column/range_overlay.h"
#include <cstdint>
+#include <limits>
+#include <utility>
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
@@ -35,12 +37,12 @@
using testing::IsEmpty;
using Range = Range;
-TEST(SelectorOverlay, SearchSingle) {
+TEST(SelectorOverlay, SingleSearch) {
Range range(3, 8);
RangeOverlay storage(&range);
- auto fake = FakeStorage::SearchSubset(
+ auto fake = FakeStorageChain::SearchSubset(
8, BitVector{false, false, false, true, false, false, false, false});
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kEq, SqlValue::Long(0u), 0),
SingleSearchResult::kMatch);
@@ -48,11 +50,45 @@
SingleSearchResult::kNoMatch);
}
+TEST(SelectorOverlay, UniqueSearch) {
+ Range range(1, 3);
+ RangeOverlay storage(&range);
+ auto fake = FakeStorageChain::SearchSubset(5, Range(2, 3));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kMatch);
+ ASSERT_EQ(row, 1u);
+}
+
+TEST(SelectorOverlay, UniqueSearchLowOutOfBounds) {
+ Range range(3, 8);
+ RangeOverlay storage(&range);
+ auto fake = FakeStorageChain::SearchSubset(8, Range(1, 2));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kNoMatch);
+}
+
+TEST(SelectorOverlay, UniqueSearchHighOutOfBounds) {
+ Range range(3, 8);
+ RangeOverlay storage(&range);
+ auto fake = FakeStorageChain::SearchSubset(9, Range(8, 9));
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kIsNotNull, SqlValue(), &row),
+ UniqueSearchResult::kNoMatch);
+}
+
TEST(RangeOverlay, SearchAll) {
Range range(3, 8);
RangeOverlay storage(&range);
- auto fake = FakeStorage::SearchAll(10);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto fake = FakeStorageChain::SearchAll(10);
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1u, 2u, 3u));
@@ -61,38 +97,40 @@
TEST(RangeOverlay, SearchNone) {
Range range(3, 8);
RangeOverlay storage(&range);
- auto fake = FakeStorage::SearchNone(10);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto fake = FakeStorageChain::SearchNone(10);
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
}
TEST(RangeOverlay, SearchLimited) {
- auto fake = FakeStorage::SearchSubset(10, std::vector<uint32_t>{4});
+ auto fake = FakeStorageChain::SearchSubset(10, std::vector<uint32_t>{4});
Range range(3, 5);
RangeOverlay storage(&range);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 2));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1u));
}
TEST(RangeOverlay, SearchBitVector) {
- auto fake = FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
+ auto fake =
+ FakeStorageChain::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
Range range(3, 6);
RangeOverlay storage(&range);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 3));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2));
}
TEST(RangeOverlay, IndexSearch) {
- auto fake = FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
+ auto fake =
+ FakeStorageChain::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
Range range(3, 5);
RangeOverlay storage(&range);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{1u, 0u, 3u};
RangeOrBitVector res = chain->IndexSearch(
diff --git a/src/trace_processor/db/column/selector_overlay.cc b/src/trace_processor/db/column/selector_overlay.cc
index 47df692..935c4e2 100644
--- a/src/trace_processor/db/column/selector_overlay.cc
+++ b/src/trace_processor/db/column/selector_overlay.cc
@@ -34,9 +34,6 @@
namespace perfetto::trace_processor::column {
-SelectorOverlay::SelectorOverlay(const BitVector* selector)
- : selector_(selector) {}
-
SelectorOverlay::ChainImpl::ChainImpl(std::unique_ptr<DataLayerChain> inner,
const BitVector* selector)
: inner_(std::move(inner)), selector_(selector) {}
@@ -47,6 +44,25 @@
return inner_->SingleSearch(op, sql_val, selector_->IndexOfNthSet(i));
}
+UniqueSearchResult SelectorOverlay::ChainImpl::UniqueSearch(
+ FilterOp op,
+ SqlValue sql_val,
+ uint32_t* index) const {
+ switch (inner_->UniqueSearch(op, sql_val, index)) {
+ case UniqueSearchResult::kMatch:
+ if (*index >= selector_->size() || !selector_->IsSet(*index)) {
+ return UniqueSearchResult::kNoMatch;
+ }
+ *index = selector_->CountSetBits(*index);
+ return UniqueSearchResult::kMatch;
+ case UniqueSearchResult::kNoMatch:
+ return UniqueSearchResult::kNoMatch;
+ case UniqueSearchResult::kNeedsFullSearch:
+ return UniqueSearchResult::kNeedsFullSearch;
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
SearchValidationResult SelectorOverlay::ChainImpl::ValidateSearchConstraints(
FilterOp op,
SqlValue sql_val) const {
diff --git a/src/trace_processor/db/column/selector_overlay.h b/src/trace_processor/db/column/selector_overlay.h
index b550da3..04bc2e7 100644
--- a/src/trace_processor/db/column/selector_overlay.h
+++ b/src/trace_processor/db/column/selector_overlay.h
@@ -34,10 +34,11 @@
class SelectorOverlay final : public DataLayer {
public:
explicit SelectorOverlay(const BitVector*);
+ ~SelectorOverlay() override;
std::unique_ptr<DataLayerChain> MakeChain(
std::unique_ptr<DataLayerChain>,
- ChainCreationArgs = ChainCreationArgs()) override;
+ ChainCreationArgs = ChainCreationArgs());
private:
class ChainImpl : public DataLayerChain {
@@ -48,6 +49,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/selector_overlay_unittest.cc b/src/trace_processor/db/column/selector_overlay_unittest.cc
index cd6f0c5..b9151b8 100644
--- a/src/trace_processor/db/column/selector_overlay_unittest.cc
+++ b/src/trace_processor/db/column/selector_overlay_unittest.cc
@@ -17,11 +17,12 @@
#include "src/trace_processor/db/column/selector_overlay.h"
#include <cstdint>
+#include <limits>
#include <vector>
-#include "data_layer.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/db/column/data_layer.h"
#include "src/trace_processor/db/column/fake_storage.h"
#include "src/trace_processor/db/column/numeric_storage.h"
#include "src/trace_processor/db/column/types.h"
@@ -36,9 +37,9 @@
TEST(SelectorOverlay, SingleSearch) {
BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchSubset(8, Range(2, 5));
+ auto fake = FakeStorageChain::SearchSubset(8, Range(2, 5));
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
ASSERT_EQ(chain->SingleSearch(FilterOp::kGe, SqlValue::Long(0u), 1),
SingleSearchResult::kMatch);
@@ -46,11 +47,43 @@
SingleSearchResult::kNoMatch);
}
+TEST(SelectorOverlay, UniqueSearch) {
+ BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
+ auto fake = FakeStorageChain::SearchSubset(8, Range(2, 3));
+ SelectorOverlay storage(&selector);
+ auto chain = storage.MakeChain(std::move(fake));
+
+ uint32_t row = std::numeric_limits<uint32_t>::max();
+ ASSERT_EQ(chain->UniqueSearch(FilterOp::kGe, SqlValue::Long(0u), &row),
+ UniqueSearchResult::kMatch);
+ ASSERT_EQ(row, 1u);
+}
+
+TEST(SelectorOverlay, UniqueSearchNotSet) {
+ BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
+ auto fake = FakeStorageChain::SearchSubset(8, Range(4, 5));
+ SelectorOverlay storage(&selector);
+ auto chain = storage.MakeChain(std::move(fake));
+
+ ASSERT_EQ(chain->SingleSearch(FilterOp::kGe, SqlValue::Long(0u), 1),
+ SingleSearchResult::kNoMatch);
+}
+
+TEST(SelectorOverlay, UniqueSearchOutOfBounds) {
+ BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
+ auto fake = FakeStorageChain::SearchSubset(9, Range(8, 9));
+ SelectorOverlay storage(&selector);
+ auto chain = storage.MakeChain(std::move(fake));
+
+ ASSERT_EQ(chain->SingleSearch(FilterOp::kGe, SqlValue::Long(0u), 1),
+ SingleSearchResult::kNoMatch);
+}
+
TEST(SelectorOverlay, SearchAll) {
BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- auto fake = FakeStorage::SearchAll(10);
+ auto fake = FakeStorageChain::SearchAll(10);
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1u, 2u, 3u));
@@ -58,9 +91,9 @@
TEST(SelectorOverlay, SearchNone) {
BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- auto fake = FakeStorage::SearchNone(10);
+ auto fake = FakeStorageChain::SearchNone(10);
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
@@ -68,9 +101,9 @@
TEST(SelectorOverlay, SearchLimited) {
BitVector selector{0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- auto fake = FakeStorage::SearchSubset(10, Range(4, 5));
+ auto fake = FakeStorageChain::SearchSubset(10, Range(4, 5));
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2u));
@@ -78,9 +111,10 @@
TEST(SelectorOverlay, SearchBitVector) {
BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
+ auto fake =
+ FakeStorageChain::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
auto res = chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2));
@@ -88,9 +122,10 @@
TEST(SelectorOverlay, IndexSearch) {
BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- auto fake = FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
+ auto fake =
+ FakeStorageChain::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{1u, 0u, 3u};
RangeOrBitVector res = chain->IndexSearch(
@@ -102,9 +137,9 @@
TEST(SelectorOverlay, OrderedIndexSearchTrivial) {
BitVector selector{1, 0, 1, 0, 1};
- auto fake = FakeStorage::SearchAll(5);
+ auto fake = FakeStorageChain::SearchAll(5);
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{1u, 0u, 2u};
Range res = chain->OrderedIndexSearch(
@@ -117,9 +152,9 @@
TEST(SelectorOverlay, OrderedIndexSearchNone) {
BitVector selector{1, 0, 1, 0, 1};
- auto fake = FakeStorage::SearchNone(5);
+ auto fake = FakeStorageChain::SearchNone(5);
SelectorOverlay storage(&selector);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> table_idx{1u, 0u, 2u};
Range res = chain->OrderedIndexSearch(
diff --git a/src/trace_processor/db/column/set_id_storage.cc b/src/trace_processor/db/column/set_id_storage.cc
index dd22def..3e9d497 100644
--- a/src/trace_processor/db/column/set_id_storage.cc
+++ b/src/trace_processor/db/column/set_id_storage.cc
@@ -66,9 +66,6 @@
} // namespace
-SetIdStorage::SetIdStorage(const std::vector<uint32_t>* values)
- : values_(values) {}
-
SetIdStorage::ChainImpl::ChainImpl(const std::vector<uint32_t>* values)
: values_(values) {}
@@ -86,6 +83,12 @@
static_cast<uint32_t>(sql_val.long_value));
}
+UniqueSearchResult SetIdStorage::ChainImpl::UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const {
+ return UniqueSearchResult::kNeedsFullSearch;
+}
+
SearchValidationResult SetIdStorage::ChainImpl::ValidateSearchConstraints(
FilterOp op,
SqlValue val) const {
diff --git a/src/trace_processor/db/column/set_id_storage.h b/src/trace_processor/db/column/set_id_storage.h
index b20ba9c..86d2508 100644
--- a/src/trace_processor/db/column/set_id_storage.h
+++ b/src/trace_processor/db/column/set_id_storage.h
@@ -34,8 +34,9 @@
using SetId = uint32_t;
explicit SetIdStorage(const std::vector<uint32_t>*);
+ ~SetIdStorage() override;
- std::unique_ptr<DataLayerChain> MakeChain() override;
+ std::unique_ptr<DataLayerChain> MakeChain();
private:
class ChainImpl : public DataLayerChain {
@@ -46,6 +47,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/string_storage.cc b/src/trace_processor/db/column/string_storage.cc
index 5eaf950..ae6a797 100644
--- a/src/trace_processor/db/column/string_storage.cc
+++ b/src/trace_processor/db/column/string_storage.cc
@@ -197,11 +197,6 @@
} // namespace
-StringStorage::StringStorage(StringPool* string_pool,
- const std::vector<StringPool::Id>* data,
- bool is_sorted)
- : data_(data), string_pool_(string_pool), is_sorted_(is_sorted) {}
-
StringStorage::ChainImpl::ChainImpl(StringPool* string_pool,
const std::vector<StringPool::Id>* data,
bool is_sorted)
@@ -239,8 +234,8 @@
case FilterOp::kNe: {
std::optional<StringPool::Id> id =
string_pool_->GetId(base::StringView(sql_val.string_value));
- return id && NotEqual()((*data_)[i], *id) ? SingleSearchResult::kMatch
- : SingleSearchResult::kNoMatch;
+ return !id || NotEqual()((*data_)[i], *id) ? SingleSearchResult::kMatch
+ : SingleSearchResult::kNoMatch;
}
case FilterOp::kGe:
return GreaterEqual{string_pool_}(
@@ -285,6 +280,12 @@
PERFETTO_FATAL("For GCC");
}
+UniqueSearchResult StringStorage::ChainImpl::UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const {
+ return UniqueSearchResult::kNeedsFullSearch;
+}
+
SearchValidationResult StringStorage::ChainImpl::ValidateSearchConstraints(
FilterOp op,
SqlValue val) const {
diff --git a/src/trace_processor/db/column/string_storage.h b/src/trace_processor/db/column/string_storage.h
index dafa43c..03541aa 100644
--- a/src/trace_processor/db/column/string_storage.h
+++ b/src/trace_processor/db/column/string_storage.h
@@ -35,8 +35,9 @@
StringStorage(StringPool* string_pool,
const std::vector<StringPool::Id>* data,
bool is_sorted = false);
+ ~StringStorage() override;
- std::unique_ptr<DataLayerChain> MakeChain() override;
+ std::unique_ptr<DataLayerChain> MakeChain();
private:
class ChainImpl : public DataLayerChain {
@@ -49,6 +50,10 @@
SqlValue,
uint32_t) const override;
+ UniqueSearchResult UniqueSearch(FilterOp,
+ SqlValue,
+ uint32_t*) const override;
+
SearchValidationResult ValidateSearchConstraints(FilterOp,
SqlValue) const override;
diff --git a/src/trace_processor/db/column/string_storage_unittest.cc b/src/trace_processor/db/column/string_storage_unittest.cc
index 7d42d14..303ab66 100644
--- a/src/trace_processor/db/column/string_storage_unittest.cc
+++ b/src/trace_processor/db/column/string_storage_unittest.cc
@@ -53,6 +53,8 @@
ASSERT_EQ(chain->SingleSearch(FilterOp::kEq, SqlValue::String("pierogi"), 3),
SingleSearchResult::kNoMatch);
+ ASSERT_EQ(chain->SingleSearch(FilterOp::kNe, SqlValue::String("foo"), 0),
+ SingleSearchResult::kMatch);
ASSERT_EQ(chain->SingleSearch(FilterOp::kNe, SqlValue::String("pierogi"), 0),
SingleSearchResult::kMatch);
ASSERT_EQ(chain->SingleSearch(FilterOp::kNe, SqlValue::String("pierogi"), 4),
diff --git a/src/trace_processor/db/column/types.h b/src/trace_processor/db/column/types.h
index 803c6ce..f27daa7 100644
--- a/src/trace_processor/db/column/types.h
+++ b/src/trace_processor/db/column/types.h
@@ -37,6 +37,17 @@
// the crtiteria, a call to *Search is required.
};
+// Result of calling Storage::UniqueSearch function.
+enum class UniqueSearchResult {
+ kMatch, // The returned row matches the constraint.
+ kNoMatch, // The returned row does not matches the constraint.
+ kNeedsFullSearch, // UniqueSearch was unable to determine if a row meets
+ // the crtiteria, a call to *Search is required. This
+ // does not mean there >1 row necessarily, just that
+ // UniqueSearch was unable to quickly identify a single
+ // row.
+};
+
// Result of calling Storage::ValidateSearchResult function.
enum class SearchValidationResult {
kOk, // It makes sense to run search
diff --git a/src/trace_processor/db/column_storage_overlay.h b/src/trace_processor/db/column_storage_overlay.h
index 6ff16ca..c13c095 100644
--- a/src/trace_processor/db/column_storage_overlay.h
+++ b/src/trace_processor/db/column_storage_overlay.h
@@ -19,17 +19,13 @@
#include <stdint.h>
-#include <memory>
#include <optional>
#include <vector>
-#include "perfetto/base/logging.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/containers/bit_vector_iterators.h"
#include "src/trace_processor/containers/row_map.h"
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
// Contains indices which can be used to lookup data in one or more
// ColumnStorages.
@@ -136,66 +132,6 @@
// state.
void Clear() { *this = ColumnStorageOverlay(); }
- // Filters the current ColumnStorageOverlay into the RowMap given by |out|
- // based on the return value of |p(idx)|.
- //
- // Precondition: |out| should be sorted by the indices inside it (this is
- // required to keep this method efficient). This is automatically true if the
- // mode of |out| is Range or BitVector but needs to be enforced if the mode is
- // IndexVector.
- //
- // Specifically, the setup for each of the variables is as follows:
- // this: contains the indices passed to p to filter.
- // out : contains indicies into |this| and will be filtered down to only
- // contain indicies where p returns true.
- // p : takes an index given by |this| and returns whether the index should
- // be retained in |out|.
- //
- // Concretely, the algorithm being invoked looks like (but more efficient
- // based on the mode of |this| and |out|):
- // for (idx : out)
- // this_idx = (*this)[idx]
- // if (!p(this_idx))
- // out->Remove(idx)
- template <typename Predicate>
- void FilterInto(RowMap* out, Predicate p) const {
- PERFETTO_DCHECK(size() >= out->size());
-
- if (out->empty()) {
- // If the output ColumnStorageOverlay is empty, we don't need to do
- // anything.
- return;
- }
-
- if (out->size() == 1) {
- // If the output ColumnStorageOverlay has a single entry, just lookup
- // that entry and see if we should keep it.
- if (!p(Get(out->Get(0))))
- out->Clear();
- return;
- }
-
- // TODO(lalitm): investigate whether we should have another fast path for
- // cases where |out| has only a few entries so we can scan |out| instead of
- // scanning |this|.
-
- // Ideally, we'd always just scan |out| and keep the indices in |this| which
- // 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|).
- 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)>
- void StableSort(std::vector<uint32_t>* out, Comparator c) const {
- return row_map_.StableSort(out, c);
- }
-
// Returns the iterator over the rows in this ColumnStorageOverlay.
Iterator IterateRows() const { return Iterator(row_map_.IterateRows()); }
@@ -204,66 +140,9 @@
private:
explicit ColumnStorageOverlay(RowMap rm) : row_map_(std::move(rm)) {}
- // 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>
- 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();
- }
- }
- *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_;
};
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_STORAGE_OVERLAY_H_
diff --git a/src/trace_processor/db/column_storage_overlay_benchmark.cc b/src/trace_processor/db/column_storage_overlay_benchmark.cc
deleted file mode 100644
index 49be7c7..0000000
--- a/src/trace_processor/db/column_storage_overlay_benchmark.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// 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 <random>
-
-#include <benchmark/benchmark.h>
-
-#include "src/trace_processor/db/column_storage_overlay.h"
-
-using perfetto::trace_processor::BitVector;
-using perfetto::trace_processor::ColumnStorageOverlay;
-using perfetto::trace_processor::RowMap;
-
-namespace {
-
-static constexpr uint32_t kPoolSize = 100000;
-static constexpr uint32_t kSize = 123456;
-
-template <typename Container>
-Container CreateRange(uint32_t end) {
- static constexpr uint32_t kRandomSeed = 32;
- std::minstd_rand0 rnd_engine(kRandomSeed);
-
- uint32_t start = rnd_engine() % end;
- uint32_t size = rnd_engine() % (end - start);
- return Container(start, start + size);
-}
-
-std::vector<uint32_t> CreateIndexVector(uint32_t size, uint32_t mod) {
- static constexpr uint32_t kRandomSeed = 476;
- std::minstd_rand0 rnd_engine(kRandomSeed);
- std::vector<uint32_t> rows(size);
- for (uint32_t i = 0; i < size; ++i) {
- rows[i] = rnd_engine() % mod;
- }
- return rows;
-}
-
-BitVector CreateBitVector(uint32_t size) {
- static constexpr uint32_t kRandomSeed = 42;
- std::minstd_rand0 rnd_engine(kRandomSeed);
- BitVector bv;
- for (uint32_t i = 0; i < size; ++i) {
- if (rnd_engine() % 2) {
- bv.AppendTrue();
- } else {
- bv.AppendFalse();
- }
- }
- return bv;
-}
-
-template <typename Factory>
-void BenchFilterInto(benchmark::State& state,
- ColumnStorageOverlay rm,
- Factory factory) {
- auto pool_vec = CreateIndexVector(kPoolSize, kSize);
-
- uint32_t pool_idx = 0;
- for (auto _ : state) {
- state.PauseTiming();
- RowMap out = factory();
- state.ResumeTiming();
-
- auto fn = [&pool_vec, pool_idx](uint32_t row) {
- return pool_vec[pool_idx] != 0 && (row % pool_vec[pool_idx]) != 0;
- };
- rm.FilterInto(&out, fn);
- pool_idx = (pool_idx + 1) % kPoolSize;
-
- benchmark::ClobberMemory();
- }
-}
-
-} // namespace
-
-static void BM_CSOFilterIntoRangeWithRange(benchmark::State& state) {
- ColumnStorageOverlay overlay(CreateRange<ColumnStorageOverlay>(kSize));
- uint32_t overlay_size = overlay.size();
- BenchFilterInto(state, std::move(overlay), [overlay_size]() {
- return CreateRange<RowMap>(overlay_size);
- });
-}
-BENCHMARK(BM_CSOFilterIntoRangeWithRange);
-
-static void BM_CSOFilterIntoRangeWithBv(benchmark::State& state) {
- ColumnStorageOverlay overlay(CreateRange<ColumnStorageOverlay>(kSize));
- uint32_t overlay_size = overlay.size();
- BenchFilterInto(state, std::move(overlay), [overlay_size]() {
- return RowMap(CreateBitVector(overlay_size));
- });
-}
-BENCHMARK(BM_CSOFilterIntoRangeWithBv);
-
-static void BM_CSOFilterIntoBvWithRange(benchmark::State& state) {
- ColumnStorageOverlay overlay(CreateBitVector(kSize));
- uint32_t overlay_size = overlay.size();
- BenchFilterInto(state, std::move(overlay), [overlay_size]() {
- return CreateRange<RowMap>(overlay_size);
- });
-}
-BENCHMARK(BM_CSOFilterIntoBvWithRange);
-
-static void BM_CSOFilterIntoBvWithBv(benchmark::State& state) {
- ColumnStorageOverlay overlay(CreateBitVector(kSize));
- uint32_t overlay_size = overlay.size();
- BenchFilterInto(state, std::move(overlay), [overlay_size]() {
- return RowMap(CreateBitVector(overlay_size));
- });
-}
-BENCHMARK(BM_CSOFilterIntoBvWithBv);
-
-static void BM_CSOFilterIntoIvWithRange(benchmark::State& state) {
- ColumnStorageOverlay overlay(CreateIndexVector(kSize, kSize));
- uint32_t overlay_size = overlay.size();
- BenchFilterInto(state, std::move(overlay), [overlay_size]() {
- return CreateRange<RowMap>(overlay_size);
- });
-}
-BENCHMARK(BM_CSOFilterIntoIvWithRange);
-
-static void BM_CSOFilterIntoIvWithBv(benchmark::State& state) {
- ColumnStorageOverlay overlay(CreateIndexVector(kSize, kSize));
- uint32_t overlay_size = overlay.size();
- BenchFilterInto(state, std::move(overlay), [overlay_size]() {
- return RowMap(CreateBitVector(overlay_size));
- });
-}
-BENCHMARK(BM_CSOFilterIntoIvWithBv);
diff --git a/src/trace_processor/db/column_storage_overlay_unittest.cc b/src/trace_processor/db/column_storage_overlay_unittest.cc
deleted file mode 100644
index 827153f..0000000
--- a/src/trace_processor/db/column_storage_overlay_unittest.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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/trace_processor/db/column_storage_overlay.h"
-
-#include <memory>
-
-#include "src/base/test/gtest_test_suite.h"
-#include "test/gtest_and_gmock.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace {
-
-TEST(ColumnStorageOverlay, FilterIntoEmptyOutput) {
- ColumnStorageOverlay rm(0, 10000);
- RowMap filter(4, 4);
- rm.FilterInto(&filter, [](uint32_t) -> bool {
- ADD_FAILURE() << "Should not have called lambda";
- return true;
- });
-
- ASSERT_EQ(filter.size(), 0u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoSingleRowTrue) {
- ColumnStorageOverlay rm(100, 10000);
- RowMap filter(6, 7);
- rm.FilterInto(&filter, [](uint32_t row) { return row == 106u; });
-
- ASSERT_EQ(filter.size(), 1u);
- ASSERT_EQ(filter.Get(0u), 6u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoSingleRowFalse) {
- ColumnStorageOverlay rm(100, 10000);
- RowMap filter(6, 7);
- rm.FilterInto(&filter, [](uint32_t row) {
- EXPECT_EQ(row, 106u);
- return row != 106u;
- });
-
- ASSERT_EQ(filter.size(), 0u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoRangeWithRange) {
- ColumnStorageOverlay rm(93, 157);
- RowMap filter(4, 7);
- rm.FilterInto(&filter, [](uint32_t row) { return row == 97u || row == 98u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 4u);
- ASSERT_EQ(filter.Get(1u), 5u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoOffsetRangeWithRange) {
- ColumnStorageOverlay rm(100000, 100010);
- RowMap filter(4, 7);
- rm.FilterInto(&filter, [](uint32_t row) { return row == 100004u; });
-
- ASSERT_EQ(filter.size(), 1u);
- ASSERT_EQ(filter.Get(0u), 4u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoLargeRangeWithRange) {
- ColumnStorageOverlay rm(0, 100000);
- RowMap filter(0, 100000);
- rm.FilterInto(&filter, [](uint32_t row) { return row % 2 == 0; });
-
- ASSERT_EQ(filter.size(), 100000u / 2);
- for (uint32_t i = 0; i < 100000 / 2; ++i) {
- ASSERT_EQ(filter.Get(i), i * 2);
- }
-}
-
-TEST(ColumnStorageOverlay, FilterIntoBitVectorWithRange) {
- ColumnStorageOverlay rm(
- BitVector{true, false, false, true, false, true, false, true, true});
- RowMap filter(1u, 5u);
- rm.FilterInto(&filter, [](uint32_t row) { return row == 3u || row == 7u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 1u);
- ASSERT_EQ(filter.Get(1u), 3u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoIndexVectorWithRange) {
- ColumnStorageOverlay rm(std::vector<uint32_t>{33, 2u, 45u, 7u, 8u, 9u});
- RowMap filter(2, 5);
- rm.FilterInto(&filter, [](uint32_t row) { return row == 45u || row == 8u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 2u);
- ASSERT_EQ(filter.Get(1u), 4u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoRangeWithBitVector) {
- ColumnStorageOverlay rm(27, 31);
- RowMap filter(BitVector{true, false, true, true});
- rm.FilterInto(&filter, [](uint32_t row) { return row == 29u || row == 30u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 2u);
- ASSERT_EQ(filter.Get(1u), 3u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoBitVectorWithBitVector) {
- ColumnStorageOverlay rm(BitVector{true, false, true, true, false, true});
- RowMap filter(BitVector{true, true, false, true});
- rm.FilterInto(&filter, [](uint32_t row) { return row == 2u || row == 5u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 1u);
- ASSERT_EQ(filter.Get(1u), 3u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoIndexVectorWithBitVector) {
- ColumnStorageOverlay rm(std::vector<uint32_t>{0u, 2u, 3u, 5u});
- RowMap filter(BitVector{true, true, false, true});
- rm.FilterInto(&filter, [](uint32_t row) { return row == 2u || row == 5u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 1u);
- ASSERT_EQ(filter.Get(1u), 3u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoRangeWithIndexVector) {
- ColumnStorageOverlay rm(27, 41);
- RowMap filter(std::vector<uint32_t>{3u, 5u, 9u, 10u, 12u});
- rm.FilterInto(&filter, [](uint32_t row) { return row == 32u || row == 39u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 5u);
- ASSERT_EQ(filter.Get(1u), 12u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoBitVectorWithIndexVector) {
- ColumnStorageOverlay rm(
- BitVector{false, true, false, true, true, false, true});
- RowMap filter(std::vector<uint32_t>{1u, 2u, 3u});
- rm.FilterInto(&filter, [](uint32_t row) { return row == 3u || row == 4u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 1u);
- ASSERT_EQ(filter.Get(1u), 2u);
-}
-
-TEST(ColumnStorageOverlay, FilterIntoIndexVectorWithIndexVector) {
- ColumnStorageOverlay rm(std::vector<uint32_t>{33u, 2u, 45u, 7u, 8u, 9u});
- RowMap filter(std::vector<uint32_t>{1u, 2u, 3u});
- rm.FilterInto(&filter, [](uint32_t row) { return row == 2u || row == 7u; });
-
- ASSERT_EQ(filter.size(), 2u);
- ASSERT_EQ(filter.Get(0u), 1u);
- ASSERT_EQ(filter.Get(1u), 3u);
-}
-
-} // namespace
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/db/query_executor.cc b/src/trace_processor/db/query_executor.cc
index bd15245..30214e4 100644
--- a/src/trace_processor/db/query_executor.cc
+++ b/src/trace_processor/db/query_executor.cc
@@ -57,6 +57,21 @@
}
}
+ // Given the chain a chance to return a single row which uniquely matches
+ // this constraint. This is a relatively frequent occurence e.g. id equality
+ // constraints so it is valuable to have an explicit fastpath.
+ uint32_t unique_row;
+ switch (chain.UniqueSearch(c.op, c.value, &unique_row)) {
+ case UniqueSearchResult::kMatch:
+ rm->IntersectExact(unique_row);
+ return;
+ case UniqueSearchResult::kNoMatch:
+ rm->Clear();
+ return;
+ case UniqueSearchResult::kNeedsFullSearch:
+ break;
+ }
+
// Comparison of NULL with any operation apart from |IS_NULL| and
// |IS_NOT_NULL| should return no rows.
if (c.value.is_null() && c.op != FilterOp::kIsNull &&
diff --git a/src/trace_processor/db/query_executor_benchmark.cc b/src/trace_processor/db/query_executor_benchmark.cc
index fa79206..dd1e8a9 100644
--- a/src/trace_processor/db/query_executor_benchmark.cc
+++ b/src/trace_processor/db/query_executor_benchmark.cc
@@ -67,8 +67,6 @@
constexpr std::string_view kHeapGraphObjectTable =
"test/data/heap_pgraph_object_for_benchmarks_query.csv";
-enum DB { V1, V2 };
-
std::vector<std::string> SplitCSVLine(const std::string& line) {
std::vector<std::string> output;
uint32_t start = 0;
@@ -231,7 +229,6 @@
void BenchmarkSliceTableFilter(benchmark::State& state,
SliceTableForBenchmark& table,
std::initializer_list<Constraint> c) {
- Table::kUseFilterV2 = state.range(0) == 1;
for (auto _ : state) {
benchmark::DoNotOptimize(table.table_.QueryToRowMap(c, {}));
}
@@ -244,7 +241,6 @@
void BenchmarkSliceTableSort(benchmark::State& state,
SliceTableForBenchmark& table,
std::initializer_list<Order> ob) {
- Table::kUseSortV2 = state.range(0) == 1;
for (auto _ : state) {
benchmark::DoNotOptimize(table.table_.Sort(ob));
}
@@ -258,7 +254,6 @@
benchmark::State& state,
ExpectedFrameTimelineTableForBenchmark& table,
Constraint c) {
- Table::kUseFilterV2 = state.range(0) == 1;
for (auto _ : state) {
benchmark::DoNotOptimize(table.table_.QueryToRowMap({c}, {}));
}
@@ -271,7 +266,6 @@
void BenchmarkFtraceEventTableFilter(benchmark::State& state,
FtraceEventTableForBenchmark& table,
std::initializer_list<Constraint> c) {
- Table::kUseFilterV2 = state.range(0) == 1;
for (auto _ : state) {
benchmark::DoNotOptimize(table.table_.QueryToRowMap(c, {}));
}
@@ -284,7 +278,6 @@
void BenchmarkFtraceEventTableSort(benchmark::State& state,
FtraceEventTableForBenchmark& table,
std::initializer_list<Order> ob) {
- Table::kUseSortV2 = state.range(0) == 1;
for (auto _ : state) {
benchmark::DoNotOptimize(table.table_.Sort(ob));
}
@@ -299,7 +292,7 @@
BenchmarkSliceTableFilter(state, table, {table.table_.track_id().eq(100)});
}
-BENCHMARK(BM_QESliceTableTrackIdEq)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableTrackIdEq);
void BM_QESliceTableParentIdIsNotNull(benchmark::State& state) {
SliceTableForBenchmark table(state);
@@ -307,28 +300,28 @@
{table.table_.parent_id().is_not_null()});
}
-BENCHMARK(BM_QESliceTableParentIdIsNotNull)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableParentIdIsNotNull);
void BM_QESliceTableParentIdEq(benchmark::State& state) {
SliceTableForBenchmark table(state);
BenchmarkSliceTableFilter(state, table, {table.table_.parent_id().eq(88)});
}
-BENCHMARK(BM_QESliceTableParentIdEq)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableParentIdEq);
void BM_QESliceTableNameEq(benchmark::State& state) {
SliceTableForBenchmark table(state);
BenchmarkSliceTableFilter(state, table, {table.table_.name().eq("cheese")});
}
-BENCHMARK(BM_QESliceTableNameEq)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableNameEq);
void BM_QESliceTableNameGlobNoStars(benchmark::State& state) {
SliceTableForBenchmark table(state);
BenchmarkSliceTableFilter(state, table, {table.table_.name().glob("cheese")});
}
-BENCHMARK(BM_QESliceTableNameGlobNoStars)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableNameGlobNoStars);
void BM_QESliceTableNameGlob(benchmark::State& state) {
SliceTableForBenchmark table(state);
@@ -336,7 +329,7 @@
{table.table_.name().glob("chee*se")});
}
-BENCHMARK(BM_QESliceTableNameGlob)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableNameGlob);
void BM_QESliceTableNameRegex(benchmark::State& state) {
SliceTableForBenchmark table(state);
@@ -344,14 +337,14 @@
{table.table_.name().regex(".*Pool.*")});
}
-BENCHMARK(BM_QESliceTableNameRegex)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableNameRegex);
void BM_QESliceTableSorted(benchmark::State& state) {
SliceTableForBenchmark table(state);
BenchmarkSliceTableFilter(state, table, {table.table_.ts().gt(1000)});
}
-BENCHMARK(BM_QESliceTableSorted)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableSorted);
void BM_QEFilterWithSparseSelector(benchmark::State& state) {
ExpectedFrameTimelineTableForBenchmark table(state);
@@ -359,28 +352,28 @@
table.table_.track_id().eq(88));
}
-BENCHMARK(BM_QEFilterWithSparseSelector)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFilterWithSparseSelector);
void BM_QEFilterWithDenseSelector(benchmark::State& state) {
FtraceEventTableForBenchmark table(state);
BenchmarkFtraceEventTableFilter(state, table, {table.table_.cpu().eq(4)});
}
-BENCHMARK(BM_QEFilterWithDenseSelector)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFilterWithDenseSelector);
void BM_QESliceEventFilterId(benchmark::State& state) {
SliceTableForBenchmark table(state);
BenchmarkSliceTableFilter(state, table, {table.table_.id().eq(500)});
}
-BENCHMARK(BM_QESliceEventFilterId)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceEventFilterId);
void BM_QEFtraceEventFilterId(benchmark::State& state) {
FtraceEventTableForBenchmark table(state);
BenchmarkFtraceEventTableFilter(state, table, {table.table_.id().eq(500)});
}
-BENCHMARK(BM_QEFtraceEventFilterId)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFtraceEventFilterId);
void BM_QESliceTableTsAndTrackId(benchmark::State& state) {
SliceTableForBenchmark table(state);
@@ -390,7 +383,7 @@
table.table_.track_id().eq(100)});
}
-BENCHMARK(BM_QESliceTableTsAndTrackId)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceTableTsAndTrackId);
void BM_QEFilterOneElement(benchmark::State& state) {
SliceTableForBenchmark table(state);
@@ -398,11 +391,9 @@
state, table, {table.table_.id().eq(10), table.table_.dur().eq(100)});
}
-BENCHMARK(BM_QEFilterOneElement)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFilterOneElement);
void BM_QEFilterWithArrangement(benchmark::State& state) {
- Table::kUseFilterV2 = state.range(0) == 1;
-
SliceTableForBenchmark table(state);
Order order{table.table_.dur().index_in_table(), false};
Table slice_sorted_with_duration = table.table_.Sort({order});
@@ -418,11 +409,9 @@
benchmark::Counter::kInvert);
}
-BENCHMARK(BM_QEFilterWithArrangement)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFilterWithArrangement);
void BM_QEDenseNullFilter(benchmark::State& state) {
- Table::kUseFilterV2 = state.range(0) == 1;
-
HeapGraphObjectTableForBenchmark table(state);
Constraint c{table.table_.reference_set_id().index_in_table(), FilterOp::kGt,
SqlValue::Long(1000)};
@@ -434,11 +423,9 @@
benchmark::Counter::kIsIterationInvariantRate |
benchmark::Counter::kInvert);
}
-BENCHMARK(BM_QEDenseNullFilter)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEDenseNullFilter);
void BM_QEDenseNullFilterIsNull(benchmark::State& state) {
- Table::kUseFilterV2 = state.range(0) == 1;
-
HeapGraphObjectTableForBenchmark table(state);
Constraint c{table.table_.reference_set_id().index_in_table(),
FilterOp::kIsNull, SqlValue()};
@@ -450,7 +437,7 @@
benchmark::Counter::kIsIterationInvariantRate |
benchmark::Counter::kInvert);
}
-BENCHMARK(BM_QEDenseNullFilterIsNull)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEDenseNullFilterIsNull);
void BM_QEIdColumnWithIntAsDouble(benchmark::State& state) {
SliceTableForBenchmark table(state);
@@ -459,7 +446,7 @@
BenchmarkSliceTableFilter(state, table, {c});
}
-BENCHMARK(BM_QEIdColumnWithIntAsDouble)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEIdColumnWithIntAsDouble);
void BM_QEIdColumnWithDouble(benchmark::State& state) {
SliceTableForBenchmark table(state);
@@ -468,11 +455,9 @@
BenchmarkSliceTableFilter(state, table, {c});
}
-BENCHMARK(BM_QEIdColumnWithDouble)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEIdColumnWithDouble);
void BM_QEFilterOrderedArrangement(benchmark::State& state) {
- Table::kUseFilterV2 = state.range(0) == 1;
-
SliceTableForBenchmark table(state);
Order order{table.table_.dur().index_in_table(), false};
Table slice_sorted_with_duration = table.table_.Sort({order});
@@ -488,29 +473,28 @@
benchmark::Counter::kInvert);
}
-BENCHMARK(BM_QEFilterOrderedArrangement)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFilterOrderedArrangement);
void BM_QESliceSortNumericAsc(benchmark::State& state) {
SliceTableForBenchmark table(state);
BenchmarkSliceTableSort(state, table, {table.table_.track_id().ascending()});
}
-BENCHMARK(BM_QESliceSortNumericAsc)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceSortNumericAsc);
void BM_QESliceSortNullNumericAsc(benchmark::State& state) {
SliceTableForBenchmark table(state);
BenchmarkSliceTableSort(state, table, {table.table_.parent_id().ascending()});
}
-BENCHMARK(BM_QESliceSortNullNumericAsc)->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QESliceSortNullNumericAsc);
void BM_QEFtraceEventSortSelectorNumericAsc(benchmark::State& state) {
FtraceEventTableForBenchmark table(state);
BenchmarkFtraceEventTableSort(state, table, {table.table_.cpu().ascending()});
}
-BENCHMARK(BM_QEFtraceEventSortSelectorNumericAsc)
- ->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFtraceEventSortSelectorNumericAsc);
void BM_QEFtraceEventSortSelectorNumericDesc(benchmark::State& state) {
FtraceEventTableForBenchmark table(state);
@@ -518,8 +502,7 @@
{table.table_.cpu().descending()});
}
-BENCHMARK(BM_QEFtraceEventSortSelectorNumericDesc)
- ->ArgsProduct({{DB::V1, DB::V2}});
+BENCHMARK(BM_QEFtraceEventSortSelectorNumericDesc);
} // namespace
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/db/query_executor_unittest.cc b/src/trace_processor/db/query_executor_unittest.cc
index a1a5ab3..f0d8f03 100644
--- a/src/trace_processor/db/query_executor_unittest.cc
+++ b/src/trace_processor/db/query_executor_unittest.cc
@@ -252,11 +252,11 @@
}
TEST(QueryExecutor, ArrangementOverlaySubsetInputRange) {
- auto fake = column::FakeStorage::SearchSubset(5u, RowMap::Range(2u, 4u));
+ auto fake = column::FakeStorageChain::SearchSubset(5u, RowMap::Range(2u, 4u));
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
RowMap rm(1, 3);
@@ -266,11 +266,12 @@
}
TEST(QueryExecutor, ArrangementOverlaySubsetInputBitvector) {
- auto fake = column::FakeStorage::SearchSubset(5u, BitVector({0, 0, 1, 1, 0}));
+ auto fake =
+ column::FakeStorageChain::SearchSubset(5u, BitVector({0, 0, 1, 1, 0}));
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
- auto chain = storage.MakeChain(fake->MakeChain());
+ auto chain = storage.MakeChain(std::move(fake));
Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
RowMap rm(1, 3);
diff --git a/src/trace_processor/db/table.cc b/src/trace_processor/db/table.cc
index b5c7e54..7bedbb7 100644
--- a/src/trace_processor/db/table.cc
+++ b/src/trace_processor/db/table.cc
@@ -23,6 +23,7 @@
#include <vector>
#include "perfetto/base/logging.h"
+#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/ref_counted.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/containers/string_pool.h"
@@ -37,9 +38,6 @@
namespace perfetto::trace_processor {
-bool Table::kUseFilterV2 = true;
-bool Table::kUseSortV2 = true;
-
Table::Table(StringPool* pool,
uint32_t row_count,
std::vector<ColumnLegacy> columns,
@@ -90,9 +88,20 @@
}
RowMap Table::QueryToRowMap(const std::vector<Constraint>& cs,
- const std::vector<Order>& ob,
- RowMap::OptimizeFor optimize_for) const {
- RowMap rm = FilterToRowMap(cs, optimize_for);
+ const std::vector<Order>& ob) const {
+ // We need to delay creation of the chains to this point because of Chrome
+ // does not want the binary size overhead of including the chain
+ // implementations. As they also don't query tables (instead just iterating)
+ // over them), using a combination of dead code elimination and linker
+ // stripping all chain related code be removed.
+ //
+ // From rough benchmarking, this has a negligible impact on peformance as this
+ // branch is almost never taken.
+ if (PERFETTO_UNLIKELY(chains_.size() != columns_.size())) {
+ CreateChains();
+ }
+
+ RowMap rm = QueryExecutor::FilterLegacy(this, cs);
if (ob.empty())
return rm;
@@ -112,43 +121,7 @@
PERFETTO_DCHECK(ob.front().desc);
std::reverse(idx.begin(), idx.end());
} else {
- // As our data is columnar, it's always more efficient to sort one column
- // at a time rather than try and sort lexiographically all at once.
- // To preserve correctness, we need to stably sort the index vector once
- // for each order by in *reverse* order. Reverse order is important as it
- // preserves the lexiographical property.
- //
- // For example, suppose we have the following:
- // Table {
- // Column x;
- // Column y
- // Column z;
- // }
- //
- // Then, to sort "y asc, x desc", we could do one of two things:
- // 1) sort the index vector all at once and on each index, we compare
- // y then z. This is slow as the data is columnar and we need to
- // repeatedly branch inside each column.
- // 2) we can stably sort first on x desc and then sort on y asc. This will
- // first put all the x in the correct order such that when we sort on
- // y asc, we will have the correct order of x where y is the same (since
- // the sort is stable).
- //
- // TODO(lalitm): it is possible that we could sort the last constraint (i.e.
- // the first constraint in the below loop) in a non-stable way. However,
- // this is more subtle than it appears as we would then need special
- // handling where there are order bys on a column which is already sorted
- // (e.g. ts, id). Investigate whether the performance gains from this are
- // worthwhile. This also needs changes to the constraint modification logic
- // in DbSqliteTable which currently eliminates constraints on sorted
- // columns.
- if (Table::kUseSortV2) {
- QueryExecutor::SortLegacy(this, ob, idx);
- } else {
- for (auto it = ob.rbegin(); it != ob.rend(); ++it) {
- columns_[it->col_idx].StableSort(it->desc, &idx);
- }
- }
+ QueryExecutor::SortLegacy(this, ob, idx);
}
return RowMap(std::move(idx));
}
@@ -211,19 +184,21 @@
storage_layers_ = std::move(storage_layers);
null_layers_ = std::move(null_layers);
overlay_layers_ = std::move(overlay_layers);
+}
+void Table::CreateChains() const {
+ chains_.resize(columns_.size());
for (uint32_t i = 0; i < columns_.size(); ++i) {
- auto chain = storage_layers_[i]->MakeChain();
+ chains_[i] = storage_layers_[i]->MakeChain();
if (const auto& null_overlay = null_layers_[i]; null_overlay.get()) {
- chain = null_overlay->MakeChain(std::move(chain));
+ chains_[i] = null_overlay->MakeChain(std::move(chains_[i]));
}
const auto& oly_idx = columns_[i].overlay_index();
if (const auto& overlay = overlay_layers_[oly_idx]; overlay.get()) {
- chain = overlay->MakeChain(
- std::move(chain),
+ chains_[i] = overlay->MakeChain(
+ std::move(chains_[i]),
column::DataLayer::ChainCreationArgs{columns_[i].IsSorted()});
}
- chains_.emplace_back(std::move(chain));
}
}
diff --git a/src/trace_processor/db/table.h b/src/trace_processor/db/table.h
index 4ed56c8..eab9f92 100644
--- a/src/trace_processor/db/table.h
+++ b/src/trace_processor/db/table.h
@@ -118,9 +118,6 @@
std::vector<Column> columns;
};
- static bool kUseFilterV2;
- static bool kUseSortV2;
-
virtual ~Table();
// We explicitly define the move constructor here because we need to update
@@ -135,10 +132,8 @@
// Filters and sorts the tables with the arguments specified, returning the
// result as a RowMap.
- RowMap QueryToRowMap(
- const std::vector<Constraint>&,
- const std::vector<Order>&,
- RowMap::OptimizeFor = RowMap::OptimizeFor::kMemory) const;
+ RowMap QueryToRowMap(const std::vector<Constraint>&,
+ const std::vector<Order>&) const;
// Applies the RowMap |rm| onto this table and returns an iterator over the
// resulting rows.
@@ -202,25 +197,7 @@
private:
friend class ColumnLegacy;
- PERFETTO_ALWAYS_INLINE RowMap FilterToRowMap(
- const std::vector<Constraint>& cs,
- RowMap::OptimizeFor optimize_for = RowMap::OptimizeFor::kMemory) const {
- if (cs.empty()) {
- return {0, row_count_, optimize_for};
- }
-
- if (kUseFilterV2) {
- if (optimize_for == RowMap::OptimizeFor::kMemory) {
- return QueryExecutor::FilterLegacy(this, cs);
- }
- return RowMap(QueryExecutor::FilterLegacy(this, cs).TakeAsIndexVector());
- }
- RowMap rm(0, row_count_, optimize_for);
- for (const Constraint& c : cs) {
- columns_[c.col_idx].FilterInto(c.op, c.value, &rm);
- }
- return rm;
- }
+ void CreateChains() const;
Table CopyExceptOverlays() const;
@@ -232,7 +209,7 @@
std::vector<RefPtr<column::DataLayer>> storage_layers_;
std::vector<RefPtr<column::DataLayer>> null_layers_;
std::vector<RefPtr<column::DataLayer>> overlay_layers_;
- std::vector<std::unique_ptr<column::DataLayerChain>> chains_;
+ mutable std::vector<std::unique_ptr<column::DataLayerChain>> chains_;
};
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index 823edd8..dac6e41 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -44,8 +44,6 @@
"slice_tracker.h",
"slice_translation_table.cc",
"slice_translation_table.h",
- "stack_profile_tracker.cc",
- "stack_profile_tracker.h",
"system_info_tracker.cc",
"system_info_tracker.h",
"trace_parser.cc",
@@ -68,10 +66,7 @@
"../../../base",
"../../db:minimal",
"../../storage",
- "../../tables:tables",
"../../types",
- "../../util:profiler_util",
- "../../util:stack_traces_util",
"../fuchsia:fuchsia_record",
"../systrace:systrace_line",
]
diff --git a/src/trace_processor/importers/common/stack_profile_tracker.cc b/src/trace_processor/importers/common/stack_profile_tracker.cc
deleted file mode 100644
index ad57523..0000000
--- a/src/trace_processor/importers/common/stack_profile_tracker.cc
+++ /dev/null
@@ -1,160 +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.
- */
-
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
-
-#include "perfetto/ext/base/string_utils.h"
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/profiler_tables_py.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/profiler_util.h"
-#include "src/trace_processor/util/stack_traces_util.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-namespace {
-std::string CleanBuildId(base::StringView build_id) {
- if (build_id.empty()) {
- return build_id.ToStdString();
- }
- // If the build_id is 33 characters long, we assume it's a Breakpad debug
- // identifier which is already in Hex and doesn't need conversion.
- // TODO(b/148109467): Remove workaround once all active Chrome versions
- // write raw bytes instead of a string as build_id.
- if (util::IsHexModuleId(build_id)) {
- return build_id.ToStdString();
- }
-
- return base::ToHex(build_id.data(), build_id.size());
-}
-
-} // namespace
-
-std::vector<FrameId> StackProfileTracker::JavaFramesForName(
- NameInPackage name) const {
- if (const auto* frames = java_frames_for_name_.Find(name); frames) {
- return *frames;
- }
- return {};
-}
-
-std::vector<MappingId> StackProfileTracker::FindMappingRow(
- StringId name,
- StringId build_id) const {
- if (const auto* mappings =
- mappings_by_name_and_build_id_.Find(std::make_pair(name, build_id));
- mappings) {
- return *mappings;
- }
- return {};
-}
-
-std::vector<FrameId> StackProfileTracker::FindFrameIds(MappingId mapping_id,
- uint64_t rel_pc) const {
- if (const auto* frames =
- frame_by_mapping_and_rel_pc_.Find(std::make_pair(mapping_id, rel_pc));
- frames) {
- return *frames;
- }
- return {};
-}
-
-MappingId StackProfileTracker::InternMapping(
- const CreateMappingParams& params) {
- tables::StackProfileMappingTable::Row row;
- row.build_id = InternBuildId(params.build_id);
- row.exact_offset = static_cast<int64_t>(params.exact_offset);
- row.start_offset = static_cast<int64_t>(params.start_offset);
- row.start = static_cast<int64_t>(params.start);
- row.end = static_cast<int64_t>(params.end);
- row.load_bias = static_cast<int64_t>(params.load_bias);
- row.name = context_->storage->InternString(params.name);
-
- if (MappingId* id = mapping_unique_row_index_.Find(row); id) {
- return *id;
- }
-
- MappingId mapping_id =
- context_->storage->mutable_stack_profile_mapping_table()->Insert(row).id;
- mapping_unique_row_index_.Insert(row, mapping_id);
- mappings_by_name_and_build_id_[{row.name, row.build_id}].push_back(
- mapping_id);
- return mapping_id;
-}
-
-CallsiteId StackProfileTracker::InternCallsite(
- std::optional<CallsiteId> parent_callsite_id,
- FrameId frame_id,
- uint32_t depth) {
- tables::StackProfileCallsiteTable::Row row{depth, parent_callsite_id,
- frame_id};
- if (CallsiteId* id = callsite_unique_row_index_.Find(row); id) {
- return *id;
- }
-
- CallsiteId callsite_id =
- context_->storage->mutable_stack_profile_callsite_table()->Insert(row).id;
- callsite_unique_row_index_.Insert(row, callsite_id);
- return callsite_id;
-}
-
-FrameId StackProfileTracker::InternFrame(MappingId mapping_id,
- uint64_t rel_pc,
- base::StringView function_name) {
- tables::StackProfileFrameTable::Row row;
- row.mapping = mapping_id;
- row.rel_pc = static_cast<int64_t>(rel_pc);
- row.name = context_->storage->InternString(function_name);
-
- if (FrameId* id = frame_unique_row_index_.Find(row); id) {
- return *id;
- }
-
- FrameId frame_id =
- context_->storage->mutable_stack_profile_frame_table()->Insert(row).id;
- frame_unique_row_index_.Insert(row, frame_id);
- frame_by_mapping_and_rel_pc_[{mapping_id, rel_pc}].push_back(frame_id);
-
- if (function_name.find('.') != base::StringView::npos) {
- // Java frames always contain a '.'
- base::StringView mapping_name = context_->storage->GetString(
- context_->storage->stack_profile_mapping_table()
- .FindById(mapping_id)
- ->name());
- std::optional<std::string> package =
- PackageFromLocation(context_->storage.get(), mapping_name);
- if (package) {
- NameInPackage nip{row.name, context_->storage->InternString(
- base::StringView(*package))};
- java_frames_for_name_[nip].push_back(frame_id);
- } else if (mapping_name.find("/memfd:") == 0) {
- NameInPackage nip{row.name, context_->storage->InternString("memfd")};
- java_frames_for_name_[nip].push_back(frame_id);
- }
- }
-
- return frame_id;
-}
-
-StringId StackProfileTracker::InternBuildId(base::StringView build_id) {
- return context_->storage->InternString(
- base::StringView(CleanBuildId(build_id)));
-}
-
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/importers/common/stack_profile_tracker.h b/src/trace_processor/importers/common/stack_profile_tracker.h
deleted file mode 100644
index a1067b8..0000000
--- a/src/trace_processor/importers/common/stack_profile_tracker.h
+++ /dev/null
@@ -1,121 +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_IMPORTERS_COMMON_STACK_PROFILE_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_STACK_PROFILE_TRACKER_H_
-
-#include <cstdint>
-#include <optional>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "perfetto/ext/base/flat_hash_map.h"
-#include "perfetto/ext/base/hash.h"
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/profiler_tables_py.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-struct NameInPackage {
- StringId name;
- StringId package;
-
- bool operator==(const NameInPackage& b) const {
- return std::tie(name, package) == std::tie(b.name, b.package);
- }
-
- struct Hasher {
- size_t operator()(const NameInPackage& o) const {
- return static_cast<size_t>(
- base::Hasher::Combine(o.name.raw_id(), o.package.raw_id()));
- }
- };
-};
-
-class TraceProcessorContext;
-
-class StackProfileTracker {
- public:
- struct CreateMappingParams {
- base::StringView build_id;
- uint64_t exact_offset;
- uint64_t start_offset;
- uint64_t start;
- uint64_t end;
- uint64_t load_bias;
- base::StringView name;
- };
-
- explicit StackProfileTracker(TraceProcessorContext* context)
- : context_(context) {}
-
- std::vector<FrameId> JavaFramesForName(NameInPackage name) const;
- std::vector<MappingId> FindMappingRow(StringId name, StringId build_id) const;
- std::vector<FrameId> FindFrameIds(MappingId mapping_id,
- uint64_t rel_pc) const;
-
- MappingId InternMapping(const CreateMappingParams& params);
- CallsiteId InternCallsite(std::optional<CallsiteId> parent_callsite_id,
- FrameId frame_id,
- uint32_t depth);
- FrameId InternFrame(MappingId mapping_id,
- uint64_t rel_pc,
- base::StringView function_name);
-
- private:
- StringId InternBuildId(base::StringView build_id);
-
- TraceProcessorContext* const context_;
- base::FlatHashMap<tables::StackProfileMappingTable::Row, MappingId>
- mapping_unique_row_index_;
- base::FlatHashMap<tables::StackProfileCallsiteTable::Row, CallsiteId>
- callsite_unique_row_index_;
- base::FlatHashMap<tables::StackProfileFrameTable::Row, FrameId>
- frame_unique_row_index_;
-
- struct MappingHasher {
- size_t operator()(const std::pair<StringId, StringId>& o) const {
- return static_cast<size_t>(
- base::Hasher::Combine(o.first.raw_id(), o.second.raw_id()));
- }
- };
- base::FlatHashMap<std::pair<StringId, StringId>,
- std::vector<MappingId>,
- MappingHasher>
- mappings_by_name_and_build_id_;
-
- struct FrameHasher {
- size_t operator()(const std::pair<MappingId, uint64_t>& o) const {
- return static_cast<size_t>(
- base::Hasher::Combine(o.first.value, o.second));
- }
- };
- base::FlatHashMap<std::pair<MappingId, uint64_t>,
- std::vector<FrameId>,
- FrameHasher>
- frame_by_mapping_and_rel_pc_;
-
- base::FlatHashMap<NameInPackage, std::vector<FrameId>, NameInPackage::Hasher>
- java_frames_for_name_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_STACK_PROFILE_TRACKER_H_
diff --git a/src/trace_processor/importers/ftrace/BUILD.gn b/src/trace_processor/importers/ftrace/BUILD.gn
index c618978..8065a41 100644
--- a/src/trace_processor/importers/ftrace/BUILD.gn
+++ b/src/trace_processor/importers/ftrace/BUILD.gn
@@ -68,7 +68,6 @@
"../../../../protos/perfetto/trace:zero",
"../../../../protos/perfetto/trace/ftrace:zero",
"../../../../protos/perfetto/trace/interned_data:zero",
- "../../../../protos/perfetto/trace/profiling:zero",
"../../../protozero",
"../../sorter",
"../../storage",
@@ -77,7 +76,6 @@
"../common:parser_types",
"../i2c:full",
"../proto:minimal",
- "../proto:packet_sequence_state_generation_hdr",
"../syscalls:full",
"../systrace:systrace_parser",
]
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 951c03d..cfed1d1 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -32,7 +32,7 @@
#include "src/trace_processor/importers/ftrace/v4l2_tracker.h"
#include "src/trace_processor/importers/ftrace/virtio_video_tracker.h"
#include "src/trace_processor/importers/i2c/i2c_tracker.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/syscalls/syscall_tracker.h"
#include "src/trace_processor/importers/systrace/systrace_parser.h"
#include "src/trace_processor/storage/stats.h"
@@ -85,7 +85,6 @@
#include "protos/perfetto/trace/ftrace/vmscan.pbzero.h"
#include "protos/perfetto/trace/ftrace/workqueue.pbzero.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
index 8e72751..429cfce 100644
--- a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
@@ -120,6 +120,13 @@
cpu, kMaxCpuCount);
}
+ if (PERFETTO_UNLIKELY(decoder.lost_events())) {
+ // If set, it means that the kernel overwrote an unspecified number of
+ // events since our last read from the per-cpu buffer.
+ context_->storage->SetIndexedStats(stats::ftrace_cpu_has_data_loss,
+ static_cast<int>(cpu), 1);
+ }
+
ClockTracker::ClockId clock_id;
switch (decoder.ftrace_clock()) {
case FtraceClock::FTRACE_CLOCK_UNSPECIFIED:
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
index d644742..e61a137 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
@@ -29,12 +29,12 @@
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/importers/proto/additional_modules.h"
#include "src/trace_processor/importers/proto/default_modules.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/metadata.h"
#include "src/trace_processor/storage/trace_storage.h"
@@ -236,7 +236,8 @@
context_.track_tracker.reset(new TrackTracker(&context_));
context_.global_args_tracker.reset(
new GlobalArgsTracker(context_.storage.get()));
- context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
+ context_.global_stack_profile_tracker.reset(
+ new GlobalStackProfileTracker());
context_.args_tracker.reset(new ArgsTracker(&context_));
context_.args_translation_table.reset(new ArgsTranslationTable(storage_));
context_.metadata_tracker.reset(
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index 2eaa5fe..a901ae1 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -26,6 +26,8 @@
"chrome_system_probes_parser.h",
"default_modules.cc",
"default_modules.h",
+ "heap_profile_tracker.cc",
+ "heap_profile_tracker.h",
"memory_tracker_snapshot_module.cc",
"memory_tracker_snapshot_module.h",
"memory_tracker_snapshot_parser.cc",
@@ -42,10 +44,10 @@
"perf_sample_tracker.h",
"profile_module.cc",
"profile_module.h",
- "profile_packet_sequence_state.cc",
- "profile_packet_sequence_state.h",
"profile_packet_utils.cc",
"profile_packet_utils.h",
+ "profiler_util.cc",
+ "profiler_util.h",
"proto_incremental_state.h",
"proto_trace_parser.cc",
"proto_trace_parser.h",
@@ -53,8 +55,8 @@
"proto_trace_reader.h",
"proto_trace_tokenizer.cc",
"proto_trace_tokenizer.h",
- "stack_profile_sequence_state.cc",
- "stack_profile_sequence_state.h",
+ "stack_profile_tracker.cc",
+ "stack_profile_tracker.h",
"track_event_module.cc",
"track_event_module.h",
"track_event_parser.cc",
@@ -92,7 +94,6 @@
"../../tables",
"../../types",
"../../util:gzip",
- "../../util:profiler_util",
"../../util:stack_traces_util",
"../common",
"../common:parser_types",
@@ -154,7 +155,6 @@
":gen_cc_statsd_atoms_descriptor",
":gen_cc_trace_descriptor",
":minimal",
- ":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
"../../../../include/perfetto/ext/traced:sys_stats_counters",
"../../../../protos/perfetto/common:zero",
@@ -178,10 +178,8 @@
"../../tables",
"../../types",
"../../util:descriptors",
- "../../util:profiler_util",
"../../util:proto_profiler",
"../../util:proto_to_args_parser",
- "../../util:stack_traces_util",
"../common",
"../common:parser_types",
"../etw:full",
@@ -245,9 +243,9 @@
sources = [
"active_chrome_processes_tracker_unittest.cc",
"heap_graph_tracker_unittest.cc",
+ "heap_profile_tracker_unittest.cc",
"network_trace_module_unittest.cc",
"perf_sample_tracker_unittest.cc",
- "profile_packet_sequence_state_unittest.cc",
"proto_trace_parser_unittest.cc",
"string_encoding_utils_unittests.cc",
]
@@ -275,8 +273,6 @@
"../../storage",
"../../types",
"../../util:descriptors",
- "../../util:profiler_util",
- "../../util:stack_traces_util",
"../common",
"../ftrace:full",
]
diff --git a/src/trace_processor/importers/proto/heap_graph_module.cc b/src/trace_processor/importers/proto/heap_graph_module.cc
index 93fd468..cc1d7ad 100644
--- a/src/trace_processor/importers/proto/heap_graph_module.cc
+++ b/src/trace_processor/importers/proto/heap_graph_module.cc
@@ -19,9 +19,9 @@
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
+#include "src/trace_processor/importers/proto/profiler_util.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/profiler_util.h"
#include "protos/perfetto/trace/profiling/deobfuscation.pbzero.h"
#include "protos/perfetto/trace/profiling/heap_graph.pbzero.h"
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index 2e95889..fcbd054 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -22,8 +22,8 @@
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
#include "protos/perfetto/trace/profiling/heap_graph.pbzero.h"
+#include "src/trace_processor/importers/proto/profiler_util.h"
#include "src/trace_processor/tables/profiler_tables_py.h"
-#include "src/trace_processor/util/profiler_util.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc b/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
index ebc2a5e..70c7398 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
@@ -18,7 +18,7 @@
#include "perfetto/base/logging.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/util/profiler_util.h"
+#include "src/trace_processor/importers/proto/profiler_util.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
diff --git a/src/trace_processor/importers/proto/heap_profile_tracker.cc b/src/trace_processor/importers/proto/heap_profile_tracker.cc
new file mode 100644
index 0000000..ea20108
--- /dev/null
+++ b/src/trace_processor/importers/proto/heap_profile_tracker.cc
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
+
+#include "perfetto/base/logging.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+HeapProfileTracker::HeapProfileTracker(TraceProcessorContext* context)
+ : context_(context),
+ empty_(context_->storage->InternString({"", 0})),
+ art_heap_(context_->storage->InternString("com.android.art")) {}
+
+HeapProfileTracker::~HeapProfileTracker() = default;
+
+void HeapProfileTracker::SetProfilePacketIndex(uint32_t seq_id,
+ uint64_t index) {
+ SequenceState& sequence_state = sequence_state_[seq_id];
+ bool dropped_packet = false;
+ // heapprofd starts counting at index = 0.
+ if (!sequence_state.prev_index && index != 0) {
+ dropped_packet = true;
+ }
+
+ if (sequence_state.prev_index && *sequence_state.prev_index + 1 != index) {
+ dropped_packet = true;
+ }
+
+ if (dropped_packet) {
+ if (sequence_state.prev_index) {
+ PERFETTO_ELOG("Missing packets between %" PRIu64 " and %" PRIu64,
+ *sequence_state.prev_index, index);
+ } else {
+ PERFETTO_ELOG("Invalid first packet index %" PRIu64 " (!= 0)", index);
+ }
+
+ context_->storage->IncrementStats(stats::heapprofd_missing_packet);
+ }
+ sequence_state.prev_index = index;
+}
+
+void HeapProfileTracker::AddAllocation(
+ uint32_t seq_id,
+ SequenceStackProfileTracker* sequence_stack_profile_tracker,
+ const SourceAllocation& alloc,
+ const SequenceStackProfileTracker::InternLookup* intern_lookup) {
+ SequenceState& sequence_state = sequence_state_[seq_id];
+
+ auto opt_callstack_id = sequence_stack_profile_tracker->FindOrInsertCallstack(
+ alloc.callstack_id, intern_lookup);
+ if (!opt_callstack_id)
+ return;
+
+ CallsiteId callstack_id = *opt_callstack_id;
+
+ UniquePid upid = context_->process_tracker->GetOrCreateProcess(
+ static_cast<uint32_t>(alloc.pid));
+
+ tables::HeapProfileAllocationTable::Row alloc_row{
+ alloc.timestamp,
+ upid,
+ alloc.heap_name,
+ callstack_id,
+ static_cast<int64_t>(alloc.alloc_count),
+ static_cast<int64_t>(alloc.self_allocated)};
+
+ tables::HeapProfileAllocationTable::Row free_row{
+ alloc.timestamp,
+ upid,
+ alloc.heap_name,
+ callstack_id,
+ -static_cast<int64_t>(alloc.free_count),
+ -static_cast<int64_t>(alloc.self_freed)};
+
+ auto prev_alloc_it = sequence_state.prev_alloc.find({upid, callstack_id});
+ if (prev_alloc_it == sequence_state.prev_alloc.end()) {
+ std::tie(prev_alloc_it, std::ignore) = sequence_state.prev_alloc.emplace(
+ std::make_pair(upid, callstack_id),
+ tables::HeapProfileAllocationTable::Row{});
+ }
+
+ tables::HeapProfileAllocationTable::Row& prev_alloc = prev_alloc_it->second;
+
+ auto prev_free_it = sequence_state.prev_free.find({upid, callstack_id});
+ if (prev_free_it == sequence_state.prev_free.end()) {
+ std::tie(prev_free_it, std::ignore) = sequence_state.prev_free.emplace(
+ std::make_pair(upid, callstack_id),
+ tables::HeapProfileAllocationTable::Row{});
+ }
+
+ tables::HeapProfileAllocationTable::Row& prev_free = prev_free_it->second;
+
+ std::set<CallsiteId>& callstacks_for_source_callstack_id =
+ sequence_state.seen_callstacks[SourceAllocationIndex{
+ upid, alloc.callstack_id, alloc.heap_name}];
+ bool new_callstack;
+ std::tie(std::ignore, new_callstack) =
+ callstacks_for_source_callstack_id.emplace(callstack_id);
+
+ if (new_callstack) {
+ sequence_state.alloc_correction[alloc.callstack_id] = prev_alloc;
+ sequence_state.free_correction[alloc.callstack_id] = prev_free;
+ }
+
+ auto alloc_correction_it =
+ sequence_state.alloc_correction.find(alloc.callstack_id);
+ if (alloc_correction_it != sequence_state.alloc_correction.end()) {
+ const auto& alloc_correction = alloc_correction_it->second;
+ alloc_row.count += alloc_correction.count;
+ alloc_row.size += alloc_correction.size;
+ }
+
+ auto free_correction_it =
+ sequence_state.free_correction.find(alloc.callstack_id);
+ if (free_correction_it != sequence_state.free_correction.end()) {
+ const auto& free_correction = free_correction_it->second;
+ free_row.count += free_correction.count;
+ free_row.size += free_correction.size;
+ }
+
+ tables::HeapProfileAllocationTable::Row alloc_delta = alloc_row;
+ tables::HeapProfileAllocationTable::Row free_delta = free_row;
+
+ alloc_delta.count -= prev_alloc.count;
+ alloc_delta.size -= prev_alloc.size;
+
+ free_delta.count -= prev_free.count;
+ free_delta.size -= prev_free.size;
+
+ if (alloc_delta.count < 0 || alloc_delta.size < 0 || free_delta.count > 0 ||
+ free_delta.size > 0) {
+ PERFETTO_DLOG("Non-monotonous allocation.");
+ context_->storage->IncrementIndexedStats(stats::heapprofd_malformed_packet,
+ static_cast<int>(upid));
+ return;
+ }
+
+ // Dump at max profiles do not have .count set.
+ if (alloc_delta.count || alloc_delta.size) {
+ context_->storage->mutable_heap_profile_allocation_table()->Insert(
+ alloc_delta);
+ }
+
+ // ART only reports allocations, and not frees. This throws off our logic
+ // that assumes that if a new object was allocated with the same address,
+ // the old one has to have been freed in the meantime.
+ // See HeapTracker::RecordMalloc in bookkeeping.cc.
+ if (alloc.heap_name != art_heap_ && (free_delta.count || free_delta.size)) {
+ context_->storage->mutable_heap_profile_allocation_table()->Insert(
+ free_delta);
+ }
+
+ prev_alloc = alloc_row;
+ prev_free = free_row;
+}
+
+void HeapProfileTracker::StoreAllocation(uint32_t seq_id,
+ SourceAllocation alloc) {
+ SequenceState& sequence_state = sequence_state_[seq_id];
+ sequence_state.pending_allocs.emplace_back(std::move(alloc));
+}
+
+void HeapProfileTracker::CommitAllocations(
+ uint32_t seq_id,
+ SequenceStackProfileTracker* sequence_stack_profile_tracker,
+ const SequenceStackProfileTracker::InternLookup* intern_lookup) {
+ SequenceState& sequence_state = sequence_state_[seq_id];
+ for (const auto& p : sequence_state.pending_allocs)
+ AddAllocation(seq_id, sequence_stack_profile_tracker, p, intern_lookup);
+ sequence_state.pending_allocs.clear();
+}
+
+void HeapProfileTracker::FinalizeProfile(
+ uint32_t seq_id,
+ SequenceStackProfileTracker* sequence_stack_profile_tracker,
+ const SequenceStackProfileTracker::InternLookup* intern_lookup) {
+ CommitAllocations(seq_id, sequence_stack_profile_tracker, intern_lookup);
+ sequence_stack_profile_tracker->ClearIndices();
+}
+
+void HeapProfileTracker::NotifyEndOfFile() {
+ for (const auto& key_and_sequence_state : sequence_state_) {
+ const SequenceState& sequence_state = key_and_sequence_state.second;
+ if (!sequence_state.pending_allocs.empty()) {
+ context_->storage->IncrementStats(stats::heapprofd_non_finalized_profile);
+ }
+ }
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/heap_profile_tracker.h b/src/trace_processor/importers/proto/heap_profile_tracker.h
new file mode 100644
index 0000000..5ed5394
--- /dev/null
+++ b/src/trace_processor/importers/proto/heap_profile_tracker.h
@@ -0,0 +1,126 @@
+/*
+ * 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_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_
+
+#include <optional>
+#include <set>
+#include <unordered_map>
+
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+class HeapProfileTracker {
+ public:
+ struct SourceAllocation {
+ uint64_t pid = 0;
+ // This is int64_t, because we get this from the TraceSorter which also
+ // converts this for us.
+ int64_t timestamp = 0;
+ StringPool::Id heap_name;
+ SequenceStackProfileTracker::SourceCallstackId callstack_id = 0;
+ uint64_t self_allocated = 0;
+ uint64_t self_freed = 0;
+ uint64_t alloc_count = 0;
+ uint64_t free_count = 0;
+ };
+
+ void SetProfilePacketIndex(uint32_t seq_id, uint64_t id);
+
+ explicit HeapProfileTracker(TraceProcessorContext* context);
+
+ void StoreAllocation(uint32_t seq_id, SourceAllocation);
+
+ // Call after the last profile packet of a dump to commit the allocations
+ // that had been stored using StoreAllocation and clear internal indices
+ // for that dump.
+ void FinalizeProfile(
+ uint32_t seq_id,
+ SequenceStackProfileTracker* sequence_stack_profile_tracker,
+ const SequenceStackProfileTracker::InternLookup* lookup);
+
+ // Only commit the allocations that had been stored using StoreAllocations.
+ // This is only needed in tests, use FinalizeProfile instead.
+ void CommitAllocations(
+ uint32_t seq_id,
+ SequenceStackProfileTracker* sequence_stack_profile_tracker,
+ const SequenceStackProfileTracker::InternLookup* lookup);
+
+ void NotifyEndOfFile();
+
+ ~HeapProfileTracker();
+
+ private:
+ void AddAllocation(
+ uint32_t seq_id,
+ SequenceStackProfileTracker* sequence_stack_profile_tracker,
+ const SourceAllocation&,
+ const SequenceStackProfileTracker::InternLookup* intern_lookup = nullptr);
+ struct SourceAllocationIndex {
+ UniquePid upid;
+ SequenceStackProfileTracker::SourceCallstackId src_callstack_id;
+ StringPool::Id heap_name;
+ bool operator<(const SourceAllocationIndex& o) const {
+ return std::tie(upid, src_callstack_id, heap_name) <
+ std::tie(o.upid, o.src_callstack_id, o.heap_name);
+ }
+ };
+ struct SequenceState {
+ std::vector<SourceAllocation> pending_allocs;
+
+ std::unordered_map<std::pair<UniquePid, CallsiteId>,
+ tables::HeapProfileAllocationTable::Row>
+ prev_alloc;
+ std::unordered_map<std::pair<UniquePid, CallsiteId>,
+ tables::HeapProfileAllocationTable::Row>
+ prev_free;
+
+ // For continuous dumps, we only store the delta in the data-base. To do
+ // this, we subtract the previous dump's value. Sometimes, we should not
+ // do that subtraction, because heapprofd garbage collects stacks that
+ // have no unfreed allocations. If the application then allocations again
+ // at that stack, it gets recreated and initialized to zero.
+ //
+ // To correct for this, we add the previous' stacks value to the current
+ // one, and then handle it as normal. If it is the first time we see a
+ // SourceCallstackId for a CallsiteId, we put the previous value into
+ // the correction maps below.
+ std::map<SourceAllocationIndex, std::set<CallsiteId>> seen_callstacks;
+ std::map<SequenceStackProfileTracker::SourceCallstackId,
+ tables::HeapProfileAllocationTable::Row>
+ alloc_correction;
+ std::map<SequenceStackProfileTracker::SourceCallstackId,
+ tables::HeapProfileAllocationTable::Row>
+ free_correction;
+
+ std::optional<uint64_t> prev_index;
+ };
+ std::map<uint32_t, SequenceState> sequence_state_;
+ TraceProcessorContext* const context_;
+ const StringId empty_;
+ const StringId art_heap_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc b/src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc
similarity index 74%
rename from src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
rename to src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc
index ab947fa..558ad91 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
+++ b/src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-#include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
-#include <memory>
-
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -43,6 +40,7 @@
constexpr auto kMappingStart = 234;
constexpr auto kMappingEnd = 345;
constexpr auto kMappingLoadBias = 456;
+constexpr auto kDefaultSequence = 1;
// heapprofd on Android Q has large callstack ideas, explicitly test large
// values.
@@ -58,8 +56,10 @@
public:
HeapProfileTrackerDupTest() {
context.storage.reset(new TraceStorage());
- context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- packet_sequence_state.reset(new PacketSequenceState(&context));
+ context.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
+ sequence_stack_profile_tracker.reset(
+ new SequenceStackProfileTracker(&context));
+ context.heap_profile_tracker.reset(new HeapProfileTracker(&context));
mapping_name = context.storage->InternString("[mapping]");
fully_qualified_mapping_name = context.storage->InternString("/[mapping]");
@@ -68,17 +68,13 @@
}
protected:
- ProfilePacketSequenceState& profile_packet_sequence_state() {
- return *packet_sequence_state->current_generation()
- ->GetOrCreate<ProfilePacketSequenceState>();
- }
void InsertMapping(const Packet& packet) {
- profile_packet_sequence_state().AddString(packet.mapping_name_id,
+ sequence_stack_profile_tracker->AddString(packet.mapping_name_id,
"[mapping]");
- profile_packet_sequence_state().AddString(packet.build_id, kBuildIDName);
+ sequence_stack_profile_tracker->AddString(packet.build_id, kBuildIDName);
- ProfilePacketSequenceState::SourceMapping first_frame;
+ SequenceStackProfileTracker::SourceMapping first_frame;
first_frame.build_id = packet.build_id;
first_frame.exact_offset = kMappingExactOffset;
first_frame.start_offset = kMappingStartOffset;
@@ -87,27 +83,27 @@
first_frame.load_bias = kMappingLoadBias;
first_frame.name_ids = {packet.mapping_name_id};
- profile_packet_sequence_state().AddMapping(packet.mapping_id, first_frame);
+ sequence_stack_profile_tracker->AddMapping(packet.mapping_id, first_frame);
}
void InsertFrame(const Packet& packet) {
InsertMapping(packet);
- profile_packet_sequence_state().AddString(packet.frame_name_id, "[frame]");
+ sequence_stack_profile_tracker->AddString(packet.frame_name_id, "[frame]");
- ProfilePacketSequenceState::SourceFrame first_frame;
+ SequenceStackProfileTracker::SourceFrame first_frame;
first_frame.name_id = packet.frame_name_id;
first_frame.mapping_id = packet.mapping_id;
first_frame.rel_pc = kFrameRelPc;
- profile_packet_sequence_state().AddFrame(packet.frame_id, first_frame);
+ sequence_stack_profile_tracker->AddFrame(packet.frame_id, first_frame);
}
void InsertCallsite(const Packet& packet) {
InsertFrame(packet);
- ProfilePacketSequenceState::SourceCallstack first_callsite = {
+ SequenceStackProfileTracker::SourceCallstack first_callsite = {
packet.frame_id, packet.frame_id};
- profile_packet_sequence_state().AddCallstack(kCallstackId, first_callsite);
+ sequence_stack_profile_tracker->AddCallstack(kCallstackId, first_callsite);
}
StringId mapping_name;
@@ -115,16 +111,18 @@
StringId build;
StringId frame_name;
TraceProcessorContext context;
- std::unique_ptr<PacketSequenceState> packet_sequence_state;
+ std::unique_ptr<SequenceStackProfileTracker> sequence_stack_profile_tracker;
};
// Insert the same mapping from two different packets, with different strings
// interned, and assert we only store one.
TEST_F(HeapProfileTrackerDupTest, Mapping) {
InsertMapping(kFirstPacket);
- profile_packet_sequence_state().FinalizeProfile();
+ context.heap_profile_tracker->FinalizeProfile(
+ kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
InsertMapping(kSecondPacket);
- profile_packet_sequence_state().FinalizeProfile();
+ context.heap_profile_tracker->FinalizeProfile(
+ kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
EXPECT_THAT(context.storage->stack_profile_mapping_table().build_id()[0],
context.storage->InternString({kBuildIDHexName}));
@@ -146,9 +144,11 @@
// interned, and assert we only store one.
TEST_F(HeapProfileTrackerDupTest, Frame) {
InsertFrame(kFirstPacket);
- profile_packet_sequence_state().FinalizeProfile();
+ context.heap_profile_tracker->FinalizeProfile(
+ kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
InsertFrame(kSecondPacket);
- profile_packet_sequence_state().FinalizeProfile();
+ context.heap_profile_tracker->FinalizeProfile(
+ kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
const auto& frames = context.storage->stack_profile_frame_table();
EXPECT_THAT(frames.name()[0], frame_name);
@@ -160,9 +160,11 @@
// stored once.
TEST_F(HeapProfileTrackerDupTest, Callstack) {
InsertCallsite(kFirstPacket);
- profile_packet_sequence_state().FinalizeProfile();
+ context.heap_profile_tracker->FinalizeProfile(
+ kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
InsertCallsite(kSecondPacket);
- profile_packet_sequence_state().FinalizeProfile();
+ context.heap_profile_tracker->FinalizeProfile(
+ kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
const auto& callsite_table = context.storage->stack_profile_callsite_table();
const auto& depth = callsite_table.depth();
@@ -196,20 +198,22 @@
TEST(HeapProfileTrackerTest, SourceMappingPath) {
TraceProcessorContext context;
context.storage.reset(new TraceStorage());
- context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- PacketSequenceState pss(&context);
- ProfilePacketSequenceState& ppss =
- *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+ context.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
+ context.heap_profile_tracker.reset(new HeapProfileTracker(&context));
+
+ HeapProfileTracker* hpt = context.heap_profile_tracker.get();
+ std::unique_ptr<SequenceStackProfileTracker> spt(
+ new SequenceStackProfileTracker(&context));
constexpr auto kBuildId = 1u;
constexpr auto kMappingNameId1 = 2u;
constexpr auto kMappingNameId2 = 3u;
- ppss.AddString(kBuildId, "buildid");
- ppss.AddString(kMappingNameId1, "foo");
- ppss.AddString(kMappingNameId2, "bar");
+ spt->AddString(kBuildId, "buildid");
+ spt->AddString(kMappingNameId1, "foo");
+ spt->AddString(kMappingNameId2, "bar");
- ProfilePacketSequenceState::SourceMapping mapping;
+ SequenceStackProfileTracker::SourceMapping mapping;
mapping.build_id = kBuildId;
mapping.exact_offset = 1;
mapping.start_offset = 1;
@@ -217,8 +221,8 @@
mapping.end = 3;
mapping.load_bias = 0;
mapping.name_ids = {kMappingNameId1, kMappingNameId2};
- ppss.AddMapping(0, mapping);
- ppss.CommitAllocations();
+ spt->AddMapping(0, mapping);
+ hpt->CommitAllocations(kDefaultSequence, spt.get(), nullptr);
auto foo_bar_id = context.storage->string_pool().GetId("/foo/bar");
ASSERT_NE(foo_bar_id, std::nullopt);
EXPECT_THAT(context.storage->stack_profile_mapping_table().name()[0],
@@ -229,11 +233,12 @@
TEST(HeapProfileTrackerTest, Functional) {
TraceProcessorContext context;
context.storage.reset(new TraceStorage());
- context.stack_profile_tracker.reset(new StackProfileTracker(&context));
+ context.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
+ context.heap_profile_tracker.reset(new HeapProfileTracker(&context));
- PacketSequenceState pss(&context);
- ProfilePacketSequenceState& ppss =
- *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+ HeapProfileTracker* hpt = context.heap_profile_tracker.get();
+ std::unique_ptr<SequenceStackProfileTracker> spt(
+ new SequenceStackProfileTracker(&context));
uint32_t next_string_intern_id = 1;
@@ -247,7 +252,7 @@
for (size_t i = 0; i < base::ArraySize(mapping_names); ++i)
mapping_name_ids[i] = next_string_intern_id++;
- ProfilePacketSequenceState::SourceMapping
+ SequenceStackProfileTracker::SourceMapping
mappings[base::ArraySize(mapping_names)] = {};
mappings[0].build_id = build_id_ids[0];
mappings[0].exact_offset = 1;
@@ -278,7 +283,7 @@
for (size_t i = 0; i < base::ArraySize(function_names); ++i)
function_name_ids[i] = next_string_intern_id++;
- ProfilePacketSequenceState::SourceFrame
+ SequenceStackProfileTracker::SourceFrame
frames[base::ArraySize(function_names)];
frames[0].name_id = function_name_ids[0];
frames[0].mapping_id = 0;
@@ -296,41 +301,41 @@
frames[3].mapping_id = 2;
frames[3].rel_pc = 123;
- ProfilePacketSequenceState::SourceCallstack callstacks[3];
+ SequenceStackProfileTracker::SourceCallstack callstacks[3];
callstacks[0] = {2, 1, 0};
callstacks[1] = {2, 1, 0, 1, 0};
callstacks[2] = {0, 2, 0, 1, 2};
for (size_t i = 0; i < base::ArraySize(build_ids); ++i) {
auto interned = base::StringView(build_ids[i].data(), build_ids[i].size());
- ppss.AddString(build_id_ids[i], interned);
+ spt->AddString(build_id_ids[i], interned);
}
for (size_t i = 0; i < base::ArraySize(mapping_names); ++i) {
auto interned =
base::StringView(mapping_names[i].data(), mapping_names[i].size());
- ppss.AddString(mapping_name_ids[i], interned);
+ spt->AddString(mapping_name_ids[i], interned);
}
for (size_t i = 0; i < base::ArraySize(function_names); ++i) {
auto interned =
base::StringView(function_names[i].data(), function_names[i].size());
- ppss.AddString(function_name_ids[i], interned);
+ spt->AddString(function_name_ids[i], interned);
}
for (uint32_t i = 0; i < base::ArraySize(mappings); ++i)
- ppss.AddMapping(i, mappings[i]);
+ spt->AddMapping(i, mappings[i]);
for (uint32_t i = 0; i < base::ArraySize(frames); ++i)
- ppss.AddFrame(i, frames[i]);
+ spt->AddFrame(i, frames[i]);
for (uint32_t i = 0; i < base::ArraySize(callstacks); ++i)
- ppss.AddCallstack(i, callstacks[i]);
+ spt->AddCallstack(i, callstacks[i]);
- ppss.CommitAllocations();
+ hpt->CommitAllocations(kDefaultSequence, spt.get(), nullptr);
for (size_t i = 0; i < base::ArraySize(callstacks); ++i) {
std::optional<CallsiteId> parent;
- const ProfilePacketSequenceState::SourceCallstack& callstack =
+ const SequenceStackProfileTracker::SourceCallstack& callstack =
callstacks[i];
for (size_t depth = 0; depth < callstack.size(); ++depth) {
- auto frame_id = ppss.GetDatabaseFrameIdForTesting(callstack[depth]);
+ auto frame_id = spt->GetDatabaseFrameIdForTesting(callstack[depth]);
std::optional<CallsiteId> self = FindCallstack(
*context.storage, static_cast<int64_t>(depth), parent, frame_id);
ASSERT_TRUE(self.has_value());
@@ -338,7 +343,7 @@
}
}
- ppss.FinalizeProfile();
+ hpt->FinalizeProfile(kDefaultSequence, spt.get(), nullptr);
}
} // namespace
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
index 2ad0c7b..8c29222 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state.h
@@ -19,12 +19,13 @@
#include <stdint.h>
-#include <memory>
-#include <type_traits>
+#include <unordered_map>
#include <vector>
#include "perfetto/base/compiler.h"
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
+#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/interned_message_view.h"
@@ -33,8 +34,19 @@
class PacketSequenceState {
public:
+ // Helper to keep per sequence state. These are not reset when the generation
+ // changes.
+ // Trackers or parsers can add their custom per sequence state here instead of
+ // keeping a map from seq_id to some internal state.
+ // TODO(carlscab): We should come up with a nicer API that allows extensions
+ // to be notified of generation changes.
+ // TODO(carlscab): There is some existing code that could use this. Migrate.
+ struct ExtensibleSequenceState {
+ std::unique_ptr<Destructible> v8_sequence_state;
+ };
+
explicit PacketSequenceState(TraceProcessorContext* context)
- : context_(context) {
+ : context_(context), sequence_stack_profile_tracker_(context) {
current_generation_.reset(
new PacketSequenceStateGeneration(this, generation_index_++));
}
@@ -75,7 +87,7 @@
// sequence. Add a new generation with the updated defaults but the
// current generation's interned data state.
current_generation_.reset(new PacketSequenceStateGeneration(
- this, generation_index_++, current_generation_.get(),
+ this, generation_index_++, current_generation_->interned_data_,
std::move(defaults)));
}
@@ -107,6 +119,14 @@
bool IsIncrementalStateValid() const { return !packet_loss_; }
+ SequenceStackProfileTracker& sequence_stack_profile_tracker() {
+ return sequence_stack_profile_tracker_;
+ }
+
+ ExtensibleSequenceState& extensible_sequence_state() {
+ return extensible_sequence_state_;
+ }
+
// Returns a ref-counted ptr to the current generation.
RefPtr<PacketSequenceStateGeneration> current_generation() const {
return current_generation_;
@@ -154,8 +174,20 @@
int64_t track_event_thread_instruction_count_ = 0;
RefPtr<PacketSequenceStateGeneration> current_generation_;
+ SequenceStackProfileTracker sequence_stack_profile_tracker_;
+ ExtensibleSequenceState extensible_sequence_state_;
};
+template <uint32_t FieldId, typename MessageType>
+typename MessageType::Decoder*
+PacketSequenceStateGeneration::LookupInternedMessage(uint64_t iid) {
+ auto* interned_message_view = GetInternedMessageView(FieldId, iid);
+ if (!interned_message_view)
+ return nullptr;
+
+ return interned_message_view->template GetOrCreateDecoder<MessageType>();
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
index 1e89096..6e8e98d 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
@@ -15,38 +15,12 @@
*/
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include <cstddef>
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/storage/trace_storage.h"
namespace perfetto {
namespace trace_processor {
-PacketSequenceStateGeneration::PacketSequenceStateGeneration(
- PacketSequenceState* state,
- size_t generation_index,
- PacketSequenceStateGeneration* prev_gen,
- TraceBlobView defaults)
- : state_(state),
- generation_index_(generation_index),
- interned_data_(prev_gen->interned_data_),
- trace_packet_defaults_(InternedMessageView(std::move(defaults))),
- trackers_(prev_gen->trackers_) {
- for (auto& t : trackers_) {
- if (t.get() != nullptr) {
- t->set_generation(this);
- }
- }
-}
-
-PacketSequenceStateGeneration::InternedDataTracker::~InternedDataTracker() =
- default;
-
-TraceProcessorContext* PacketSequenceStateGeneration::GetContext() const {
- return state_->context();
-}
-
void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
TraceBlobView message) {
constexpr auto kIidFieldNumber = 1;
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.h b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
index 1f05d5c..9c7aa5a 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
@@ -17,17 +17,10 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
-#include <array>
-#include <cstddef>
-#include <memory>
#include <optional>
-#include <tuple>
-#include <type_traits>
#include <unordered_map>
-#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/ref_counted.h"
-#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/util/interned_message_view.h"
#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
@@ -42,65 +35,9 @@
std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
class PacketSequenceState;
-class TraceProcessorContext;
-
-class StackProfileSequenceState;
-class ProfilePacketSequenceState;
-class V8SequenceState;
-
-using InternedDataTrackers = std::tuple<StackProfileSequenceState,
- ProfilePacketSequenceState,
- V8SequenceState>;
class PacketSequenceStateGeneration : public RefCounted {
public:
- // Base class to add custom sequence state. This state is keep per sequence
- // and per incremental state interval, that is, each time incremental state is
- // reset a new instance is created but not each time `TracePacketDefaults` are
- // updated. Note that this means that different
- // `PacketSequenceStateGeneration` instances might point to the same
- // `InternedDataTracker` (because they only differ in their
- // `TracePacketDefaults`).
- //
- // ATTENTION: You should not create instances of these classes yourself but
- // use the `PacketSequenceStateGeneration::GetOrCreate<>' method instead.
- class InternedDataTracker : public RefCounted {
- public:
- virtual ~InternedDataTracker();
-
- protected:
- template <uint32_t FieldId, typename MessageType>
- typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
- return generation_->LookupInternedMessage<FieldId, MessageType>(iid);
- }
-
- InternedMessageView* GetInternedMessageView(uint32_t field_id,
- uint64_t iid) {
- return generation_->GetInternedMessageView(field_id, iid);
- }
-
- template <typename T>
- std::remove_cv_t<T>* GetOrCreate() {
- return generation_->GetOrCreate<T>();
- }
-
- private:
- friend PacketSequenceStateGeneration;
- // Called when the a new generation is created as a result of
- // `TracePacketDefaults` being updated.
- void set_generation(PacketSequenceStateGeneration* generation) {
- generation_ = generation;
- }
-
- // Note: A `InternedDataTracker` instance can be linked to multiple
- // `PacketSequenceStateGeneration` instances (when there are multiple
- // `TracePacketDefaults` in the same interning context). `generation_` will
- // point to the latest one. We keep this member private to prevent misuse /
- // confusion around this fact. Instead subclasses should access the public
- // methods of this class to get any interned data.
- PacketSequenceStateGeneration* generation_ = nullptr;
- };
-
// Returns |nullptr| if the message with the given |iid| was not found (also
// records a stat in this case).
template <uint32_t FieldId, typename MessageType>
@@ -142,47 +79,21 @@
PacketSequenceState* state() const { return state_; }
size_t generation_index() const { return generation_index_; }
- // Extension point for custom sequence state. To add new per sequence state
- // just subclass ´PacketSequenceStateGeneration´ and get your sequence bound
- // instance by calling this method.
- template <typename T>
- std::remove_cv_t<T>* GetOrCreate();
-
private:
friend class PacketSequenceState;
- // Helper to find the index in a tuple of a given type. Lookups are done
- // ignoring cv qualifiers. If no index is found size of the tuple is returned.
- //
- // ATTENTION: Duplicate types in the tuple will trigger a compiler error.
- template <typename Tuple, typename Type, size_t index = 0>
- static constexpr size_t FindUniqueType() {
- constexpr size_t kSize = std::tuple_size_v<Tuple>;
- if constexpr (index < kSize) {
- using TypeAtIndex = typename std::tuple_element<index, Tuple>::type;
- if constexpr (std::is_same_v<std::remove_cv_t<Type>,
- std::remove_cv_t<TypeAtIndex>>) {
- static_assert(FindUniqueType<Tuple, Type, index + 1>() == kSize,
- "Duplicate types.");
- return index;
- } else {
- return FindUniqueType<Tuple, Type, index + 1>();
- }
- } else {
- return kSize;
- }
- }
-
PacketSequenceStateGeneration(PacketSequenceState* state,
size_t generation_index)
: state_(state), generation_index_(generation_index) {}
PacketSequenceStateGeneration(PacketSequenceState* state,
size_t generation_index,
- PacketSequenceStateGeneration* prev_gen,
- TraceBlobView defaults);
-
- TraceProcessorContext* GetContext() const;
+ InternedFieldMap interned_data,
+ TraceBlobView defaults)
+ : state_(state),
+ generation_index_(generation_index),
+ interned_data_(interned_data),
+ trace_packet_defaults_(InternedMessageView(std::move(defaults))) {}
void InternMessage(uint32_t field_id, TraceBlobView message);
@@ -196,34 +107,8 @@
size_t generation_index_;
InternedFieldMap interned_data_;
std::optional<InternedMessageView> trace_packet_defaults_;
- std::array<RefPtr<InternedDataTracker>,
- std::tuple_size_v<InternedDataTrackers>>
- trackers_;
};
-template <typename T>
-std::remove_cv_t<T>* PacketSequenceStateGeneration::GetOrCreate() {
- constexpr size_t index = FindUniqueType<InternedDataTrackers, T>();
- static_assert(index < std::tuple_size_v<InternedDataTrackers>, "Not found");
- auto& ptr = trackers_[index];
- if (PERFETTO_UNLIKELY(ptr.get() == nullptr)) {
- ptr.reset(new T(GetContext()));
- ptr->set_generation(this);
- }
-
- return static_cast<std::remove_cv_t<T>*>(ptr.get());
-}
-
-template <uint32_t FieldId, typename MessageType>
-typename MessageType::Decoder*
-PacketSequenceStateGeneration::LookupInternedMessage(uint64_t iid) {
- auto* interned_message_view = GetInternedMessageView(FieldId, iid);
- if (!interned_message_view)
- return nullptr;
-
- return interned_message_view->template GetOrCreateDecoder<MessageType>();
-}
-
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_module.cc b/src/trace_processor/importers/proto/profile_module.cc
index 61596d3..c337869 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -25,18 +25,17 @@
#include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
+#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
-#include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
-#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
+#include "src/trace_processor/importers/proto/profiler_util.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/stats.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/profiler_tables_py.h"
#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/profiler_util.h"
#include "src/trace_processor/util/stack_traces_util.h"
#include "protos/perfetto/common/builtin_clock.pbzero.h"
@@ -92,7 +91,8 @@
ParsePerfSample(ts, data.sequence_state.get(), decoder);
return;
case TracePacket::kProfilePacketFieldNumber:
- ParseProfilePacket(ts, data.sequence_state->state(),
+ ParseProfilePacket(ts, data.sequence_state.get(),
+ decoder.trusted_packet_sequence_id(),
decoder.profile_packet());
return;
case TracePacket::kModuleSymbolsFieldNumber:
@@ -152,8 +152,9 @@
ProcessTracker* procs = context_->process_tracker.get();
TraceStorage* storage = context_->storage.get();
- StackProfileSequenceState& stack_profile_sequence_state =
- *sequence_state->GetOrCreate<StackProfileSequenceState>();
+ SequenceStackProfileTracker& sequence_stack_profile_tracker =
+ sequence_state->state()->sequence_stack_profile_tracker();
+ ProfilePacketInternLookup intern_lookup(sequence_state);
uint32_t pid = static_cast<uint32_t>(sequence_state->state()->pid());
uint32_t tid = static_cast<uint32_t>(sequence_state->state()->tid());
@@ -170,8 +171,8 @@
break;
}
- auto opt_cs_id =
- stack_profile_sequence_state.FindOrInsertCallstack(*callstack_it);
+ auto opt_cs_id = sequence_stack_profile_tracker.FindOrInsertCallstack(
+ *callstack_it, &intern_lookup);
if (!opt_cs_id) {
context_->storage->IncrementStats(stats::stackprofile_parser_error);
continue;
@@ -246,11 +247,12 @@
ts, static_cast<double>(sample.timebase_count()),
sampling_stream.timebase_track_id);
- StackProfileSequenceState& stack_profile_sequence_state =
- *sequence_state->GetOrCreate<StackProfileSequenceState>();
+ SequenceStackProfileTracker& stack_tracker =
+ sequence_state->state()->sequence_stack_profile_tracker();
+ ProfilePacketInternLookup intern_lookup(sequence_state);
uint64_t callstack_iid = sample.callstack_iid();
std::optional<CallsiteId> cs_id =
- stack_profile_sequence_state.FindOrInsertCallstack(callstack_iid);
+ stack_tracker.FindOrInsertCallstack(callstack_iid, &intern_lookup);
// A failed lookup of the interned callstack can mean either:
// (a) This is a counter-only profile without callstacks. Due to an
@@ -296,38 +298,45 @@
context_->storage->mutable_perf_sample_table()->Insert(sample_row);
}
-void ProfileModule::ParseProfilePacket(int64_t ts,
- PacketSequenceState* sequence_state,
- ConstBytes blob) {
- ProfilePacketSequenceState& profile_packet_sequence_state =
- *sequence_state->current_generation()
- ->GetOrCreate<ProfilePacketSequenceState>();
+void ProfileModule::ParseProfilePacket(
+ int64_t ts,
+ PacketSequenceStateGeneration* sequence_state,
+ uint32_t seq_id,
+ ConstBytes blob) {
protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
- profile_packet_sequence_state.SetProfilePacketIndex(packet.index());
+ context_->heap_profile_tracker->SetProfilePacketIndex(seq_id, packet.index());
for (auto it = packet.strings(); it; ++it) {
protos::pbzero::InternedString::Decoder entry(*it);
+
const char* str = reinterpret_cast<const char*>(entry.str().data);
auto str_view = base::StringView(str, entry.str().size);
- profile_packet_sequence_state.AddString(entry.iid(), str_view);
+ sequence_state->state()->sequence_stack_profile_tracker().AddString(
+ entry.iid(), str_view);
}
for (auto it = packet.mappings(); it; ++it) {
protos::pbzero::Mapping::Decoder entry(*it);
- profile_packet_sequence_state.AddMapping(
- entry.iid(), ProfilePacketUtils::MakeSourceMapping(entry));
+ SequenceStackProfileTracker::SourceMapping src_mapping =
+ ProfilePacketUtils::MakeSourceMapping(entry);
+ sequence_state->state()->sequence_stack_profile_tracker().AddMapping(
+ entry.iid(), src_mapping);
}
for (auto it = packet.frames(); it; ++it) {
protos::pbzero::Frame::Decoder entry(*it);
- profile_packet_sequence_state.AddFrame(
- entry.iid(), ProfilePacketUtils::MakeSourceFrame(entry));
+ SequenceStackProfileTracker::SourceFrame src_frame =
+ ProfilePacketUtils::MakeSourceFrame(entry);
+ sequence_state->state()->sequence_stack_profile_tracker().AddFrame(
+ entry.iid(), src_frame);
}
for (auto it = packet.callstacks(); it; ++it) {
protos::pbzero::Callstack::Decoder entry(*it);
- profile_packet_sequence_state.AddCallstack(
- entry.iid(), ProfilePacketUtils::MakeSourceCallstack(entry));
+ SequenceStackProfileTracker::SourceCallstack src_callstack =
+ ProfilePacketUtils::MakeSourceCallstack(entry);
+ sequence_state->state()->sequence_stack_profile_tracker().AddCallstack(
+ entry.iid(), src_callstack);
}
for (auto it = packet.process_dumps(); it; ++it) {
@@ -397,7 +406,7 @@
for (auto sample_it = entry.samples(); sample_it; ++sample_it) {
protos::pbzero::ProfilePacket::HeapSample::Decoder sample(*sample_it);
- ProfilePacketSequenceState::SourceAllocation src_allocation;
+ HeapProfileTracker::SourceAllocation src_allocation;
src_allocation.pid = entry.pid();
if (entry.heap_name().size != 0) {
src_allocation.heap_name =
@@ -418,11 +427,15 @@
src_allocation.free_count = sample.free_count();
}
- profile_packet_sequence_state.StoreAllocation(src_allocation);
+ context_->heap_profile_tracker->StoreAllocation(seq_id, src_allocation);
}
}
if (!packet.continued()) {
- profile_packet_sequence_state.FinalizeProfile();
+ PERFETTO_CHECK(sequence_state);
+ ProfilePacketInternLookup intern_lookup(sequence_state);
+ context_->heap_profile_tracker->FinalizeProfile(
+ seq_id, &sequence_state->state()->sequence_stack_profile_tracker(),
+ &intern_lookup);
}
}
@@ -438,7 +451,7 @@
module_symbols.build_id().data, module_symbols.build_id().size)));
}
- auto mapping_ids = context_->stack_profile_tracker->FindMappingRow(
+ auto mapping_ids = context_->global_stack_profile_tracker->FindMappingRow(
context_->storage->InternString(module_symbols.path()), build_id);
if (mapping_ids.empty()) {
context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
@@ -471,7 +484,7 @@
context_->args_translation_table->AddNativeSymbolTranslationRule(
mapping_id, address_symbols.address(), last_location);
std::vector<FrameId> frame_ids =
- context_->stack_profile_tracker->FindFrameIds(
+ context_->global_stack_profile_tracker->FindFrameIds(
mapping_id, address_symbols.address());
for (const FrameId frame_id : frame_ids) {
@@ -523,16 +536,21 @@
std::vector<tables::StackProfileFrameTable::Id> frames;
if (opt_package_name_id) {
- const std::vector<tables::StackProfileFrameTable::Id> pkg_frames =
- context_->stack_profile_tracker->JavaFramesForName(
+ const std::vector<tables::StackProfileFrameTable::Id>* pkg_frames =
+ context_->global_stack_profile_tracker->JavaFramesForName(
{*merged_obfuscated_id, *opt_package_name_id});
- frames.insert(frames.end(), pkg_frames.begin(), pkg_frames.end());
+ if (pkg_frames) {
+ frames.insert(frames.end(), pkg_frames->begin(), pkg_frames->end());
+ }
}
if (opt_memfd_id) {
- const std::vector<tables::StackProfileFrameTable::Id> memfd_frames =
- context_->stack_profile_tracker->JavaFramesForName(
+ const std::vector<tables::StackProfileFrameTable::Id>* memfd_frames =
+ context_->global_stack_profile_tracker->JavaFramesForName(
{*merged_obfuscated_id, *opt_memfd_id});
- frames.insert(frames.end(), memfd_frames.begin(), memfd_frames.end());
+ if (memfd_frames) {
+ frames.insert(frames.end(), memfd_frames->begin(),
+ memfd_frames->end());
+ }
}
for (tables::StackProfileFrameTable::Id frame_id : frames) {
diff --git a/src/trace_processor/importers/proto/profile_module.h b/src/trace_processor/importers/proto/profile_module.h
index 883fb7a..e6674d7 100644
--- a/src/trace_processor/importers/proto/profile_module.h
+++ b/src/trace_processor/importers/proto/profile_module.h
@@ -65,7 +65,8 @@
// heap profiling:
void ParseProfilePacket(int64_t ts,
- PacketSequenceState*,
+ PacketSequenceStateGeneration*,
+ uint32_t seq_id,
protozero::ConstBytes);
void ParseDeobfuscationMapping(int64_t ts,
PacketSequenceStateGeneration*,
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
deleted file mode 100644
index 71a4b13..0000000
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
+++ /dev/null
@@ -1,281 +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.
- */
-
-#include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
-
-#include "perfetto/base/flat_set.h"
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include "src/trace_processor/importers/proto/profile_packet_utils.h"
-#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
-#include "src/trace_processor/storage/stats.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace {
-const char kArtHeapName[] = "com.android.art";
-}
-
-ProfilePacketSequenceState::ProfilePacketSequenceState(
- TraceProcessorContext* context)
- : context_(context) {}
-
-ProfilePacketSequenceState::~ProfilePacketSequenceState() = default;
-
-void ProfilePacketSequenceState::SetProfilePacketIndex(uint64_t index) {
- bool dropped_packet = false;
- // heapprofd starts counting at index = 0.
- if (!prev_index.has_value() && index != 0) {
- dropped_packet = true;
- }
-
- if (prev_index.has_value() && *prev_index + 1 != index) {
- dropped_packet = true;
- }
-
- if (dropped_packet) {
- context_->storage->IncrementStats(stats::heapprofd_missing_packet);
- }
- prev_index = index;
-}
-
-void ProfilePacketSequenceState::AddString(SourceStringId id,
- base::StringView str) {
- strings_.Insert(id, str.ToStdString());
-}
-
-void ProfilePacketSequenceState::AddMapping(SourceMappingId id,
- const SourceMapping& mapping) {
- StackProfileTracker::CreateMappingParams params;
- if (std::string* str = strings_.Find(mapping.build_id); str) {
- params.build_id = base::StringView(*str);
- } else {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- return;
- }
- params.exact_offset = mapping.exact_offset;
- params.start_offset = mapping.start_offset;
- params.start = mapping.start;
- params.end = mapping.end;
- params.load_bias = mapping.load_bias;
-
- std::vector<base::StringView> path_components;
- path_components.reserve(mapping.name_ids.size());
- for (SourceStringId string_id : mapping.name_ids) {
- if (std::string* str = strings_.Find(string_id); str) {
- path_components.push_back(base::StringView(*str));
- } else {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- return;
- }
- }
- std::string path = ProfilePacketUtils::MakeMappingName(path_components);
- params.name = base::StringView(path);
- MappingId mapping_id = context_->stack_profile_tracker->InternMapping(params);
- mappings_.Insert(id, mapping_id);
-}
-
-void ProfilePacketSequenceState::AddFrame(SourceFrameId id,
- const SourceFrame& frame) {
- MappingId* mapping_id = mappings_.Find(frame.mapping_id);
- if (!mapping_id) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
- return;
- }
-
- std::string* function_name = strings_.Find(frame.name_id);
- if (!function_name) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- return;
- }
-
- FrameId frame_id = context_->stack_profile_tracker->InternFrame(
- *mapping_id, frame.rel_pc, base::StringView(*function_name));
-
- frames_.Insert(id, frame_id);
-}
-
-void ProfilePacketSequenceState::AddCallstack(
- SourceCallstackId id,
- const SourceCallstack& callstack) {
- std::optional<CallsiteId> parent_callsite_id;
- uint32_t depth = 0;
- for (SourceFrameId source_frame_id : callstack) {
- FrameId* frame_id = frames_.Find(source_frame_id);
- if (!frame_id) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
- return;
- }
- parent_callsite_id = context_->stack_profile_tracker->InternCallsite(
- parent_callsite_id, *frame_id, depth);
- ++depth;
- }
-
- if (!parent_callsite_id) {
- context_->storage->IncrementStats(stats::stackprofile_empty_callstack);
- return;
- }
-
- callstacks_.Insert(id, *parent_callsite_id);
-}
-
-void ProfilePacketSequenceState::StoreAllocation(
- const SourceAllocation& alloc) {
- pending_allocs_.push_back(std::move(alloc));
-}
-
-void ProfilePacketSequenceState::CommitAllocations() {
- for (const SourceAllocation& alloc : pending_allocs_)
- AddAllocation(alloc);
- pending_allocs_.clear();
-}
-
-void ProfilePacketSequenceState::FinalizeProfile() {
- CommitAllocations();
- strings_.Clear();
- mappings_.Clear();
- frames_.Clear();
- callstacks_.Clear();
-}
-
-FrameId ProfilePacketSequenceState::GetDatabaseFrameIdForTesting(
- SourceFrameId source_frame_id) {
- FrameId* frame_id = frames_.Find(source_frame_id);
- if (!frame_id) {
- PERFETTO_DLOG("Invalid frame.");
- return {};
- }
- return *frame_id;
-}
-
-void ProfilePacketSequenceState::AddAllocation(const SourceAllocation& alloc) {
- auto opt_callstack_id = FindOrInsertCallstack(alloc.callstack_id);
- if (!opt_callstack_id)
- return;
-
- CallsiteId callstack_id = *opt_callstack_id;
-
- UniquePid upid = context_->process_tracker->GetOrCreateProcess(
- static_cast<uint32_t>(alloc.pid));
-
- tables::HeapProfileAllocationTable::Row alloc_row{
- alloc.timestamp,
- upid,
- alloc.heap_name,
- callstack_id,
- static_cast<int64_t>(alloc.alloc_count),
- static_cast<int64_t>(alloc.self_allocated)};
-
- tables::HeapProfileAllocationTable::Row free_row{
- alloc.timestamp,
- upid,
- alloc.heap_name,
- callstack_id,
- -static_cast<int64_t>(alloc.free_count),
- -static_cast<int64_t>(alloc.self_freed)};
-
- auto* prev_alloc = prev_alloc_.Find({upid, callstack_id});
- if (!prev_alloc) {
- prev_alloc = prev_alloc_
- .Insert(std::make_pair(upid, callstack_id),
- tables::HeapProfileAllocationTable::Row{})
- .first;
- }
-
- auto* prev_free = prev_free_.Find({upid, callstack_id});
- if (!prev_free) {
- prev_free = prev_free_
- .Insert(std::make_pair(upid, callstack_id),
- tables::HeapProfileAllocationTable::Row{})
- .first;
- }
-
- base::FlatSet<CallsiteId>& callstacks_for_source_callstack_id =
- seen_callstacks_[SourceAllocationIndex{upid, alloc.callstack_id,
- alloc.heap_name}];
- bool new_callstack;
- std::tie(std::ignore, new_callstack) =
- callstacks_for_source_callstack_id.insert(callstack_id);
-
- if (new_callstack) {
- alloc_correction_[alloc.callstack_id] = *prev_alloc;
- free_correction_[alloc.callstack_id] = *prev_free;
- }
-
- const auto* alloc_correction = alloc_correction_.Find(alloc.callstack_id);
- if (alloc_correction) {
- alloc_row.count += alloc_correction->count;
- alloc_row.size += alloc_correction->size;
- }
-
- const auto* free_correction = free_correction_.Find(alloc.callstack_id);
- if (free_correction) {
- free_row.count += free_correction->count;
- free_row.size += free_correction->size;
- }
-
- tables::HeapProfileAllocationTable::Row alloc_delta = alloc_row;
- tables::HeapProfileAllocationTable::Row free_delta = free_row;
-
- alloc_delta.count -= prev_alloc->count;
- alloc_delta.size -= prev_alloc->size;
-
- free_delta.count -= prev_free->count;
- free_delta.size -= prev_free->size;
-
- if (alloc_delta.count < 0 || alloc_delta.size < 0 || free_delta.count > 0 ||
- free_delta.size > 0) {
- PERFETTO_DLOG("Non-monotonous allocation.");
- context_->storage->IncrementIndexedStats(stats::heapprofd_malformed_packet,
- static_cast<int>(upid));
- return;
- }
-
- // Dump at max profiles do not have .count set.
- if (alloc_delta.count || alloc_delta.size) {
- context_->storage->mutable_heap_profile_allocation_table()->Insert(
- alloc_delta);
- }
-
- // ART only reports allocations, and not frees. This throws off our logic
- // that assumes that if a new object was allocated with the same address,
- // the old one has to have been freed in the meantime.
- // See HeapTracker::RecordMalloc in bookkeeping.cc.
- if (context_->storage->GetString(alloc.heap_name) != kArtHeapName &&
- (free_delta.count || free_delta.size)) {
- context_->storage->mutable_heap_profile_allocation_table()->Insert(
- free_delta);
- }
-
- *prev_alloc = alloc_row;
- *prev_free = free_row;
-}
-
-std::optional<CallsiteId> ProfilePacketSequenceState::FindOrInsertCallstack(
- uint64_t iid) {
- if (CallsiteId* id = callstacks_.Find(iid); id) {
- return *id;
- }
- return GetOrCreate<StackProfileSequenceState>()->FindOrInsertCallstack(iid);
-}
-
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.h b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
deleted file mode 100644
index 678aab2..0000000
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.h
+++ /dev/null
@@ -1,175 +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_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_
-
-#include <cstdint>
-#include "perfetto/base/flat_set.h"
-#include "perfetto/ext/base/flat_hash_map.h"
-
-#include "perfetto/ext/base/hash.h"
-#include "perfetto/ext/base/string_view.h"
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
-#include "src/trace_processor/storage/trace_storage.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// Keeps sequence specific state for profile packets.
-class ProfilePacketSequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
- public:
- using SourceStringId = uint64_t;
-
- struct SourceMapping {
- SourceStringId build_id = 0;
- uint64_t exact_offset = 0;
- uint64_t start_offset = 0;
- uint64_t start = 0;
- uint64_t end = 0;
- uint64_t load_bias = 0;
- std::vector<SourceStringId> name_ids;
- };
- using SourceMappingId = uint64_t;
-
- struct SourceFrame {
- SourceStringId name_id = 0;
- SourceMappingId mapping_id = 0;
- uint64_t rel_pc = 0;
- };
- using SourceFrameId = uint64_t;
-
- using SourceCallstack = std::vector<SourceFrameId>;
- using SourceCallstackId = uint64_t;
- struct SourceAllocation {
- uint64_t pid = 0;
- // This is int64_t, because we get this from the TraceSorter which also
- // converts this for us.
- int64_t timestamp = 0;
- StringId heap_name;
- uint64_t callstack_id = 0;
- uint64_t self_allocated = 0;
- uint64_t self_freed = 0;
- uint64_t alloc_count = 0;
- uint64_t free_count = 0;
- };
-
- explicit ProfilePacketSequenceState(TraceProcessorContext* context);
- virtual ~ProfilePacketSequenceState() override;
-
- // Profile packets keep track of a index to detect packet loss. Call this
- // method to update this index with the latest seen value.
- void SetProfilePacketIndex(uint64_t index);
-
- // In Android version Q we did not intern Mappings, Frames nor Callstacks,
- // instead the profile packed "interned these". The following methods are used
- // to support this old use case. They add the given object to a sequence local
- // index for them to be retrieved later (see Find* Lookup* methods).
- void AddString(SourceStringId id, base::StringView str);
- void AddMapping(SourceMappingId id, const SourceMapping& mapping);
- void AddFrame(SourceFrameId id, const SourceFrame& frame);
- void AddCallstack(SourceCallstackId id, const SourceCallstack& callstack);
-
- void StoreAllocation(const SourceAllocation& allocation);
- void FinalizeProfile();
- void CommitAllocations();
-
- FrameId GetDatabaseFrameIdForTesting(SourceFrameId);
-
- private:
- struct SourceAllocationIndex {
- UniquePid upid;
- SourceCallstackId src_callstack_id;
- StringPool::Id heap_name;
- bool operator==(const SourceAllocationIndex& o) const {
- return std::tie(upid, src_callstack_id, heap_name) ==
- std::tie(o.upid, o.src_callstack_id, o.heap_name);
- }
- struct Hasher {
- size_t operator()(const SourceAllocationIndex& o) const {
- return static_cast<size_t>(base::Hasher::Combine(
- o.upid, o.src_callstack_id, o.heap_name.raw_id()));
- }
- };
- };
-
- void AddAllocation(const SourceAllocation& alloc);
-
- // The following methods deal with interned data. In Android version Q we did
- // not intern Mappings, Frames nor Callstacks, instead the profile packed
- // "interned these" and this class keeps those ina sequence local index. In
- // newer versions, these objects are in InternedData (see
- // protos/perfetto/trace/interned_data) and are shared across multiple
- // ProfilePackets. For backwards compatibility, the following methods first
- // look up interned data in the private sequence local index (for values added
- // via the Add* methods), and then, if this lookup fails, in the InternedData
- // instead.
- std::optional<MappingId> FindOrInsertMapping(uint64_t iid);
- std::optional<CallsiteId> FindOrInsertCallstack(uint64_t iid);
-
- TraceProcessorContext* const context_;
-
- base::FlatHashMap<SourceStringId, std::string> strings_;
- base::FlatHashMap<SourceMappingId, MappingId> mappings_;
- base::FlatHashMap<SourceFrameId, FrameId> frames_;
- base::FlatHashMap<SourceCallstackId, CallsiteId> callstacks_;
-
- std::vector<SourceAllocation> pending_allocs_;
-
- struct Hasher {
- size_t operator()(const std::pair<UniquePid, CallsiteId>& p) const {
- return static_cast<size_t>(
- base::Hasher::Combine(p.first, p.second.value));
- }
- };
- base::FlatHashMap<std::pair<UniquePid, CallsiteId>,
- tables::HeapProfileAllocationTable::Row,
- Hasher>
- prev_alloc_;
- base::FlatHashMap<std::pair<UniquePid, CallsiteId>,
- tables::HeapProfileAllocationTable::Row,
- Hasher>
- prev_free_;
-
- // For continuous dumps, we only store the delta in the data-base. To do
- // this, we subtract the previous dump's value. Sometimes, we should not
- // do that subtraction, because heapprofd garbage collects stacks that
- // have no unfreed allocations. If the application then allocations again
- // at that stack, it gets recreated and initialized to zero.
- //
- // To correct for this, we add the previous' stacks value to the current
- // one, and then handle it as normal. If it is the first time we see a
- // SourceCallstackId for a CallsiteId, we put the previous value into
- // the correction maps below.
- base::FlatHashMap<SourceAllocationIndex,
- base::FlatSet<CallsiteId>,
- SourceAllocationIndex::Hasher>
- seen_callstacks_;
- base::FlatHashMap<SourceCallstackId, tables::HeapProfileAllocationTable::Row>
- alloc_correction_;
- base::FlatHashMap<SourceCallstackId, tables::HeapProfileAllocationTable::Row>
- free_correction_;
-
- std::optional<uint64_t> prev_index;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/profile_packet_utils.cc b/src/trace_processor/importers/proto/profile_packet_utils.cc
index 3cc5dc1..9478db9 100644
--- a/src/trace_processor/importers/proto/profile_packet_utils.cc
+++ b/src/trace_processor/importers/proto/profile_packet_utils.cc
@@ -15,27 +15,11 @@
*/
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
-#include "perfetto/ext/base/string_utils.h"
namespace perfetto {
namespace trace_processor {
-// static
-std::string ProfilePacketUtils::MakeMappingName(
- const std::vector<base::StringView>& path_components) {
- std::string name;
- for (base::StringView p : path_components) {
- name.push_back('/');
- name.append(p.data(), p.size());
- }
-
- // When path strings just have single full path(like Chrome does), the mapping
- // path gets an extra '/' prepended, strip the extra '/'.
- if (base::StartsWith(name, "//")) {
- name = name.substr(1);
- }
- return name;
-}
+ProfilePacketInternLookup::~ProfilePacketInternLookup() = default;
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_packet_utils.h b/src/trace_processor/importers/proto/profile_packet_utils.h
index a9ea0e6..64b2c50 100644
--- a/src/trace_processor/importers/proto/profile_packet_utils.h
+++ b/src/trace_processor/importers/proto/profile_packet_utils.h
@@ -20,7 +20,7 @@
#include "perfetto/ext/base/string_view.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
@@ -31,12 +31,9 @@
class ProfilePacketUtils {
public:
- static std::string MakeMappingName(
- const std::vector<base::StringView>& path_components);
-
- static ProfilePacketSequenceState::SourceMapping MakeSourceMapping(
+ static SequenceStackProfileTracker::SourceMapping MakeSourceMapping(
const protos::pbzero::Mapping::Decoder& entry) {
- ProfilePacketSequenceState::SourceMapping src_mapping{};
+ SequenceStackProfileTracker::SourceMapping src_mapping{};
src_mapping.build_id = entry.build_id();
src_mapping.exact_offset = entry.exact_offset();
src_mapping.start_offset = entry.start_offset();
@@ -50,18 +47,18 @@
return src_mapping;
}
- static ProfilePacketSequenceState::SourceFrame MakeSourceFrame(
+ static SequenceStackProfileTracker::SourceFrame MakeSourceFrame(
const protos::pbzero::Frame::Decoder& entry) {
- ProfilePacketSequenceState::SourceFrame src_frame;
+ SequenceStackProfileTracker::SourceFrame src_frame;
src_frame.name_id = entry.function_name_id();
src_frame.mapping_id = entry.mapping_id();
src_frame.rel_pc = entry.rel_pc();
return src_frame;
}
- static ProfilePacketSequenceState::SourceCallstack MakeSourceCallstack(
+ static SequenceStackProfileTracker::SourceCallstack MakeSourceCallstack(
const protos::pbzero::Callstack::Decoder& entry) {
- ProfilePacketSequenceState::SourceCallstack src_callstack;
+ SequenceStackProfileTracker::SourceCallstack src_callstack;
for (auto frame_it = entry.frame_ids(); frame_it; ++frame_it)
src_callstack.emplace_back(*frame_it);
return src_callstack;
@@ -129,6 +126,76 @@
}
};
+class ProfilePacketInternLookup
+ : public SequenceStackProfileTracker::InternLookup {
+ public:
+ explicit ProfilePacketInternLookup(PacketSequenceStateGeneration* seq_state)
+ : seq_state_(seq_state) {}
+ ~ProfilePacketInternLookup() override;
+
+ std::optional<base::StringView> GetString(
+ SequenceStackProfileTracker::SourceStringId iid,
+ SequenceStackProfileTracker::InternedStringType type) const override {
+ protos::pbzero::InternedString::Decoder* decoder = nullptr;
+ switch (type) {
+ case SequenceStackProfileTracker::InternedStringType::kBuildId:
+ decoder = seq_state_->LookupInternedMessage<
+ protos::pbzero::InternedData::kBuildIdsFieldNumber,
+ protos::pbzero::InternedString>(iid);
+ break;
+ case SequenceStackProfileTracker::InternedStringType::kFunctionName:
+ decoder = seq_state_->LookupInternedMessage<
+ protos::pbzero::InternedData::kFunctionNamesFieldNumber,
+ protos::pbzero::InternedString>(iid);
+ break;
+ case SequenceStackProfileTracker::InternedStringType::kMappingPath:
+ decoder = seq_state_->LookupInternedMessage<
+ protos::pbzero::InternedData::kMappingPathsFieldNumber,
+ protos::pbzero::InternedString>(iid);
+ break;
+ }
+ if (!decoder)
+ return std::nullopt;
+ return base::StringView(reinterpret_cast<const char*>(decoder->str().data),
+ decoder->str().size);
+ }
+
+ std::optional<SequenceStackProfileTracker::SourceMapping> GetMapping(
+ SequenceStackProfileTracker::SourceMappingId iid) const override {
+ auto* decoder = seq_state_->LookupInternedMessage<
+ protos::pbzero::InternedData::kMappingsFieldNumber,
+ protos::pbzero::Mapping>(iid);
+ if (!decoder)
+ return std::nullopt;
+ return ProfilePacketUtils::MakeSourceMapping(*decoder);
+ }
+
+ std::optional<SequenceStackProfileTracker::SourceFrame> GetFrame(
+ SequenceStackProfileTracker::SourceFrameId iid) const override {
+ auto* decoder = seq_state_->LookupInternedMessage<
+ protos::pbzero::InternedData::kFramesFieldNumber,
+ protos::pbzero::Frame>(iid);
+ if (!decoder)
+ return std::nullopt;
+ return ProfilePacketUtils::MakeSourceFrame(*decoder);
+ }
+
+ std::optional<SequenceStackProfileTracker::SourceCallstack> GetCallstack(
+ SequenceStackProfileTracker::SourceCallstackId iid) const override {
+ auto* interned_message_view = seq_state_->GetInternedMessageView(
+ protos::pbzero::InternedData::kCallstacksFieldNumber, iid);
+ if (!interned_message_view)
+ return std::nullopt;
+ protos::pbzero::Callstack::Decoder decoder(
+ interned_message_view->message().data(),
+ interned_message_view->message().length());
+ return ProfilePacketUtils::MakeSourceCallstack(std::move(decoder));
+ }
+
+ private:
+ PacketSequenceStateGeneration* seq_state_;
+};
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/util/profiler_util.cc b/src/trace_processor/importers/proto/profiler_util.cc
similarity index 98%
rename from src/trace_processor/util/profiler_util.cc
rename to src/trace_processor/importers/proto/profiler_util.cc
index 71c3c25..79a5448 100644
--- a/src/trace_processor/util/profiler_util.cc
+++ b/src/trace_processor/importers/proto/profiler_util.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/trace_processor/util/profiler_util.h"
+#include "src/trace_processor/importers/proto/profiler_util.h"
#include <optional>
#include "perfetto/ext/base/string_utils.h"
diff --git a/src/trace_processor/util/profiler_util.h b/src/trace_processor/importers/proto/profiler_util.h
similarity index 86%
rename from src/trace_processor/util/profiler_util.h
rename to src/trace_processor/importers/proto/profiler_util.h
index 3af3606..cbf8ad1 100644
--- a/src/trace_processor/util/profiler_util.h
+++ b/src/trace_processor/importers/proto/profiler_util.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef SRC_TRACE_PROCESSOR_UTIL_PROFILER_UTIL_H_
-#define SRC_TRACE_PROCESSOR_UTIL_PROFILER_UTIL_H_
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILER_UTIL_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILER_UTIL_H_
#include <optional>
#include <string>
@@ -38,4 +38,4 @@
} // namespace trace_processor
} // namespace perfetto
-#endif // SRC_TRACE_PROCESSOR_UTIL_PROFILER_UTIL_H_
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILER_UTIL_H_
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 148bf60..af96d34 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -28,12 +28,12 @@
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/importers/proto/additional_modules.h"
#include "src/trace_processor/importers/proto/default_modules.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/metadata.h"
#include "src/trace_processor/storage/trace_storage.h"
@@ -55,7 +55,6 @@
#include "protos/perfetto/trace/ftrace/sched.pbzero.h"
#include "protos/perfetto/trace/ftrace/task.pbzero.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
#include "protos/perfetto/trace/ps/process_tree.pbzero.h"
#include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
@@ -252,7 +251,8 @@
context_.track_tracker.reset(new TrackTracker(&context_));
context_.global_args_tracker.reset(
new GlobalArgsTracker(context_.storage.get()));
- context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
+ context_.global_stack_profile_tracker.reset(
+ new GlobalStackProfileTracker());
context_.args_tracker.reset(new ArgsTracker(&context_));
context_.args_translation_table.reset(new ArgsTranslationTable(storage_));
context_.metadata_tracker.reset(
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index 8afc40c..1c554a6 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -24,7 +24,6 @@
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
-#include "src/trace_processor/storage/trace_storage.h"
namespace protozero {
struct ConstBytes;
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.cc b/src/trace_processor/importers/proto/stack_profile_sequence_state.cc
deleted file mode 100644
index 693a1ed..0000000
--- a/src/trace_processor/importers/proto/stack_profile_sequence_state.cc
+++ /dev/null
@@ -1,209 +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.
- */
-
-#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
-
-#include <optional>
-#include <vector>
-
-#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/string_view.h"
-#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include "src/trace_processor/importers/proto/profile_packet_utils.h"
-#include "src/trace_processor/storage/stats.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace {
-base::StringView ToStringView(protozero::ConstBytes bytes) {
- return base::StringView(reinterpret_cast<const char*>(bytes.data),
- bytes.size);
-}
-} // namespace
-
-StackProfileSequenceState::StackProfileSequenceState(
- TraceProcessorContext* context)
- : context_(context) {}
-
-StackProfileSequenceState::~StackProfileSequenceState() = default;
-
-std::optional<MappingId> StackProfileSequenceState::FindOrInsertMapping(
- uint64_t iid) {
- if (MappingId* id = cached_mappings_.Find(iid); id) {
- return *id;
- }
- auto* decoder =
- LookupInternedMessage<protos::pbzero::InternedData::kMappingsFieldNumber,
- protos::pbzero::Mapping>(iid);
- if (!decoder) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
- return std::nullopt;
- }
-
- base::StringView build_id;
- if (decoder->has_build_id()) {
- std::optional<base::StringView> maybe_build_id =
- LookupInternedBuildId(decoder->build_id());
- if (!maybe_build_id) {
- return std::nullopt;
- }
- build_id = *maybe_build_id;
- }
-
- std::vector<base::StringView> path_components;
- for (auto it = decoder->path_string_ids(); it; ++it) {
- std::optional<base::StringView> str = LookupInternedMappingPath(*it);
- if (!str) {
- return std::nullopt;
- }
- path_components.push_back(*str);
- }
- std::string path = ProfilePacketUtils::MakeMappingName(path_components);
-
- StackProfileTracker::CreateMappingParams params;
- params.build_id = build_id;
- params.exact_offset = decoder->exact_offset();
- params.start_offset = decoder->start_offset();
- params.start = decoder->start();
- params.end = decoder->end();
- params.load_bias = decoder->load_bias();
- params.name = base::StringView(path);
- MappingId mapping_id = context_->stack_profile_tracker->InternMapping(params);
- cached_mappings_.Insert(iid, mapping_id);
- return mapping_id;
-}
-
-std::optional<base::StringView>
-StackProfileSequenceState::LookupInternedBuildId(uint64_t iid) {
- auto* decoder =
- LookupInternedMessage<protos::pbzero::InternedData::kBuildIdsFieldNumber,
- protos::pbzero::InternedString>(iid);
- if (!decoder) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- return std::nullopt;
- }
-
- return ToStringView(decoder->str());
-}
-
-std::optional<base::StringView>
-StackProfileSequenceState::LookupInternedMappingPath(uint64_t iid) {
- auto* decoder =
-
- LookupInternedMessage<
- protos::pbzero::InternedData::kMappingPathsFieldNumber,
- protos::pbzero::InternedString>(iid);
- if (!decoder) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- return std::nullopt;
- }
-
- return ToStringView(decoder->str());
-}
-
-std::optional<CallsiteId> StackProfileSequenceState::FindOrInsertCallstack(
- uint64_t iid) {
- if (CallsiteId* id = cached_callstacks_.Find(iid); id) {
- return *id;
- }
- auto* decoder = LookupInternedMessage<
- protos::pbzero::InternedData::kCallstacksFieldNumber,
- protos::pbzero::Callstack>(iid);
- if (!decoder) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
- return std::nullopt;
- }
-
- std::optional<CallsiteId> parent_callsite_id;
- uint32_t depth = 0;
- for (auto it = decoder->frame_ids(); it; ++it) {
- std::optional<FrameId> frame_id = FindOrInsertFrame(*it);
- if (!frame_id) {
- return std::nullopt;
- }
- parent_callsite_id = context_->stack_profile_tracker->InternCallsite(
- parent_callsite_id, *frame_id, depth);
- ++depth;
- }
-
- if (!parent_callsite_id) {
- context_->storage->IncrementStats(stats::stackprofile_empty_callstack);
- return std::nullopt;
- }
-
- cached_callstacks_.Insert(iid, *parent_callsite_id);
-
- return *parent_callsite_id;
-}
-
-std::optional<FrameId> StackProfileSequenceState::FindOrInsertFrame(
- uint64_t iid) {
- if (FrameId* id = cached_frames_.Find(iid); id) {
- return *id;
- }
- auto* decoder =
- LookupInternedMessage<protos::pbzero::InternedData::kFramesFieldNumber,
- protos::pbzero::Frame>(iid);
- if (!decoder) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
- return std::nullopt;
- }
-
- std::optional<MappingId> mapping_id =
- FindOrInsertMapping(decoder->mapping_id());
- if (!mapping_id) {
- return std::nullopt;
- }
-
- base::StringView function_name;
- if (decoder->function_name_id() != 0) {
- std::optional<base::StringView> func =
- LookupInternedFunctionName(decoder->function_name_id());
- if (!func) {
- return std::nullopt;
- }
- function_name = *func;
- }
-
- FrameId frame_id = context_->stack_profile_tracker->InternFrame(
- *mapping_id, decoder->rel_pc(), function_name);
-
- cached_frames_.Insert(iid, frame_id);
-
- return frame_id;
-}
-
-std::optional<base::StringView>
-StackProfileSequenceState::LookupInternedFunctionName(uint64_t iid) {
- auto* decoder = LookupInternedMessage<
- protos::pbzero::InternedData::kFunctionNamesFieldNumber,
- protos::pbzero::InternedString>(iid);
- if (!decoder) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- return std::nullopt;
- }
-
- return ToStringView(decoder->str());
-}
-
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.h b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
deleted file mode 100644
index 7a7879a..0000000
--- a/src/trace_processor/importers/proto/stack_profile_sequence_state.h
+++ /dev/null
@@ -1,61 +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_IMPORTERS_PROTO_STACK_PROFILE_SEQUENCE_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_SEQUENCE_STATE_H_
-
-#include <cstdint>
-#include <optional>
-
-#include "perfetto/ext/base/flat_hash_map.h"
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class TraceProcessorContext;
-
-class StackProfileSequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
- public:
- explicit StackProfileSequenceState(TraceProcessorContext* context);
-
- StackProfileSequenceState(const StackProfileSequenceState&);
-
- virtual ~StackProfileSequenceState() override;
-
- std::optional<MappingId> FindOrInsertMapping(uint64_t iid);
- std::optional<CallsiteId> FindOrInsertCallstack(uint64_t iid);
-
- private:
- std::optional<base::StringView> LookupInternedBuildId(uint64_t iid);
- std::optional<base::StringView> LookupInternedMappingPath(uint64_t iid);
- std::optional<base::StringView> LookupInternedFunctionName(uint64_t iid);
- std::optional<FrameId> FindOrInsertFrame(uint64_t iid);
-
- TraceProcessorContext* const context_;
- base::FlatHashMap<uint64_t, MappingId> cached_mappings_;
- base::FlatHashMap<uint64_t, CallsiteId> cached_callstacks_;
- base::FlatHashMap<uint64_t, FrameId> cached_frames_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/stack_profile_tracker.cc b/src/trace_processor/importers/proto/stack_profile_tracker.cc
new file mode 100644
index 0000000..d00f287
--- /dev/null
+++ b/src/trace_processor/importers/proto/stack_profile_tracker.cc
@@ -0,0 +1,368 @@
+/*
+ * 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.
+ */
+
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
+
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/importers/proto/profiler_util.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/stack_traces_util.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+SequenceStackProfileTracker::InternLookup::~InternLookup() = default;
+
+SequenceStackProfileTracker::SequenceStackProfileTracker(
+ TraceProcessorContext* context)
+ : context_(context), empty_(kNullStringId) {}
+
+SequenceStackProfileTracker::~SequenceStackProfileTracker() = default;
+
+StringId SequenceStackProfileTracker::GetEmptyStringId() {
+ if (empty_ == kNullStringId) {
+ empty_ = context_->storage->InternString({"", 0});
+ }
+
+ return empty_;
+}
+
+void SequenceStackProfileTracker::AddString(SourceStringId id,
+ base::StringView str) {
+ string_map_.emplace(id, str.ToStdString());
+}
+
+std::optional<MappingId> SequenceStackProfileTracker::AddMapping(
+ SourceMappingId id,
+ const SourceMapping& mapping,
+ const InternLookup* intern_lookup) {
+ std::string path;
+ for (SourceStringId str_id : mapping.name_ids) {
+ auto opt_str = FindOrInsertString(str_id, intern_lookup,
+ InternedStringType::kMappingPath);
+ if (!opt_str)
+ break;
+ path += "/" + *opt_str;
+ }
+ // When path strings just have single full path(like Chrome does), the mapping
+ // path gets an extra '/' prepended, strip the extra '/'.
+ if (base::StartsWith(path, "//")) {
+ path = path.substr(1);
+ }
+
+ auto opt_build_id = FindAndInternString(mapping.build_id, intern_lookup,
+ InternedStringType::kBuildId);
+ if (!opt_build_id) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ PERFETTO_DLOG("Invalid string.");
+ return std::nullopt;
+ }
+ const StringId raw_build_id = opt_build_id.value();
+ NullTermStringView raw_build_id_str =
+ context_->storage->GetString(raw_build_id);
+ StringId build_id = GetEmptyStringId();
+ if (!raw_build_id_str.empty()) {
+ // If the build_id is 33 characters long, we assume it's a Breakpad debug
+ // identifier which is already in Hex and doesn't need conversion.
+ // TODO(b/148109467): Remove workaround once all active Chrome versions
+ // write raw bytes instead of a string as build_id.
+ if (util::IsHexModuleId(raw_build_id_str)) {
+ build_id = raw_build_id;
+ } else {
+ std::string hex_build_id =
+ base::ToHex(raw_build_id_str.c_str(), raw_build_id_str.size());
+ build_id =
+ context_->storage->InternString(base::StringView(hex_build_id));
+ }
+ }
+
+ tables::StackProfileMappingTable::Row row{
+ build_id,
+ static_cast<int64_t>(mapping.exact_offset),
+ static_cast<int64_t>(mapping.start_offset),
+ static_cast<int64_t>(mapping.start),
+ static_cast<int64_t>(mapping.end),
+ static_cast<int64_t>(mapping.load_bias),
+ context_->storage->InternString(base::StringView(path))};
+
+ tables::StackProfileMappingTable* mappings =
+ context_->storage->mutable_stack_profile_mapping_table();
+ std::optional<MappingId> cur_id;
+ auto it = mapping_idx_.find(row);
+ if (it != mapping_idx_.end()) {
+ cur_id = it->second;
+ } else {
+ std::vector<MappingId> db_mappings =
+ context_->global_stack_profile_tracker->FindMappingRow(row.name,
+ row.build_id);
+ for (const MappingId preexisting_mapping : db_mappings) {
+ uint32_t preexisting_row = *mappings->id().IndexOf(preexisting_mapping);
+ tables::StackProfileMappingTable::Row preexisting_data{
+ mappings->build_id()[preexisting_row],
+ mappings->exact_offset()[preexisting_row],
+ mappings->start_offset()[preexisting_row],
+ mappings->start()[preexisting_row],
+ mappings->end()[preexisting_row],
+ mappings->load_bias()[preexisting_row],
+ mappings->name()[preexisting_row]};
+
+ if (row == preexisting_data) {
+ cur_id = preexisting_mapping;
+ }
+ }
+ if (!cur_id) {
+ MappingId mapping_id = mappings->Insert(row).id;
+ context_->global_stack_profile_tracker->InsertMappingId(
+ row.name, row.build_id, mapping_id);
+ cur_id = mapping_id;
+ }
+ mapping_idx_.emplace(row, *cur_id);
+ }
+ mapping_ids_.emplace(id, *cur_id);
+ return cur_id;
+}
+
+std::optional<FrameId> SequenceStackProfileTracker::AddFrame(
+ SourceFrameId id,
+ const SourceFrame& frame,
+ const InternLookup* intern_lookup) {
+ std::optional<std::string> opt_name = FindOrInsertString(
+ frame.name_id, intern_lookup, InternedStringType::kFunctionName);
+ if (!opt_name) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ PERFETTO_DLOG("Invalid string.");
+ return std::nullopt;
+ }
+ const std::string& name = *opt_name;
+ const StringId str_id =
+ context_->storage->InternString(base::StringView(name));
+
+ auto opt_mapping = FindOrInsertMapping(frame.mapping_id, intern_lookup);
+ if (!opt_mapping) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
+ return std::nullopt;
+ }
+ MappingId mapping_id = *opt_mapping;
+ const auto& mappings = context_->storage->stack_profile_mapping_table();
+ StringId mapping_name_id =
+ mappings.name()[*mappings.id().IndexOf(mapping_id)];
+ auto mapping_name = context_->storage->GetString(mapping_name_id);
+
+ tables::StackProfileFrameTable::Row row{str_id, mapping_id,
+ static_cast<int64_t>(frame.rel_pc)};
+
+ auto* frames = context_->storage->mutable_stack_profile_frame_table();
+
+ std::optional<FrameId> cur_id;
+ auto it = frame_idx_.find(row);
+ if (it != frame_idx_.end()) {
+ cur_id = it->second;
+ } else {
+ std::vector<FrameId> db_frames =
+ context_->global_stack_profile_tracker->FindFrameIds(mapping_id,
+ frame.rel_pc);
+ for (const FrameId preexisting_frame : db_frames) {
+ uint32_t preexisting_row_id = *frames->id().IndexOf(preexisting_frame);
+ tables::StackProfileFrameTable::Row preexisting_row{
+ frames->name()[preexisting_row_id],
+ frames->mapping()[preexisting_row_id],
+ frames->rel_pc()[preexisting_row_id]};
+
+ if (row == preexisting_row) {
+ cur_id = preexisting_frame;
+ }
+ }
+ if (!cur_id) {
+ cur_id = frames->Insert(row).id;
+ context_->global_stack_profile_tracker->InsertFrameRow(
+ mapping_id, static_cast<uint64_t>(row.rel_pc), *cur_id);
+ if (base::Contains(name, '.')) {
+ // Java frames always contain a '.'
+ std::optional<std::string> package =
+ PackageFromLocation(context_->storage.get(), mapping_name);
+ if (package) {
+ NameInPackage nip{str_id, context_->storage->InternString(
+ base::StringView(*package))};
+ context_->global_stack_profile_tracker->InsertJavaFrameForName(
+ nip, *cur_id);
+ } else if (mapping_name.find("/memfd:") == 0) {
+ NameInPackage nip{str_id, context_->storage->InternString("memfd")};
+ context_->global_stack_profile_tracker->InsertJavaFrameForName(
+ nip, *cur_id);
+ }
+ }
+ }
+ frame_idx_.emplace(row, *cur_id);
+ }
+ frame_ids_.emplace(id, *cur_id);
+ return cur_id;
+}
+
+std::optional<CallsiteId> SequenceStackProfileTracker::AddCallstack(
+ SourceCallstackId id,
+ const SourceCallstack& frame_ids,
+ const InternLookup* intern_lookup) {
+ if (frame_ids.empty())
+ return std::nullopt;
+
+ std::optional<CallsiteId> parent_id;
+ for (uint32_t depth = 0; depth < frame_ids.size(); ++depth) {
+ auto opt_frame_id = FindOrInsertFrame(frame_ids[depth], intern_lookup);
+ if (!opt_frame_id) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
+ return std::nullopt;
+ }
+ FrameId frame_id = *opt_frame_id;
+
+ tables::StackProfileCallsiteTable::Row row{depth, parent_id, frame_id};
+ CallsiteId self_id;
+ auto callsite_it = callsite_idx_.find(row);
+ if (callsite_it != callsite_idx_.end()) {
+ self_id = callsite_it->second;
+ } else {
+ auto* callsite =
+ context_->storage->mutable_stack_profile_callsite_table();
+ self_id = callsite->Insert(row).id;
+ callsite_idx_.emplace(row, self_id);
+ }
+ parent_id = self_id;
+ }
+ PERFETTO_DCHECK(parent_id); // The loop ran at least once.
+ callstack_ids_.emplace(id, *parent_id);
+ return parent_id;
+}
+
+FrameId SequenceStackProfileTracker::GetDatabaseFrameIdForTesting(
+ SourceFrameId frame_id) {
+ auto it = frame_ids_.find(frame_id);
+ if (it == frame_ids_.end()) {
+ PERFETTO_DLOG("Invalid frame.");
+ return {};
+ }
+ return it->second;
+}
+
+std::optional<StringId> SequenceStackProfileTracker::FindAndInternString(
+ SourceStringId id,
+ const InternLookup* intern_lookup,
+ SequenceStackProfileTracker::InternedStringType type) {
+ if (id == 0)
+ return GetEmptyStringId();
+
+ auto opt_str = FindOrInsertString(id, intern_lookup, type);
+ if (!opt_str)
+ return GetEmptyStringId();
+
+ return context_->storage->InternString(base::StringView(*opt_str));
+}
+
+std::optional<std::string> SequenceStackProfileTracker::FindOrInsertString(
+ SourceStringId id,
+ const InternLookup* intern_lookup,
+ SequenceStackProfileTracker::InternedStringType type) {
+ if (id == 0)
+ return "";
+
+ auto it = string_map_.find(id);
+ if (it == string_map_.end()) {
+ if (intern_lookup) {
+ auto str = intern_lookup->GetString(id, type);
+ if (!str) {
+ context_->storage->IncrementStats(
+ stats::stackprofile_invalid_string_id);
+ PERFETTO_DLOG("Invalid string.");
+ return std::nullopt;
+ }
+ return str->ToStdString();
+ }
+ return std::nullopt;
+ }
+
+ return it->second;
+}
+
+std::optional<MappingId> SequenceStackProfileTracker::FindOrInsertMapping(
+ SourceMappingId mapping_id,
+ const InternLookup* intern_lookup) {
+ std::optional<MappingId> res;
+ auto it = mapping_ids_.find(mapping_id);
+ if (it == mapping_ids_.end()) {
+ if (intern_lookup) {
+ auto interned_mapping = intern_lookup->GetMapping(mapping_id);
+ if (interned_mapping) {
+ res = AddMapping(mapping_id, *interned_mapping, intern_lookup);
+ return res;
+ }
+ }
+ context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
+ return res;
+ }
+ res = it->second;
+ return res;
+}
+
+std::optional<FrameId> SequenceStackProfileTracker::FindOrInsertFrame(
+ SourceFrameId frame_id,
+ const InternLookup* intern_lookup) {
+ std::optional<FrameId> res;
+ auto it = frame_ids_.find(frame_id);
+ if (it == frame_ids_.end()) {
+ if (intern_lookup) {
+ auto interned_frame = intern_lookup->GetFrame(frame_id);
+ if (interned_frame) {
+ res = AddFrame(frame_id, *interned_frame, intern_lookup);
+ return res;
+ }
+ }
+ context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
+ PERFETTO_DLOG("Unknown frame %" PRIu64 " : %zu", frame_id,
+ frame_ids_.size());
+ return res;
+ }
+ res = it->second;
+ return res;
+}
+
+std::optional<CallsiteId> SequenceStackProfileTracker::FindOrInsertCallstack(
+ SourceCallstackId callstack_id,
+ const InternLookup* intern_lookup) {
+ std::optional<CallsiteId> res;
+ auto it = callstack_ids_.find(callstack_id);
+ if (it == callstack_ids_.end()) {
+ auto interned_callstack = intern_lookup->GetCallstack(callstack_id);
+ if (interned_callstack) {
+ res = AddCallstack(callstack_id, *interned_callstack, intern_lookup);
+ return res;
+ }
+ context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
+ PERFETTO_DLOG("Unknown callstack %" PRIu64 " : %zu", callstack_id,
+ callstack_ids_.size());
+ return res;
+ }
+ res = it->second;
+ return res;
+}
+
+void SequenceStackProfileTracker::ClearIndices() {
+ string_map_.clear();
+ mapping_ids_.clear();
+ callstack_ids_.clear();
+ frame_ids_.clear();
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/stack_profile_tracker.h b/src/trace_processor/importers/proto/stack_profile_tracker.h
new file mode 100644
index 0000000..a29d3c1
--- /dev/null
+++ b/src/trace_processor/importers/proto/stack_profile_tracker.h
@@ -0,0 +1,289 @@
+/*
+ * 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_IMPORTERS_PROTO_STACK_PROFILE_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_TRACKER_H_
+
+#include <deque>
+#include <optional>
+#include <unordered_map>
+
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/tables/profiler_tables_py.h"
+
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
+
+template <>
+struct std::hash<std::pair<uint32_t, int64_t>> {
+ using argument_type = std::pair<uint32_t, int64_t>;
+ using result_type = size_t;
+
+ result_type operator()(const argument_type& p) const {
+ return std::hash<uint32_t>{}(p.first) ^ std::hash<int64_t>{}(p.second);
+ }
+};
+
+template <>
+struct std::hash<std::pair<uint32_t, perfetto::trace_processor::CallsiteId>> {
+ using argument_type =
+ std::pair<uint32_t, perfetto::trace_processor::CallsiteId>;
+ using result_type = size_t;
+
+ result_type operator()(const argument_type& p) const {
+ return std::hash<uint32_t>{}(p.first) ^
+ std::hash<uint32_t>{}(p.second.value);
+ }
+};
+
+template <>
+struct std::hash<std::pair<uint32_t, perfetto::trace_processor::MappingId>> {
+ using argument_type =
+ std::pair<uint32_t, perfetto::trace_processor::MappingId>;
+ using result_type = size_t;
+
+ result_type operator()(const argument_type& p) const {
+ return std::hash<uint32_t>{}(p.first) ^
+ std::hash<uint32_t>{}(p.second.value);
+ }
+};
+
+template <>
+struct std::hash<std::pair<uint32_t, perfetto::trace_processor::FrameId>> {
+ using argument_type = std::pair<uint32_t, perfetto::trace_processor::FrameId>;
+ using result_type = size_t;
+
+ result_type operator()(const argument_type& p) const {
+ return std::hash<uint32_t>{}(p.first) ^
+ std::hash<uint32_t>{}(p.second.value);
+ }
+};
+
+template <>
+struct std::hash<std::vector<uint64_t>> {
+ using argument_type = std::vector<uint64_t>;
+ using result_type = size_t;
+
+ result_type operator()(const argument_type& p) const {
+ size_t h = 0u;
+ for (auto v : p)
+ h = h ^ std::hash<uint64_t>{}(v);
+ return h;
+ }
+};
+
+namespace perfetto {
+namespace trace_processor {
+
+struct NameInPackage {
+ StringId name;
+ StringId package;
+
+ bool operator<(const NameInPackage& b) const {
+ return std::tie(name, package) < std::tie(b.name, b.package);
+ }
+};
+
+class TraceProcessorContext;
+
+class GlobalStackProfileTracker {
+ public:
+ std::vector<MappingId> FindMappingRow(StringId name,
+ StringId build_id) const {
+ auto it = stack_profile_mapping_index_.find(std::make_pair(name, build_id));
+ if (it == stack_profile_mapping_index_.end())
+ return {};
+ return it->second;
+ }
+
+ void InsertMappingId(StringId name, StringId build_id, MappingId row) {
+ auto pair = std::make_pair(name, build_id);
+ stack_profile_mapping_index_[pair].emplace_back(row);
+ }
+
+ std::vector<FrameId> FindFrameIds(MappingId mapping_row,
+ uint64_t rel_pc) const {
+ auto it =
+ stack_profile_frame_index_.find(std::make_pair(mapping_row, rel_pc));
+ if (it == stack_profile_frame_index_.end())
+ return {};
+ return it->second;
+ }
+
+ void InsertFrameRow(MappingId mapping_row, uint64_t rel_pc, FrameId row) {
+ auto pair = std::make_pair(mapping_row, rel_pc);
+ stack_profile_frame_index_[pair].emplace_back(row);
+ }
+
+ const std::vector<tables::StackProfileFrameTable::Id>* JavaFramesForName(
+ NameInPackage name) {
+ auto it = java_frames_for_name_.find(name);
+ if (it == java_frames_for_name_.end())
+ return nullptr;
+ return &it->second;
+ }
+
+ void InsertJavaFrameForName(NameInPackage name,
+ tables::StackProfileFrameTable::Id id) {
+ java_frames_for_name_[name].push_back(id);
+ }
+
+ private:
+ using MappingKey = std::pair<StringId /* name */, StringId /* build id */>;
+ std::map<MappingKey, std::vector<MappingId>> stack_profile_mapping_index_;
+
+ using FrameKey = std::pair<MappingId, uint64_t /* rel_pc */>;
+ std::map<FrameKey, std::vector<FrameId>> stack_profile_frame_index_;
+
+ std::map<NameInPackage, std::vector<tables::StackProfileFrameTable::Id>>
+ java_frames_for_name_;
+};
+
+// TODO(lalitm): Overhaul this class to make row vs id consistent and use
+// base::Optional instead of int64_t.
+class SequenceStackProfileTracker {
+ public:
+ using SourceStringId = uint64_t;
+
+ enum class InternedStringType {
+ kMappingPath,
+ kBuildId,
+ kFunctionName,
+ };
+
+ struct SourceMapping {
+ SourceStringId build_id = 0;
+ uint64_t exact_offset = 0;
+ uint64_t start_offset = 0;
+ uint64_t start = 0;
+ uint64_t end = 0;
+ uint64_t load_bias = 0;
+ std::vector<SourceStringId> name_ids;
+ };
+ using SourceMappingId = uint64_t;
+
+ struct SourceFrame {
+ SourceStringId name_id = 0;
+ SourceMappingId mapping_id = 0;
+ uint64_t rel_pc = 0;
+ };
+ using SourceFrameId = uint64_t;
+
+ using SourceCallstack = std::vector<SourceFrameId>;
+ using SourceCallstackId = uint64_t;
+
+ struct SourceAllocation {
+ uint64_t pid = 0;
+ // This is int64_t, because we get this from the TraceSorter which also
+ // converts this for us.
+ int64_t timestamp = 0;
+ SourceCallstackId callstack_id = 0;
+ uint64_t self_allocated = 0;
+ uint64_t self_freed = 0;
+ uint64_t alloc_count = 0;
+ uint64_t free_count = 0;
+ };
+
+ class InternLookup {
+ public:
+ virtual ~InternLookup();
+
+ virtual std::optional<base::StringView> GetString(
+ SourceStringId,
+ InternedStringType) const = 0;
+ virtual std::optional<SourceMapping> GetMapping(SourceMappingId) const = 0;
+ virtual std::optional<SourceFrame> GetFrame(SourceFrameId) const = 0;
+ virtual std::optional<SourceCallstack> GetCallstack(
+ SourceCallstackId) const = 0;
+ };
+
+ explicit SequenceStackProfileTracker(TraceProcessorContext* context);
+ ~SequenceStackProfileTracker();
+
+ void AddString(SourceStringId, base::StringView);
+ std::optional<MappingId> AddMapping(
+ SourceMappingId,
+ const SourceMapping&,
+ const InternLookup* intern_lookup = nullptr);
+ std::optional<FrameId> AddFrame(SourceFrameId,
+ const SourceFrame&,
+ const InternLookup* intern_lookup = nullptr);
+ std::optional<CallsiteId> AddCallstack(
+ SourceCallstackId,
+ const SourceCallstack&,
+ const InternLookup* intern_lookup = nullptr);
+
+ FrameId GetDatabaseFrameIdForTesting(SourceFrameId);
+
+ // Gets the row number of string / mapping / frame / callstack previously
+ // added through AddString / AddMapping/ AddFrame / AddCallstack.
+ //
+ // If it is not found, look up the string / mapping / frame / callstack in
+ // the global InternedData state, and if found, add to the database, if not
+ // already added before.
+ //
+ // This is to support both ProfilePackets that contain the interned data
+ // (for Android Q) and where the interned data is kept globally in
+ // InternedData (for versions newer than Q).
+ std::optional<StringId> FindAndInternString(SourceStringId,
+ const InternLookup* intern_lookup,
+ InternedStringType type);
+ std::optional<std::string> FindOrInsertString(
+ SourceStringId,
+ const InternLookup* intern_lookup,
+ InternedStringType type);
+ std::optional<MappingId> FindOrInsertMapping(
+ SourceMappingId,
+ const InternLookup* intern_lookup);
+ std::optional<FrameId> FindOrInsertFrame(SourceFrameId,
+ const InternLookup* intern_lookup);
+
+ std::optional<CallsiteId> FindOrInsertCallstack(
+ SourceCallstackId,
+ const InternLookup* intern_lookup);
+
+ // Clear indices when they're no longer needed.
+ void ClearIndices();
+
+ private:
+ StringId GetEmptyStringId();
+
+ std::unordered_map<SourceStringId, std::string> string_map_;
+
+ // Mapping from ID of mapping / frame / callstack in original trace and the
+ // index in the respective table it was inserted into.
+ std::unordered_map<SourceMappingId, MappingId> mapping_ids_;
+ std::unordered_map<SourceFrameId, FrameId> frame_ids_;
+ std::unordered_map<SourceCallstackId, CallsiteId> callstack_ids_;
+
+ // TODO(oysteine): Share these indices between the StackProfileTrackers,
+ // since they're not sequence-specific.
+ //
+ // Mapping from content of database row to the index of the raw.
+ std::unordered_map<tables::StackProfileMappingTable::Row, MappingId>
+ mapping_idx_;
+ std::unordered_map<tables::StackProfileFrameTable::Row, FrameId> frame_idx_;
+ std::unordered_map<tables::StackProfileCallsiteTable::Row, CallsiteId>
+ callsite_idx_;
+
+ TraceProcessorContext* const context_;
+ StringId empty_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_TRACKER_H_
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 00bf52e..06e5c39 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -34,7 +34,6 @@
#include "src/trace_processor/importers/proto/packet_analyzer.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
-#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
#include "src/trace_processor/importers/proto/track_event_tracker.h"
#include "src/trace_processor/util/debug_annotation_parser.h"
#include "src/trace_processor/util/proto_to_args_parser.h"
@@ -196,9 +195,12 @@
}
// Interned mapping_id loses it's meaning when the sequence ends. So we need
// to get an id from stack_profile_mapping table.
- auto mapping_id = delegate.seq_state()
- ->GetOrCreate<StackProfileSequenceState>()
- ->FindOrInsertMapping(decoder->mapping_id());
+ ProfilePacketInternLookup intern_lookup(delegate.seq_state());
+ auto mapping_id =
+ delegate.seq_state()
+ ->state()
+ ->sequence_stack_profile_tracker()
+ .FindOrInsertMapping(decoder->mapping_id(), &intern_lookup);
if (!mapping_id) {
return std::nullopt;
}
diff --git a/src/trace_processor/importers/proto/v8_module.cc b/src/trace_processor/importers/proto/v8_module.cc
index 94684e3..ac2086a 100644
--- a/src/trace_processor/importers/proto/v8_module.cc
+++ b/src/trace_processor/importers/proto/v8_module.cc
@@ -88,7 +88,8 @@
void V8Module::ParseV8JsCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *V8SequenceState::GetOrCreate(data.sequence_state->state());
V8JsCode::Decoder code(bytes);
@@ -109,7 +110,8 @@
void V8Module::ParseV8InternalCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *V8SequenceState::GetOrCreate(data.sequence_state->state());
V8InternalCode::Decoder code(bytes);
@@ -124,7 +126,8 @@
void V8Module::ParseV8WasmCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *V8SequenceState::GetOrCreate(data.sequence_state->state());
V8WasmCode::Decoder code(bytes);
@@ -145,7 +148,8 @@
void V8Module::ParseV8RegExpCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *V8SequenceState::GetOrCreate(data.sequence_state->state());
V8RegExpCode::Decoder code(bytes);
@@ -160,7 +164,8 @@
void V8Module::ParseV8CodeMove(protozero::ConstBytes bytes,
int64_t,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *V8SequenceState::GetOrCreate(data.sequence_state->state());
protos::pbzero::V8CodeMove::Decoder v8_code_move(bytes);
std::optional<tables::V8IsolateTable::Id> isolate_id =
diff --git a/src/trace_processor/importers/proto/v8_sequence_state.cc b/src/trace_processor/importers/proto/v8_sequence_state.cc
index 33abb24..946ab22 100644
--- a/src/trace_processor/importers/proto/v8_sequence_state.cc
+++ b/src/trace_processor/importers/proto/v8_sequence_state.cc
@@ -17,10 +17,10 @@
#include "src/trace_processor/importers/proto/v8_sequence_state.h"
#include <optional>
+#include "perfetto/ext/base/string_utils.h"
#include "protos/perfetto/trace/chrome/v8.pbzero.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/importers/proto/string_encoding_utils.h"
#include "src/trace_processor/importers/proto/v8_tracker.h"
#include "src/trace_processor/storage/stats.h"
@@ -41,8 +41,9 @@
} // namespace
-V8SequenceState::V8SequenceState(TraceProcessorContext* context)
- : context_(context), v8_tracker_(V8Tracker::GetOrCreate(context_)) {}
+V8SequenceState::V8SequenceState(PacketSequenceState* sequence_state)
+ : sequence_state_(sequence_state),
+ v8_tracker_(V8Tracker::GetOrCreate(sequence_state->context())) {}
V8SequenceState::~V8SequenceState() = default;
@@ -52,9 +53,11 @@
return *id;
}
- auto* view = GetInternedMessageView(InternedData::kV8IsolateFieldNumber, iid);
+ auto* view = sequence_state_->current_generation()->GetInternedMessageView(
+ InternedData::kV8IsolateFieldNumber, iid);
if (!view) {
- context_->storage->IncrementStats(stats::v8_intern_errors);
+ sequence_state_->context()->storage->IncrementStats(
+ stats::v8_intern_errors);
return std::nullopt;
}
@@ -70,10 +73,11 @@
return *id;
}
- auto* view =
- GetInternedMessageView(InternedData::kV8JsFunctionFieldNumber, iid);
+ auto* view = sequence_state_->current_generation()->GetInternedMessageView(
+ InternedData::kV8JsFunctionFieldNumber, iid);
if (!view) {
- context_->storage->IncrementStats(stats::v8_intern_errors);
+ sequence_state_->context()->storage->IncrementStats(
+ stats::v8_intern_errors);
return std::nullopt;
}
@@ -103,10 +107,11 @@
if (auto* id = wasm_scripts_.Find(iid); id != nullptr) {
return *id;
}
- auto* view =
- GetInternedMessageView(InternedData::kV8WasmScriptFieldNumber, iid);
+ auto* view = sequence_state_->current_generation()->GetInternedMessageView(
+ InternedData::kV8WasmScriptFieldNumber, iid);
if (!view) {
- context_->storage->IncrementStats(stats::v8_intern_errors);
+ sequence_state_->context()->storage->IncrementStats(
+ stats::v8_intern_errors);
return std::nullopt;
}
@@ -122,10 +127,11 @@
if (auto* id = js_scripts_.Find(iid); id != nullptr) {
return *id;
}
- auto* view =
- GetInternedMessageView(InternedData::kV8JsScriptFieldNumber, iid);
+ auto* view = sequence_state_->current_generation()->GetInternedMessageView(
+ InternedData::kV8JsScriptFieldNumber, iid);
if (!view) {
- context_->storage->IncrementStats(stats::v8_intern_errors);
+ sequence_state_->context()->storage->IncrementStats(
+ stats::v8_intern_errors);
return std::nullopt;
}
@@ -141,16 +147,17 @@
return *id;
}
- auto* view =
- GetInternedMessageView(InternedData::kV8JsFunctionNameFieldNumber, iid);
+ auto* view = sequence_state_->current_generation()->GetInternedMessageView(
+ InternedData::kV8JsFunctionNameFieldNumber, iid);
if (!view) {
- context_->storage->IncrementStats(stats::v8_intern_errors);
+ sequence_state_->context()->storage->IncrementStats(
+ stats::v8_intern_errors);
return std::nullopt;
}
InternedV8String::Decoder function_name(ToConstBytes(view->message()));
- auto& storage = *context_->storage;
+ auto& storage = *sequence_state_->context()->storage;
StringId id;
if (function_name.has_latin1()) {
id = storage.InternString(
diff --git a/src/trace_processor/importers/proto/v8_sequence_state.h b/src/trace_processor/importers/proto/v8_sequence_state.h
index d2e008a..781960d 100644
--- a/src/trace_processor/importers/proto/v8_sequence_state.h
+++ b/src/trace_processor/importers/proto/v8_sequence_state.h
@@ -21,7 +21,7 @@
#include <optional>
#include "perfetto/ext/base/flat_hash_map.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/v8_tables_py.h"
#include "src/trace_processor/types/destructible.h"
@@ -29,14 +29,19 @@
namespace perfetto {
namespace trace_processor {
-class TraceProcessorContext;
class V8Tracker;
// Helper class to deal with V8 related interned data.
-class V8SequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
+class V8SequenceState : public Destructible {
public:
- explicit V8SequenceState(TraceProcessorContext* context);
+ static V8SequenceState* GetOrCreate(PacketSequenceState* sequence_state) {
+ auto& v8_sequence_state =
+ sequence_state->extensible_sequence_state().v8_sequence_state;
+ if (!v8_sequence_state) {
+ v8_sequence_state.reset(new V8SequenceState(sequence_state));
+ }
+ return static_cast<V8SequenceState*>(v8_sequence_state.get());
+ }
~V8SequenceState() override;
@@ -49,12 +54,13 @@
tables::V8IsolateTable::Id isolate_id);
private:
+ explicit V8SequenceState(PacketSequenceState* sequence_state);
std::optional<tables::V8JsScriptTable::Id> GetOrInsertJsScript(
uint64_t iid,
tables::V8IsolateTable::Id isolate_id);
std::optional<StringId> GetOrInsertJsFunctionName(uint64_t iid);
- TraceProcessorContext* const context_;
+ PacketSequenceState* const sequence_state_;
V8Tracker* const v8_tracker_;
using InterningId = uint64_t;
diff --git a/src/trace_processor/importers/proto/vulkan_memory_tracker.h b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
index 9d1afc5..1457923 100644
--- a/src/trace_processor/importers/proto/vulkan_memory_tracker.h
+++ b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
@@ -17,7 +17,6 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/winscope/protolog_messages_tracker.h b/src/trace_processor/importers/proto/winscope/protolog_messages_tracker.h
index e61c5f5..0f47c32 100644
--- a/src/trace_processor/importers/proto/winscope/protolog_messages_tracker.h
+++ b/src/trace_processor/importers/proto/winscope/protolog_messages_tracker.h
@@ -35,6 +35,7 @@
std::vector<double> double_params;
std::vector<bool> boolean_params;
std::vector<std::string> string_params;
+ std::optional<StringId> stacktrace;
tables::ProtoLogTable::Id table_row_id;
int64_t timestamp;
};
diff --git a/src/trace_processor/importers/proto/winscope/protolog_parser.cc b/src/trace_processor/importers/proto/winscope/protolog_parser.cc
index 0543222..15c19ac 100644
--- a/src/trace_processor/importers/proto/winscope/protolog_parser.cc
+++ b/src/trace_processor/importers/proto/winscope/protolog_parser.cc
@@ -30,7 +30,6 @@
#include "src/trace_processor/types/trace_processor_context.h"
#include <sstream>
-
namespace perfetto {
namespace trace_processor {
@@ -79,9 +78,9 @@
}
std::vector<std::string> string_params;
- if (protolog_message.has_interned_str_params()) {
+ if (protolog_message.has_str_param_iids()) {
if (sequence_state->state()->IsIncrementalStateValid()) {
- for (auto it = protolog_message.interned_str_params(); it; ++it) {
+ for (auto it = protolog_message.str_param_iids(); it; ++it) {
auto decoder =
sequence_state->state()
->current_generation()
@@ -109,6 +108,28 @@
}
}
+ std::optional<StringId> stacktrace = std::nullopt;
+ if (protolog_message.has_stacktrace_iid()) {
+ auto stacktrace_decoder =
+ sequence_state->state()
+ ->current_generation()
+ ->LookupInternedMessage<
+ protos::pbzero::InternedData::kProtologStacktraceFieldNumber,
+ protos::pbzero::InternedString>(
+ protolog_message.stacktrace_iid());
+
+ if (!stacktrace_decoder) {
+ // This shouldn't happen since we already checked the incremental
+ // state is valid.
+ string_params.emplace_back("<ERROR>");
+ context_->storage->IncrementStats(
+ stats::winscope_protolog_missing_interned_stacktrace_parse_errors);
+ } else {
+ stacktrace = context_->storage->InternString(
+ base::StringView(stacktrace_decoder->str().ToStdString()));
+ }
+ }
+
auto* protolog_table = context_->storage->mutable_protolog_table();
tables::ProtoLogTable::Row row;
@@ -122,6 +143,7 @@
std::move(double_params),
std::move(boolean_params),
std::move(string_params),
+ stacktrace,
row_id,
timestamp};
protolog_message_tracker->TrackMessage(std::move(tracked_message));
@@ -195,6 +217,10 @@
auto message = context_->storage->InternString(
base::StringView(formatted_message));
row.set_message(message);
+
+ if (tracked_message.stacktrace.has_value()) {
+ row.set_stacktrace(tracked_message.stacktrace.value());
+ }
}
}
}
diff --git a/src/trace_processor/importers/proto/winscope/protolog_parser.h b/src/trace_processor/importers/proto/winscope/protolog_parser.h
index 97d9183..fbcf9d9 100644
--- a/src/trace_processor/importers/proto/winscope/protolog_parser.h
+++ b/src/trace_processor/importers/proto/winscope/protolog_parser.h
@@ -19,7 +19,6 @@
#include "protos/perfetto/trace/android/protolog.pbzero.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/util/descriptors.h"
#include "src/trace_processor/util/proto_to_args_parser.h"
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
index ea8b3ae..e34973c 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
@@ -42,7 +42,7 @@
]
deps = [
"../../..:demangle",
- "../../..:export_json_sources",
+ "../../..:export_json",
"../../..:metatrace",
"../../../../../gn:default_deps",
"../../../../../gn:sqlite",
diff --git a/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc b/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc
index b4d76cf..fde9046 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc
@@ -31,8 +31,8 @@
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/table.h"
#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
+#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/flamegraph_construction_algorithms.h"
-#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/profiler_tables_py.h"
#include "src/trace_processor/types/trace_processor_context.h"
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql b/src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql
index 3afe0bf..6467ea7 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql
@@ -14,37 +14,82 @@
-- limitations under the License.
--
+INCLUDE PERFETTO MODULE android.freezer;
+
+CREATE PERFETTO FUNCTION _extract_broadcast_process_name(name STRING)
+RETURNS INT
+AS
+WITH
+ pid_and_name AS (
+ SELECT STR_SPLIT(STR_SPLIT($name, '/', 0), ' ', 1) AS value
+ ),
+ start AS (
+ SELECT CAST(INSTR(value, ':') AS INT) + 1 AS value FROM pid_and_name
+ )
+SELECT SUBSTR(pid_and_name.value, start.value) FROM pid_and_name, start;
+
-- Provides a list of broadcast names and processes they were sent to by the
-- system_server process on U+ devices.
-CREATE PERFETTO VIEW _android_broadcasts_minsdk_u(
- -- The name of the broadcast type which was sent.
- type STRING,
- -- The process name the broadcast was sent to.
+CREATE PERFETTO TABLE _android_broadcasts_minsdk_u(
+ -- Intent action of the broadcast.
+ intent_action STRING,
+ -- Name of the process the broadcast was sent to.
process_name STRING,
- -- The name of the broacast queue the broadcast was dispatched from.
- queue_name STRING
+ -- Pid of the process the broadcast was sent to.
+ pid STRING,
+ -- Upid of the process the broadcast was sent to.
+ upid STRING,
+ -- Id of the broacast queue the broadcast was dispatched from.
+ queue_id INT,
+ -- Slice id of the broadcast dispatch.
+ id INT,
+ -- Timestamp the broadcast was dispatched.
+ ts INT,
+ -- Duration to dispatch the broadcast.
+ dur INT,
+ -- Track id the broadcast was dispatched from.
+ track_id INT
) AS
WITH
-broadcast_queues AS (
- SELECT process_track.id, process_track.name AS queue_name
- FROM process_track
- JOIN process USING (upid)
- WHERE
- process_track.name GLOB 'BroadcastQueue.mRunning*'
- AND process.name = 'system_server'
-),
-broadcast_process_running AS (
- SELECT ts, dur, str_split(slice.name, '/', 0) AS process_name, queue_name
- FROM slice
- JOIN broadcast_queues ON broadcast_queues.id = slice.track_id
- WHERE slice.name GLOB '* running'
-)
-SELECT str_split(slice.name, '/', 0) AS type, process_name, queue_name
-FROM broadcast_process_running
-JOIN broadcast_queues USING (queue_name)
-JOIN slice ON (
- broadcast_process_running.ts < slice.ts
- AND slice.ts < broadcast_process_running.ts + broadcast_process_running.dur
- AND slice.track_id = broadcast_queues.id
+ broadcast_queues AS (
+ SELECT
+ process_track.id,
+ CAST(replace(str_split(process_track.name, '[', 1), ']', '') AS INT) AS queue_id
+ FROM process_track
+ JOIN process
+ USING (upid)
+ WHERE
+ process_track.name GLOB 'BroadcastQueue.mRunning*'
+ AND process.name = 'system_server'
+ ),
+ broadcast_process_running AS (
+ SELECT
+ slice.ts,
+ slice.dur,
+ _extract_broadcast_process_name(slice.name) AS process_name,
+ CAST(str_split(str_split(str_split(slice.name, '/', 0), ' ', 1), ':', 0) AS INT) AS pid,
+ queue_id
+ FROM slice
+ JOIN broadcast_queues
+ ON broadcast_queues.id = slice.track_id
+ WHERE slice.name GLOB '* running'
)
+SELECT
+ str_split(str_split(slice.name, '/', 0), ' ', 1) AS intent_action,
+ process_name,
+ pid,
+ _pid_to_upid(pid, slice.ts) AS upid,
+ queue_id,
+ slice.id,
+ slice.ts,
+ slice.dur,
+ slice.track_id
+FROM broadcast_process_running
+JOIN broadcast_queues
+ USING (queue_id)
+JOIN slice
+ ON (
+ broadcast_process_running.ts < slice.ts
+ AND slice.ts < broadcast_process_running.ts + broadcast_process_running.dur
+ AND slice.track_id = broadcast_queues.id)
WHERE slice.name GLOB '* scheduled';
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql b/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
index 040d79f..314e612 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
@@ -93,7 +93,7 @@
slice.name AS oom_adj_trigger,
LEAD(thread_slice.ts) OVER (ORDER BY thread_slice.ts) AS oom_adj_next_ts
FROM thread_slice
- JOIN slice ON slice.id = thread_slice.parent_id
+ LEFT JOIN slice ON slice.id = thread_slice.parent_id AND slice.dur != -1
WHERE thread_slice.name GLOB 'updateOomAdj_*' AND process_name = 'system_server'
)
SELECT
diff --git a/src/trace_processor/sqlite/db_sqlite_table.cc b/src/trace_processor/sqlite/db_sqlite_table.cc
index 8131d36..4d38bd6 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.cc
+++ b/src/trace_processor/sqlite/db_sqlite_table.cc
@@ -646,15 +646,7 @@
}
});
- // Attempt to filter into a RowMap first - weall figure out whether to apply
- // this to the table or we should use the RowMap directly. Also, if we are
- // going to sort on the RowMap, it makes sense that we optimize for lookup
- // speed so our sorting is not super slow.
- RowMap::OptimizeFor optimize_for = orders_.empty()
- ? RowMap::OptimizeFor::kMemory
- : RowMap::OptimizeFor::kLookupSpeed;
- RowMap filter_map =
- SourceTable()->QueryToRowMap(constraints_, orders_, optimize_for);
+ RowMap filter_map = SourceTable()->QueryToRowMap(constraints_, orders_);
if (filter_map.IsRange() && filter_map.size() <= 1) {
// Currently, our criteria where we have a special fast path is if it's
// a single ranged row. We have this fast path for joins on id columns
diff --git a/src/trace_processor/storage/stats.h b/src/trace_processor/storage/stats.h
index 74cba79..66a524e 100644
--- a/src/trace_processor/storage/stats.h
+++ b/src/trace_processor/storage/stats.h
@@ -60,12 +60,15 @@
F(ftrace_cpu_oldest_event_ts_end, kIndexed, kInfo, kTrace, ""), \
F(ftrace_cpu_overrun_begin, kIndexed, kInfo, kTrace, ""), \
F(ftrace_cpu_overrun_end, kIndexed, kInfo, kTrace, ""), \
- F(ftrace_cpu_overrun_delta, kIndexed, kDataLoss, kTrace, \
- "The kernel ftrace buffer cannot keep up with the rate of events " \
- "produced. Indexed by CPU. This is likely a misconfiguration."), \
+ F(ftrace_cpu_overrun_delta, kIndexed, kInfo, kTrace, ""), \
F(ftrace_cpu_read_events_begin, kIndexed, kInfo, kTrace, ""), \
F(ftrace_cpu_read_events_end, kIndexed, kInfo, kTrace, ""), \
F(ftrace_cpu_read_events_delta, kIndexed, kInfo, kTrace, ""), \
+ F(ftrace_cpu_has_data_loss, kIndexed, kDataLoss, kTrace, \
+ "Ftrace data for the given cpu has data losses and is therefore " \
+ "unreliable. The kernel buffer overwrote events between our reads " \
+ "in userspace. Try re-recording the trace with a bigger buffer " \
+ "(ftrace_config.buffer_size_kb), or with fewer enabled ftrace events."),\
F(ftrace_setup_errors, kSingle, kInfo, kTrace, \
"One or more atrace/ftrace categories were not found or failed to " \
"enable. See ftrace_setup_errors in the metadata table for details."), \
@@ -112,8 +115,6 @@
F(flow_end_without_start, kSingle, kInfo, kTrace, ""), \
F(flow_invalid_id, kSingle, kError, kTrace, ""), \
F(flow_without_direction, kSingle, kError, kTrace, ""), \
- F(stackprofile_empty_callstack, kSingle, kError, kTrace, \
- "Callstack had no frames. Ignored"), \
F(stackprofile_invalid_string_id, kSingle, kError, kTrace, ""), \
F(stackprofile_invalid_mapping_id, kSingle, kError, kTrace, ""), \
F(stackprofile_invalid_frame_id, kSingle, kError, kTrace, ""), \
@@ -140,7 +141,11 @@
kIndexed, kInfo, kTrace, ""), \
F(traced_buf_padding_bytes_cleared, kIndexed, kInfo, kTrace, ""), \
F(traced_buf_padding_bytes_written, kIndexed, kInfo, kTrace, ""), \
- F(traced_buf_patches_failed, kIndexed, kDataLoss, kTrace, ""), \
+ F(traced_buf_patches_failed, kIndexed, kDataLoss, kTrace, \
+ "The tracing service potentially lost data from one of the data sources "\
+ "writing into the given target_buffer. This entry can be ignored" \
+ "if you're using DISCARD buffers and traced_buf_chunks_discarded is \
+ nonzero, meaning that the buffer was filled."), \
F(traced_buf_patches_succeeded, kIndexed, kInfo, kTrace, ""), \
F(traced_buf_readaheads_failed, kIndexed, kInfo, kTrace, ""), \
F(traced_buf_readaheads_succeeded, kIndexed, kInfo, kTrace, ""), \
@@ -299,7 +304,10 @@
"ProtoLog message string has invalid interplation parameter."), \
F(winscope_protolog_missing_interned_arg_parse_errors, \
kSingle, kInfo, kAnalysis, \
- "Failed to find interned ProtoLog argument."), \
+ "Failed to find interned ProtoLog argument."), \
+ F(winscope_protolog_missing_interned_stacktrace_parse_errors, \
+ kSingle, kInfo, kAnalysis, \
+ "Failed to find interned ProtoLog stacktrace."), \
F(ftrace_missing_event_id, kSingle, kInfo, kAnalysis, \
"Indicates that the ftrace event was dropped because the event id was " \
"missing. This is an 'info' stat rather than an error stat because " \
diff --git a/src/trace_processor/tables/BUILD.gn b/src/trace_processor/tables/BUILD.gn
index a0ec6fa..b2fcffb 100644
--- a/src/trace_processor/tables/BUILD.gn
+++ b/src/trace_processor/tables/BUILD.gn
@@ -44,9 +44,6 @@
"../../../include/perfetto/trace_processor",
"../containers",
"../db:minimal",
-
- # TODO(lalitm): change this to minimal to reduce binary size
- # impact on Chrome.
"../db/column",
]
public_deps = [ ":tables_python" ]
diff --git a/src/trace_processor/tables/py_tables_benchmark.cc b/src/trace_processor/tables/py_tables_benchmark.cc
index 37bb9f7..6aea3d5 100644
--- a/src/trace_processor/tables/py_tables_benchmark.cc
+++ b/src/trace_processor/tables/py_tables_benchmark.cc
@@ -95,29 +95,6 @@
}
BENCHMARK(BM_TableIteratorChild)->Apply(TableFilterArgs);
-static void BM_TableFilterAndSortRoot(benchmark::State& state) {
- StringPool pool;
- RootTestTable root(&pool);
-
- auto size = static_cast<uint32_t>(state.range(0));
- uint32_t partitions = 8;
-
- std::minstd_rand0 rnd_engine(45);
- for (uint32_t i = 0; i < size; ++i) {
- RootTestTable::Row row;
- row.root_non_null = rnd_engine() % partitions;
- row.root_non_null_2 = static_cast<uint32_t>(rnd_engine());
- root.Insert(row);
- }
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(root.ApplyAndIterateRows(root.QueryToRowMap(
- {root.root_non_null().eq(5)}, {root.root_non_null_2().ascending()},
- RowMap::OptimizeFor::kLookupSpeed)));
- }
-}
-BENCHMARK(BM_TableFilterAndSortRoot)->Apply(TableFilterArgs);
-
static void BM_TableFilterRootId(benchmark::State& state) {
StringPool pool;
RootTestTable root(&pool);
diff --git a/src/trace_processor/tables/winscope_tables.py b/src/trace_processor/tables/winscope_tables.py
index 830f88e..8a60e43 100644
--- a/src/trace_processor/tables/winscope_tables.py
+++ b/src/trace_processor/tables/winscope_tables.py
@@ -112,6 +112,7 @@
C('level', CppString()),
C('tag', CppString()),
C('message', CppString()),
+ C('stacktrace', CppString()),
],
tabledoc=TableDoc(
doc='Protolog',
@@ -121,6 +122,7 @@
'level': 'The log level of the protolog message',
'tag': 'The log tag of the protolog message',
'message': 'The protolog message',
+ 'stacktrace': 'Stacktrace captured at the message\'s logpoint',
}))
# Keep this list sorted.
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index c7cea38..34da487 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -31,12 +31,13 @@
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/slice_translation_table.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
+#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/importers/proto/track_event_module.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/types/destructible.h"
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 41fdab3..8894f47 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -339,18 +339,6 @@
context_.content_analyzer.reset(new ProtoContentAnalyzer(&context_));
}
- auto v2 = context_.config.dev_flags.find("enable_db2_filtering");
- if (v2 != context_.config.dev_flags.end()) {
- if (v2->second == "true") {
- Table::kUseFilterV2 = true;
- } else if (v2->second == "false") {
- Table::kUseFilterV2 = false;
- } else {
- PERFETTO_ELOG("Unknown value for enable_db2_filtering %s",
- v2->second.c_str());
- }
- }
-
// Add metrics to descriptor pool
const std::vector<std::string> sanitized_extension_paths =
SanitizeMetricMountPaths(config_.skip_builtin_metric_paths);
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index 05b88c0..f24a1fc 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -30,14 +30,15 @@
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/slice_translation_table.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/proto/chrome_track_event.descriptor.h"
#include "src/trace_processor/importers/proto/default_modules.h"
+#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
#include "src/trace_processor/importers/proto/packet_analyzer.h"
#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/importers/proto/proto_trace_reader.h"
+#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/importers/proto/track_event.descriptor.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/util/descriptors.h"
@@ -62,8 +63,9 @@
context_.process_tracker.reset(new ProcessTracker(&context_));
context_.clock_tracker.reset(new ClockTracker(&context_));
context_.clock_converter.reset(new ClockConverter(&context_));
+ context_.heap_profile_tracker.reset(new HeapProfileTracker(&context_));
context_.perf_sample_tracker.reset(new PerfSampleTracker(&context_));
- context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
+ context_.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
context_.metadata_tracker.reset(new MetadataTracker(context_.storage.get()));
context_.global_args_tracker.reset(
new GlobalArgsTracker(context_.storage.get()));
@@ -141,6 +143,7 @@
}
context_.event_tracker->FlushPendingEvents();
context_.slice_tracker->FlushPendingSlices();
+ context_.heap_profile_tracker->NotifyEndOfFile();
context_.args_tracker->Flush();
context_.process_tracker->NotifyEndOfFile();
}
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index ad4e148..25f129b 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -52,8 +52,9 @@
class ForwardingTraceParser;
class FtraceModule;
class GlobalArgsTracker;
-class StackProfileTracker;
+class GlobalStackProfileTracker;
class HeapGraphTracker;
+class HeapProfileTracker;
class PerfSampleTracker;
class MetadataTracker;
class PacketAnalyzer;
@@ -100,8 +101,9 @@
std::unique_ptr<EventTracker> event_tracker;
std::unique_ptr<ClockTracker> clock_tracker;
std::unique_ptr<ClockConverter> clock_converter;
+ std::unique_ptr<HeapProfileTracker> heap_profile_tracker;
std::unique_ptr<PerfSampleTracker> perf_sample_tracker;
- std::unique_ptr<StackProfileTracker> stack_profile_tracker;
+ std::unique_ptr<GlobalStackProfileTracker> global_stack_profile_tracker;
std::unique_ptr<MetadataTracker> metadata_tracker;
// These fields are stored as pointers to Destructible objects rather than
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index 8420a06..c717d3e 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -61,19 +61,6 @@
}
}
-source_set("profiler_util") {
- sources = [
- "profiler_util.cc",
- "profiler_util.h",
- ]
- deps = [
- "../../../gn:default_deps",
- "../../../include/perfetto/ext/base:base",
- "../../../protos/perfetto/trace/profiling:zero",
- "../storage:storage",
- ]
-}
-
source_set("stack_traces_util") {
sources = [
"stack_traces_util.cc",
@@ -82,7 +69,6 @@
deps = [
"../../../gn:default_deps",
"../../../include/perfetto/ext/base:base",
- "../../../protos/perfetto/trace/profiling:zero",
]
}
diff --git a/src/tracing/service/tracing_service_impl.cc b/src/tracing/service/tracing_service_impl.cc
index 3b94cbf..aba6620 100644
--- a/src/tracing/service/tracing_service_impl.cc
+++ b/src/tracing/service/tracing_service_impl.cc
@@ -1797,7 +1797,7 @@
}
if (tracing_session->state != TracingSession::STARTED) {
- PERFETTO_ELOG("Flush() called, but tracing has not been started");
+ PERFETTO_LOG("Flush() called, but tracing has not been started");
callback(false);
return;
}
diff --git a/src/tracing/service/tracing_service_impl_unittest.cc b/src/tracing/service/tracing_service_impl_unittest.cc
index 76590b4..17936e5 100644
--- a/src/tracing/service/tracing_service_impl_unittest.cc
+++ b/src/tracing/service/tracing_service_impl_unittest.cc
@@ -5080,7 +5080,7 @@
}
TEST_F(TracingServiceImplTest, ClearBeforeClone) {
- // The consumer the creates the initial tracing session.
+ // The consumer that creates the initial tracing session.
std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
consumer->Connect(svc.get());
@@ -5150,6 +5150,53 @@
HasSubstr("after_clone")))));
}
+TEST_F(TracingServiceImplTest, CloneMainSessionStopped) {
+ // The consumer that creates the initial tracing session.
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer1");
+ producer->RegisterDataSource("ds_1");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(1024); // Buf 0.
+ auto* ds_cfg = trace_config.add_data_sources()->mutable_config();
+ ds_cfg->set_name("ds_1");
+ ds_cfg->set_target_buffer(0);
+
+ consumer->EnableTracing(trace_config);
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("ds_1");
+ producer->WaitForDataSourceStart("ds_1");
+
+ std::unique_ptr<TraceWriter> writer = producer->CreateTraceWriter("ds_1");
+ {
+ auto packet = writer->NewTracePacket();
+ packet->set_for_testing()->set_str("before_clone");
+ }
+ writer->Flush();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("ds_1");
+ consumer->WaitForTracingDisabled();
+
+ // The tracing session is disabled, but it's still there. We can still clone
+ // it.
+ std::unique_ptr<MockConsumer> clone_consumer = CreateMockConsumer();
+ clone_consumer->Connect(svc.get());
+
+ auto clone_done = task_runner.CreateCheckpoint("clone_done");
+ EXPECT_CALL(*clone_consumer, OnSessionCloned(_))
+ .WillOnce(InvokeWithoutArgs(clone_done));
+ clone_consumer->CloneSession(1);
+
+ auto packets = clone_consumer->ReadBuffers();
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ HasSubstr("before_clone")))));
+}
+
TEST_F(TracingServiceImplTest, CloneTransferFlush) {
// The consumer the creates the initial tracing session.
std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
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 25fb3c5..590d1c0 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 @@
-9f4d57409034b11957935bbd94c8fa925d24db453b617503b6c908366b1f11cc
\ No newline at end of file
+71f0799ce780f36dbdeb601ba535ee012b7323afc57254a5b383704ec384da62
\ 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 f99f37b..fd6b0fe 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 @@
-f358a8b059b98a0445674d5e720230047f85829a6366439559ffc5908508ba11
\ No newline at end of file
+725ff7289949bda82fc4c2d454e1ee0b4218b3d56f20c1098d6fa7914ef19bfc
\ 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 d8f53e7..06a3e7b 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 @@
-a4b1867255b838c3ab73f6d00c84aa5bd7fc31bb53da5b83f52ceb84d99e96b2
\ No newline at end of file
+22ca974ba2f262c4e421e95dba686746eb89564a8ff213e50f78c9424277587c
\ 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 6cbb409..a917bab 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 @@
-ec9873453c3834735d55eb21138bf510069cf863342509a799076d821a8f01dd
\ No newline at end of file
+90505c5620c73940b88d163a73c79005fa8e81d097d0fcabf2585e56f7bc6a99
\ 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 6667e5f..89a9c57 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 @@
-351edcf1ade9e6b1b7ced9d4f204e9a939370b7a56066f66793e56c9d93ec972
\ No newline at end of file
+d1a9ace55344d8a2850a8238b698892aca1ea2eacf80886420108043de8d3c56
\ 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 90d04b9..470075f 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 @@
-3699ab1be1ccf7f41559fad373027c884b3f1539183f4b405e29852f01985937
\ No newline at end of file
+a97c6027c4bef120c4227a7ed32e6a6fb6b290938ef8d66652e6d369b7e5d157
\ 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 92f9c01..a0ddb77 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 @@
-1bcbdbf6d1c2c1c2e77faa90be1c060b350f21472f67aed9477e6ba5e5219e81
\ No newline at end of file
+47cda8e8a9ed007945bff13d7c10fa4d33fc6e264c1198b2038a216559bec962
\ 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 bd02978..98f2571 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 @@
-0b44f0292e51fcf599f17622193d67b17bbaca02440cf2f0e994dbbbac65306a
\ No newline at end of file
+bd495271f97ffe17851f6605acaf24463c2363cb6a4bcf8e1b3fd78b9e18353f
\ 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 ff33850..5b79980 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 @@
-7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
+ab93fa5646ab5e2bc63922ee8f6c6d7657f128fe7b5426df97d02f19c770a1bc
\ 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 92f9c01..a0ddb77 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 @@
-1bcbdbf6d1c2c1c2e77faa90be1c060b350f21472f67aed9477e6ba5e5219e81
\ No newline at end of file
+47cda8e8a9ed007945bff13d7c10fa4d33fc6e264c1198b2038a216559bec962
\ 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 ff33850..5b79980 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 @@
-7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
+ab93fa5646ab5e2bc63922ee8f6c6d7657f128fe7b5426df97d02f19c770a1bc
\ 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 ff33850..5b79980 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 @@
-7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
+ab93fa5646ab5e2bc63922ee8f6c6d7657f128fe7b5426df97d02f19c770a1bc
\ 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 2fe4afb..d806076 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 @@
-b3f9edabe8db232b481a7484c5230fa08d01f37336f9e60eaf6fbe8e8d0ded16
\ No newline at end of file
+2dc0e3ade667e7578fa6b5b8911177ab272300bfddb015c4979c3b4361d93047
\ 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 92f9c01..a0ddb77 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 @@
-1bcbdbf6d1c2c1c2e77faa90be1c060b350f21472f67aed9477e6ba5e5219e81
\ No newline at end of file
+47cda8e8a9ed007945bff13d7c10fa4d33fc6e264c1198b2038a216559bec962
\ 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 ff33850..5b79980 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 @@
-7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
+ab93fa5646ab5e2bc63922ee8f6c6d7657f128fe7b5426df97d02f19c770a1bc
\ 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 ff33850..5b79980 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 @@
-7d8429af94229b4cb96f3e7691e987b4eb0ade9683acce9a2c14c41777415d73
\ No newline at end of file
+ab93fa5646ab5e2bc63922ee8f6c6d7657f128fe7b5426df97d02f19c770a1bc
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/parser/android/protolog.textproto b/test/trace_processor/diff_tests/parser/android/protolog.textproto
index 4ab660d..6e65ffd 100644
--- a/test/trace_processor/diff_tests/parser/android/protolog.textproto
+++ b/test/trace_processor/diff_tests/parser/android/protolog.textproto
@@ -20,15 +20,27 @@
packet {
trusted_uid: 1000
trusted_packet_sequence_id: 2
+ interned_data {
+ protolog_stacktrace {
+ iid: 1
+ str: "A STACK TRACE"
+ }
+ }
+ trusted_pid: 1716
+}
+packet {
+ trusted_uid: 1000
+ trusted_packet_sequence_id: 2
sequence_flags: 2
trusted_pid: 1716
timestamp: 857384100
protolog_message {
message_id: 6924537961316301726
- interned_str_params: 1
+ str_param_iids: 1
sint64_params: 888
double_params: 8.88
boolean_params: 1
+ stacktrace_iid: 1
}
}
packet {
@@ -83,10 +95,10 @@
timestamp: 857384130
protolog_message {
message_id: 9274895847396301003
- interned_str_params: 1
- interned_str_params: 1
- interned_str_params: 2
- interned_str_params: 1
+ str_param_iids: 1
+ str_param_iids: 1
+ str_param_iids: 2
+ str_param_iids: 1
}
}
packet {
diff --git a/test/trace_processor/diff_tests/parser/android/tests_protolog.py b/test/trace_processor/diff_tests/parser/android/tests_protolog.py
index 6db8cfe..404f34e 100644
--- a/test/trace_processor/diff_tests/parser/android/tests_protolog.py
+++ b/test/trace_processor/diff_tests/parser/android/tests_protolog.py
@@ -24,10 +24,10 @@
def test_has_expected_protolog_rows(self):
return DiffTestBlueprint(
trace=Path('protolog.textproto'),
- query="SELECT id, ts, level, tag, message FROM protolog;",
+ query="SELECT id, ts, level, tag, message, stacktrace FROM protolog;",
out=Csv("""
- "id","ts","level","tag","message"
- 0,857384100,"DEBUG","MyFirstGroup","Test message with a string (MyTestString), an int (1776), a double 8.88, and a boolean true."
- 1,857384110,"WARN","MySecondGroup","Test message with different int formats: 1776, 0o3360, 0x6f0, 888.000000, 8.880000e+02."
- 2,857384130,"ERROR","MyThirdGroup","Message re-using interned string 'MyOtherTestString' == 'MyOtherTestString', but 'SomeOtherTestString' != 'MyOtherTestString'"
+ "id","ts","level","tag","message","stacktrace"
+ 0,857384100,"DEBUG","MyFirstGroup","Test message with a string (MyTestString), an int (1776), a double 8.88, and a boolean true.","A STACK TRACE"
+ 1,857384110,"WARN","MySecondGroup","Test message with different int formats: 1776, 0o3360, 0x6f0, 888.000000, 8.880000e+02.","[NULL]"
+ 2,857384130,"ERROR","MyThirdGroup","Message re-using interned string 'MyOtherTestString' == 'MyOtherTestString', but 'SomeOtherTestString' != 'MyOtherTestString'","[NULL]"
"""))
diff --git a/test/trace_processor/diff_tests/parser/parsing/android_sched_and_ps_stats.out b/test/trace_processor/diff_tests/parser/parsing/android_sched_and_ps_stats.out
index 17268dc..e1542c5 100644
--- a/test/trace_processor/diff_tests/parser/parsing/android_sched_and_ps_stats.out
+++ b/test/trace_processor/diff_tests/parser/parsing/android_sched_and_ps_stats.out
@@ -143,14 +143,14 @@
"ftrace_cpu_overrun_end",5,"info","trace",0
"ftrace_cpu_overrun_end",6,"info","trace",0
"ftrace_cpu_overrun_end",7,"info","trace",0
-"ftrace_cpu_overrun_delta",0,"data_loss","trace",0
-"ftrace_cpu_overrun_delta",1,"data_loss","trace",0
-"ftrace_cpu_overrun_delta",2,"data_loss","trace",0
-"ftrace_cpu_overrun_delta",3,"data_loss","trace",0
-"ftrace_cpu_overrun_delta",4,"data_loss","trace",0
-"ftrace_cpu_overrun_delta",5,"data_loss","trace",0
-"ftrace_cpu_overrun_delta",6,"data_loss","trace",0
-"ftrace_cpu_overrun_delta",7,"data_loss","trace",0
+"ftrace_cpu_overrun_delta",0,"info","trace",0
+"ftrace_cpu_overrun_delta",1,"info","trace",0
+"ftrace_cpu_overrun_delta",2,"info","trace",0
+"ftrace_cpu_overrun_delta",3,"info","trace",0
+"ftrace_cpu_overrun_delta",4,"info","trace",0
+"ftrace_cpu_overrun_delta",5,"info","trace",0
+"ftrace_cpu_overrun_delta",6,"info","trace",0
+"ftrace_cpu_overrun_delta",7,"info","trace",0
"ftrace_cpu_read_events_begin",0,"info","trace",0
"ftrace_cpu_read_events_begin",1,"info","trace",0
"ftrace_cpu_read_events_begin",2,"info","trace",0
diff --git a/test/trace_processor/diff_tests/stdlib/android/tests.py b/test/trace_processor/diff_tests/stdlib/android/tests.py
index 23ae137..897fe4f 100644
--- a/test/trace_processor/diff_tests/stdlib/android/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/tests.py
@@ -1255,3 +1255,25 @@
1737069091010,3467799559,975,"cached_app_lmk_first","com.android.packageinstaller",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
1737069240534,3467650035,985,"cached_app_lmk_first","com.android.managedprovisioning",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
"""))
+
+ def test_broadcast_minsdk_u(self):
+ return DiffTestBlueprint(
+ trace=DataPath('freezer_trace.atr'),
+ query="""
+ INCLUDE PERFETTO MODULE android.broadcasts;
+ SELECT intent_action, process_name, pid, queue_id, ts, dur FROM _android_broadcasts_minsdk_u
+ ORDER BY ts LIMIT 10
+ """,
+ out=Csv("""
+ "intent_action","process_name","pid","queue_id","ts","dur"
+ "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED","system",2519,0,91286297271477,221619
+ "android.intent.action.TIME_TICK","com.android.systemui",2762,0,91295942589896,469216
+ "android.intent.action.TIME_TICK","com.android.systemui",2762,0,91295943366025,313104
+ "android.intent.action.TIME_TICK","com.android.systemui",2762,0,91295943943713,356194
+ "android.intent.action.TIME_TICK","com.android.systemui",2762,0,91355941417856,444189
+ "android.intent.action.TIME_TICK","com.android.systemui",2762,0,91355942543001,405369
+ "android.intent.action.TIME_TICK","com.android.systemui",2762,0,91355943262781,339640
+ "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION","system",2519,0,91359865607938,862534
+ "android.content.pm.action.SESSION_COMMITTED","com.android.launcher3",3219,0,91360380556725,15221753
+ "android.intent.action.PACKAGE_ADDED","system",2519,0,91360396877398,107502
+ """))
diff --git a/tools/install-build-deps b/tools/install-build-deps
index d1efa23..b27e8ea 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -221,8 +221,8 @@
# From https://github.com/ianlancetaylor/libbacktrace/archive/177940370e4a6b2509e92a0aaa9749184e64af43.zip
Dependency(
'buildtools/libbacktrace.zip',
- 'https://storage.googleapis.com/perfetto/libbacktrace-177940370e4a6b2509e92a0aaa9749184e64af43.zip',
- '21ac9a4209f7aeef766c482be53a7fa365063c031c7077e2070b491202983b31',
+ 'https://storage.googleapis.com/perfetto/libbacktrace-14818b7783eeb9a56c3f0fca78cefd3143f8c5f6.zip',
+ '0d09295938155aa84d9a6049f63df8cd2def3a28302b3550ea3ead9100b3d086',
'all', 'all'),
# Sqlite for the trace processing library.
diff --git a/ui/release/channels.json b/ui/release/channels.json
index 8e7a8cf..778c4d8 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -6,7 +6,7 @@
},
{
"name": "canary",
- "rev": "ed568855bbbfffe3fb099cd5f3d0096f1e4aa268"
+ "rev": "f62b11e6b5d34d0b0f1af3d60eb4d40a57b652b6"
},
{
"name": "autopush",