Use Chrome's TrackEvent extensions in trace processor
Bug: 173607375
Change-Id: I4637fa88bc55a8f1ccc96c301a3231c11f9ea7e6
diff --git a/Android.bp b/Android.bp
index a8f0d8c..d2eefc3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -6324,6 +6324,44 @@
],
}
+// GN: //protos/third_party/chromium:chrome_track_event_descriptor
+genrule {
+ name: "perfetto_protos_third_party_chromium_chrome_track_event_descriptor",
+ srcs: [
+ "protos/perfetto/trace/track_event/chrome_application_state_info.proto",
+ "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.proto",
+ "protos/perfetto/trace/track_event/chrome_frame_reporter.proto",
+ "protos/perfetto/trace/track_event/chrome_histogram_sample.proto",
+ "protos/perfetto/trace/track_event/chrome_keyed_service.proto",
+ "protos/perfetto/trace/track_event/chrome_latency_info.proto",
+ "protos/perfetto/trace/track_event/chrome_legacy_ipc.proto",
+ "protos/perfetto/trace/track_event/chrome_message_pump.proto",
+ "protos/perfetto/trace/track_event/chrome_mojo_event_info.proto",
+ "protos/perfetto/trace/track_event/chrome_process_descriptor.proto",
+ "protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.proto",
+ "protos/perfetto/trace/track_event/chrome_thread_descriptor.proto",
+ "protos/perfetto/trace/track_event/chrome_user_event.proto",
+ "protos/perfetto/trace/track_event/chrome_window_handle_event_info.proto",
+ "protos/perfetto/trace/track_event/counter_descriptor.proto",
+ "protos/perfetto/trace/track_event/debug_annotation.proto",
+ "protos/perfetto/trace/track_event/log_message.proto",
+ "protos/perfetto/trace/track_event/process_descriptor.proto",
+ "protos/perfetto/trace/track_event/source_location.proto",
+ "protos/perfetto/trace/track_event/task_execution.proto",
+ "protos/perfetto/trace/track_event/thread_descriptor.proto",
+ "protos/perfetto/trace/track_event/track_descriptor.proto",
+ "protos/perfetto/trace/track_event/track_event.proto",
+ "protos/third_party/chromium/chrome_track_event.proto",
+ ],
+ tools: [
+ "aprotoc",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --descriptor_set_out=$(out) $(in)",
+ out: [
+ "perfetto_protos_third_party_chromium_chrome_track_event_descriptor.bin",
+ ],
+}
+
// GN: //protos/third_party/pprof:zero
genrule {
name: "perfetto_protos_third_party_pprof_zero_gen",
@@ -7288,6 +7326,21 @@
],
}
+// GN: //src/trace_processor/importers:gen_cc_chrome_track_event_descriptor
+genrule {
+ name: "perfetto_src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
+ srcs: [
+ ":perfetto_protos_third_party_chromium_chrome_track_event_descriptor",
+ ],
+ cmd: "$(location tools/gen_cc_proto_descriptor.py) --gen_dir=$(genDir) --cpp_out=$(out) $(in)",
+ out: [
+ "src/trace_processor/importers/chrome_track_event.descriptor.h",
+ ],
+ tool_files: [
+ "tools/gen_cc_proto_descriptor.py",
+ ],
+}
+
// GN: //src/trace_processor/importers:gen_cc_config_descriptor
genrule {
name: "perfetto_src_trace_processor_importers_gen_cc_config_descriptor",
@@ -8753,6 +8806,7 @@
"perfetto_src_protozero_testing_messages_cpp_gen_headers",
"perfetto_src_protozero_testing_messages_lite_gen_headers",
"perfetto_src_protozero_testing_messages_zero_gen_headers",
+ "perfetto_src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
"perfetto_src_trace_processor_importers_gen_cc_config_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
@@ -8907,6 +8961,7 @@
"perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
"perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
"perfetto_src_base_version_gen_h",
+ "perfetto_src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
"perfetto_src_trace_processor_importers_gen_cc_config_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
@@ -9061,6 +9116,7 @@
"perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
"perfetto_protos_third_party_pprof_zero_gen_headers",
"perfetto_src_base_version_gen_h",
+ "perfetto_src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
"perfetto_src_trace_processor_importers_gen_cc_config_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
diff --git a/BUILD b/BUILD
index 71a5ef7..20db6b0 100644
--- a/BUILD
+++ b/BUILD
@@ -825,6 +825,16 @@
)
perfetto_cc_proto_descriptor(
+ name = "src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
+ deps = [
+ ":protos_third_party_chromium_chrome_track_event_descriptor",
+ ],
+ outs = [
+ "src/trace_processor/importers/chrome_track_event.descriptor.h",
+ ],
+)
+
+perfetto_cc_proto_descriptor(
name = "src_trace_processor_importers_gen_cc_config_descriptor",
deps = [
":protos_perfetto_config_descriptor",
@@ -2967,6 +2977,31 @@
],
)
+# GN target: //protos/third_party/chromium:chrome_track_event_descriptor
+perfetto_proto_descriptor(
+ name = "protos_third_party_chromium_chrome_track_event_descriptor",
+ deps = [
+ ":protos_third_party_chromium_chrome_track_event_protos",
+ ],
+ outs = [
+ "protos_third_party_chromium_chrome_track_event_descriptor.bin",
+ ],
+)
+
+# GN target: //protos/third_party/chromium:chrome_track_event_descriptor
+perfetto_proto_library(
+ name = "protos_third_party_chromium_chrome_track_event_protos",
+ srcs = [
+ "protos/third_party/chromium/chrome_track_event.proto",
+ ],
+ visibility = [
+ PERFETTO_CONFIG.proto_library_visibility,
+ ],
+ deps = [
+ ":protos_perfetto_trace_track_event_protos",
+ ],
+)
+
# GN target: //protos/third_party/pprof:zero
perfetto_proto_library(
name = "protos_third_party_pprof_protos",
@@ -3241,6 +3276,7 @@
":protos_perfetto_trace_track_event_zero",
":protozero",
":src_base_base",
+ ":src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
":src_trace_processor_importers_gen_cc_config_descriptor",
":src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
":src_trace_processor_metrics_gen_cc_metrics_descriptor",
@@ -3331,6 +3367,7 @@
":protozero",
":src_base_base",
":src_base_unix_socket",
+ ":src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
":src_trace_processor_importers_gen_cc_config_descriptor",
":src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
":src_trace_processor_metrics_gen_cc_metrics_descriptor",
@@ -3508,6 +3545,7 @@
":protos_third_party_pprof_zero",
":protozero",
":src_base_base",
+ ":src_trace_processor_importers_gen_cc_chrome_track_event_descriptor",
":src_trace_processor_importers_gen_cc_config_descriptor",
":src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
":src_trace_processor_metrics_gen_cc_metrics_descriptor",
diff --git a/protos/third_party/chromium/BUILD.gn b/protos/third_party/chromium/BUILD.gn
new file mode 100644
index 0000000..6f9b5ab
--- /dev/null
+++ b/protos/third_party/chromium/BUILD.gn
@@ -0,0 +1,9 @@
+import("../../../gn/perfetto.gni")
+import("../../../gn/proto_library.gni")
+
+perfetto_proto_library("chrome_track_event_@TYPE@") {
+ proto_generators = [ "descriptor" ]
+ sources = [ "chrome_track_event.proto" ]
+ generate_descriptor = "chrome_track_event.descriptor"
+ deps = [ "../../perfetto/trace/track_event:source_set" ]
+}
diff --git a/protos/third_party/chromium/chrome_track_event.proto b/protos/third_party/chromium/chrome_track_event.proto
index 31cd53a..158715f 100644
--- a/protos/third_party/chromium/chrome_track_event.proto
+++ b/protos/third_party/chromium/chrome_track_event.proto
@@ -4,7 +4,7 @@
syntax = "proto2";
-import "third_party/perfetto/protos/perfetto/trace/track_event/track_event.proto";
+import public "protos/perfetto/trace/track_event/track_event.proto";
package perfetto.protos;
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 51a21ff..e0c00c4 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -145,6 +145,7 @@
"../protozero",
"containers",
"importers:common",
+ "importers:gen_cc_chrome_track_event_descriptor",
"importers/memory_tracker:graph_processor",
"storage",
"tables",
diff --git a/src/trace_processor/importers/BUILD.gn b/src/trace_processor/importers/BUILD.gn
index f01421f..7d728ae 100644
--- a/src/trace_processor/importers/BUILD.gn
+++ b/src/trace_processor/importers/BUILD.gn
@@ -95,3 +95,24 @@
outputs = [ generated_header ]
public_configs = [ ":gen_config" ]
}
+
+action("gen_cc_chrome_track_event_descriptor") {
+ descriptor_target =
+ "../../../protos/third_party/chromium:chrome_track_event_descriptor"
+ generated_header = "${target_gen_dir}/chrome_track_event.descriptor.h"
+
+ descriptor_file_path = get_label_info(descriptor_target, "target_gen_dir") +
+ "/chrome_track_event.descriptor"
+
+ script = "../../../tools/gen_cc_proto_descriptor.py"
+ deps = [ descriptor_target ]
+ args = [
+ "--gen_dir",
+ rebase_path(root_gen_dir, root_build_dir),
+ "--cpp_out",
+ rebase_path(generated_header, root_build_dir),
+ rebase_path(descriptor_file_path, root_build_dir),
+ ]
+ inputs = [ descriptor_file_path ]
+ outputs = [ generated_header ]
+}
diff --git a/src/trace_processor/importers/proto/args_table_utils.cc b/src/trace_processor/importers/proto/args_table_utils.cc
index 3db5899..d7e365c 100644
--- a/src/trace_processor/importers/proto/args_table_utils.cc
+++ b/src/trace_processor/importers/proto/args_table_utils.cc
@@ -36,9 +36,11 @@
util::Status ProtoToArgsTable::AddProtoFileDescriptor(
const uint8_t* proto_descriptor_array,
- size_t proto_descriptor_array_size) {
+ size_t proto_descriptor_array_size,
+ bool merge_existing_messages) {
return pool_.AddFromFileDescriptorSet(proto_descriptor_array,
- proto_descriptor_array_size);
+ proto_descriptor_array_size,
+ merge_existing_messages);
}
util::Status ProtoToArgsTable::InternProtoFieldsIntoArgsTable(
@@ -59,17 +61,16 @@
protozero::ProtoDecoder decoder(cb);
for (protozero::Field f = decoder.ReadField(); f.valid();
f = decoder.ReadField()) {
- auto field_idx = descriptor.FindFieldIdxByTag(f.id());
- if (!field_idx) {
+ auto field = descriptor.FindFieldByTag(f.id());
+ if (!field) {
// Unknown field, possibly an unknown extension.
continue;
}
- auto field = descriptor.fields()[*field_idx];
// If allowlist is not provided, reflect all fields. Otherwise, check if the
// current field either an extension or is in allowlist.
bool is_allowed =
- field.is_extension() || fields == nullptr ||
+ field->is_extension() || !fields ||
std::find(fields->begin(), fields->end(), f.id()) != fields->end();
if (!is_allowed) {
@@ -79,8 +80,8 @@
}
ParsingOverrideState state{context_, sequence_state};
RETURN_IF_ERROR(InternFieldIntoArgsTable(
- field, repeated_field_index[f.id()], state, inserter, f));
- if (field.is_repeated()) {
+ *field, repeated_field_index[f.id()], state, inserter, f));
+ if (field->is_repeated()) {
repeated_field_index[f.id()]++;
}
}
@@ -150,29 +151,25 @@
}
auto proto_descriptor = pool_.descriptors()[*opt_proto_descriptor_idx];
- // For repeated fields, contains mapping from field descriptor index to
- // current count of how many fields have been serialized with this field.
+ // For repeated fields, contains mapping from numeric field ID to
+ // current count of how many values have been serialized with this field.
std::unordered_map<size_t, int> repeated_field_index;
// Parse this message field by field until there are no bytes left.
protozero::ProtoDecoder decoder(cb.data, cb.size);
for (auto field = decoder.ReadField(); field.valid();
field = decoder.ReadField()) {
- auto opt_field_descriptor_idx =
- proto_descriptor.FindFieldIdxByTag(field.id());
- if (!opt_field_descriptor_idx) {
+ auto field_descriptor = proto_descriptor.FindFieldByTag(field.id());
+ if (!field_descriptor) {
// Since the binary descriptor is compiled in it is possible we're seeing
// a new message that our descriptors don't have. Just skip the field.
continue;
}
- const auto& field_descriptor =
- proto_descriptor.fields()[*opt_field_descriptor_idx];
-
- InternFieldIntoArgsTable(field_descriptor,
- repeated_field_index[*opt_field_descriptor_idx],
- state, inserter, field);
- if (field_descriptor.is_repeated()) {
- repeated_field_index[*opt_field_descriptor_idx]++;
+ InternFieldIntoArgsTable(*field_descriptor,
+ repeated_field_index[field.id()], state, inserter,
+ field);
+ if (field_descriptor->is_repeated()) {
+ repeated_field_index[field.id()]++;
}
}
PERFETTO_DCHECK(decoder.bytes_left() == 0);
diff --git a/src/trace_processor/importers/proto/args_table_utils.h b/src/trace_processor/importers/proto/args_table_utils.h
index 88e00b2..10b6cd1 100644
--- a/src/trace_processor/importers/proto/args_table_utils.h
+++ b/src/trace_processor/importers/proto/args_table_utils.h
@@ -110,7 +110,8 @@
// listed in the event_list file. You can then find your variable inside the
// header location specified inside that python script.
util::Status AddProtoFileDescriptor(const uint8_t* proto_descriptor_array,
- size_t proto_descriptor_array_size);
+ size_t proto_descriptor_array_size,
+ bool merge_existing_messages = false);
// Given a view of bytes that represent a serialized protozero message of
// |type| we will parse each field into the Args table using RowId |row|.
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index e2b1cde..1fbd37b 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -67,8 +67,9 @@
descriptor.size);
auto extension = decoder.extension_set();
- return context_->proto_to_args_table_->AddProtoFileDescriptor(extension.data,
- extension.size);
+ return context_->proto_to_args_table_->AddProtoFileDescriptor(
+ extension.data, extension.size,
+ /*merge_existing_messages=*/true);
}
util::Status ProtoTraceReader::ParsePacket(TraceBlobView packet) {
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 019d878..89ca206 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -22,6 +22,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/string_writer.h"
#include "perfetto/trace_processor/status.h"
+#include "src/trace_processor/importers/chrome_track_event.descriptor.h"
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/flow_tracker.h"
@@ -1325,6 +1326,11 @@
PERFETTO_DCHECK(status.ok());
+ status = context_->proto_to_args_table_->AddProtoFileDescriptor(
+ kChromeTrackEventDescriptor.data(), kChromeTrackEventDescriptor.size());
+
+ PERFETTO_DCHECK(status.ok());
+
// Switch |source_location_iid| into its interned data variant.
context_->proto_to_args_table_->AddParsingOverride(
"begin_impl_frame_args.current_args.source_location_iid",
diff --git a/src/trace_processor/metrics/metrics.cc b/src/trace_processor/metrics/metrics.cc
index 3e7ac8f..be21ada 100644
--- a/src/trace_processor/metrics/metrics.cc
+++ b/src/trace_processor/metrics/metrics.cc
@@ -97,43 +97,43 @@
util::Status ProtoBuilder::AppendLong(const std::string& field_name,
int64_t value,
bool is_inside_repeated) {
- auto field_idx = descriptor_->FindFieldIdxByName(field_name);
- if (!field_idx.has_value()) {
+ auto field = descriptor_->FindFieldByName(field_name);
+ if (!field) {
return util::ErrStatus("Field with name %s not found in proto type %s",
field_name.c_str(),
descriptor_->full_name().c_str());
}
using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
- const auto& field = descriptor_->fields()[field_idx.value()];
- if (field.is_repeated() && !is_inside_repeated) {
+ if (field->is_repeated() && !is_inside_repeated) {
return util::ErrStatus(
"Unexpected long value for repeated field %s in proto type %s",
field_name.c_str(), descriptor_->full_name().c_str());
}
- switch (field.type()) {
+ switch (field->type()) {
case FieldDescriptorProto::TYPE_INT32:
case FieldDescriptorProto::TYPE_INT64:
case FieldDescriptorProto::TYPE_UINT32:
case FieldDescriptorProto::TYPE_BOOL:
- message_->AppendVarInt(field.number(), value);
+ message_->AppendVarInt(field->number(), value);
break;
case FieldDescriptorProto::TYPE_SINT32:
case FieldDescriptorProto::TYPE_SINT64:
- message_->AppendSignedVarInt(field.number(), value);
+ message_->AppendSignedVarInt(field->number(), value);
break;
case FieldDescriptorProto::TYPE_FIXED32:
case FieldDescriptorProto::TYPE_SFIXED32:
case FieldDescriptorProto::TYPE_FIXED64:
case FieldDescriptorProto::TYPE_SFIXED64:
- message_->AppendFixed(field.number(), value);
+ message_->AppendFixed(field->number(), value);
break;
default: {
return util::ErrStatus(
"Tried to write value of type long into field %s (in proto type %s) "
"which has type %d",
- field.name().c_str(), descriptor_->full_name().c_str(), field.type());
+ field->name().c_str(), descriptor_->full_name().c_str(),
+ field->type());
}
}
return util::OkStatus();
@@ -142,28 +142,27 @@
util::Status ProtoBuilder::AppendDouble(const std::string& field_name,
double value,
bool is_inside_repeated) {
- auto field_idx = descriptor_->FindFieldIdxByName(field_name);
- if (!field_idx.has_value()) {
+ auto field = descriptor_->FindFieldByName(field_name);
+ if (!field) {
return util::ErrStatus("Field with name %s not found in proto type %s",
field_name.c_str(),
descriptor_->full_name().c_str());
}
using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
- const auto& field = descriptor_->fields()[field_idx.value()];
- if (field.is_repeated() && !is_inside_repeated) {
+ if (field->is_repeated() && !is_inside_repeated) {
return util::ErrStatus(
"Unexpected double value for repeated field %s in proto type %s",
field_name.c_str(), descriptor_->full_name().c_str());
}
- switch (field.type()) {
+ switch (field->type()) {
case FieldDescriptorProto::TYPE_FLOAT:
case FieldDescriptorProto::TYPE_DOUBLE: {
- if (field.type() == FieldDescriptorProto::TYPE_FLOAT) {
- message_->AppendFixed(field.number(), static_cast<float>(value));
+ if (field->type() == FieldDescriptorProto::TYPE_FLOAT) {
+ message_->AppendFixed(field->number(), static_cast<float>(value));
} else {
- message_->AppendFixed(field.number(), value);
+ message_->AppendFixed(field->number(), value);
}
break;
}
@@ -171,7 +170,8 @@
return util::ErrStatus(
"Tried to write value of type double into field %s (in proto type "
"%s) which has type %d",
- field.name().c_str(), descriptor_->full_name().c_str(), field.type());
+ field->name().c_str(), descriptor_->full_name().c_str(),
+ field->type());
}
}
return util::OkStatus();
@@ -180,31 +180,31 @@
util::Status ProtoBuilder::AppendString(const std::string& field_name,
base::StringView data,
bool is_inside_repeated) {
- auto field_idx = descriptor_->FindFieldIdxByName(field_name);
- if (!field_idx.has_value()) {
+ const FieldDescriptor* field = descriptor_->FindFieldByName(field_name);
+ if (!field) {
return util::ErrStatus("Field with name %s not found in proto type %s",
field_name.c_str(),
descriptor_->full_name().c_str());
}
using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
- const auto& field = descriptor_->fields()[field_idx.value()];
- if (field.is_repeated() && !is_inside_repeated) {
+ if (field->is_repeated() && !is_inside_repeated) {
return util::ErrStatus(
"Unexpected string value for repeated field %s in proto type %s",
field_name.c_str(), descriptor_->full_name().c_str());
}
- switch (field.type()) {
+ switch (field->type()) {
case FieldDescriptorProto::TYPE_STRING: {
- message_->AppendBytes(field.number(), data.data(), data.size());
+ message_->AppendBytes(field->number(), data.data(), data.size());
break;
}
default: {
return util::ErrStatus(
"Tried to write value of type string into field %s (in proto type "
"%s) which has type %d",
- field.name().c_str(), descriptor_->full_name().c_str(), field.type());
+ field->name().c_str(), descriptor_->full_name().c_str(),
+ field->type());
}
}
return util::OkStatus();
@@ -214,20 +214,19 @@
const uint8_t* ptr,
size_t size,
bool is_inside_repeated) {
- auto field_idx = descriptor_->FindFieldIdxByName(field_name);
- if (!field_idx.has_value()) {
+ const FieldDescriptor* field = descriptor_->FindFieldByName(field_name);
+ if (!field) {
return util::ErrStatus("Field with name %s not found in proto type %s",
field_name.c_str(),
descriptor_->full_name().c_str());
}
using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
- const auto& field = descriptor_->fields()[field_idx.value()];
- if (field.is_repeated() && !is_inside_repeated)
- return AppendRepeated(field, ptr, size);
+ if (field->is_repeated() && !is_inside_repeated)
+ return AppendRepeated(*field, ptr, size);
- if (field.type() == FieldDescriptorProto::TYPE_MESSAGE)
- return AppendSingleMessage(field, ptr, size);
+ if (field->type() == FieldDescriptorProto::TYPE_MESSAGE)
+ return AppendSingleMessage(*field, ptr, size);
if (size == 0) {
return util::ErrStatus(
@@ -235,13 +234,13 @@
"Nulls are only supported for message protos; all other types should"
"ensure that nulls are not passed to proto builder functions by using"
"the SQLite IFNULL/COALESCE functions.",
- field.name().c_str(), descriptor_->full_name().c_str());
+ field->name().c_str(), descriptor_->full_name().c_str());
}
return util::ErrStatus(
"Tried to write value of type bytes into field %s (in proto type %s) "
"which has type %d",
- field.name().c_str(), descriptor_->full_name().c_str(), field.type());
+ field->name().c_str(), descriptor_->full_name().c_str(), field->type());
}
util::Status ProtoBuilder::AppendSingleMessage(const FieldDescriptor& field,
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 1fc79f6..567aa7e 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -930,9 +930,8 @@
pool_.FindDescriptorIdx(".perfetto.protos.TraceMetrics");
if (!desc_idx.has_value())
return false;
- base::Optional<uint32_t> field_idx =
- pool_.descriptors()[*desc_idx].FindFieldIdxByName(metric_name);
- return field_idx.has_value();
+ auto field_idx = pool_.descriptors()[*desc_idx].FindFieldByName(metric_name);
+ return field_idx != nullptr;
}
util::Status TraceProcessorImpl::RegisterMetric(const std::string& path,
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index efd3557..f497b43 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -44,6 +44,7 @@
"descriptors.h",
]
deps = [
+ ":util",
"..:track_event_descriptor",
"../../../gn:default_deps",
"../../../include/perfetto/trace_processor",
diff --git a/src/trace_processor/util/descriptors.cc b/src/trace_processor/util/descriptors.cc
index 55bc525..d99b0e2 100644
--- a/src/trace_processor/util/descriptors.cc
+++ b/src/trace_processor/util/descriptors.cc
@@ -20,6 +20,7 @@
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "protos/perfetto/common/descriptor.pbzero.h"
#include "protos/perfetto/trace_processor/trace_processor.pbzero.h"
+#include "src/trace_processor/util/status_macros.h"
namespace perfetto {
namespace trace_processor {
@@ -86,26 +87,13 @@
return util::OkStatus();
}
-void DescriptorPool::CheckPreviousDefinition(
- const std::string& file_name,
- const std::string& descriptor_name) {
- auto prev_idx = FindDescriptorIdx(descriptor_name);
- if (prev_idx.has_value()) {
- auto prev_file = descriptors_[*prev_idx].file_name();
- // We should already make sure we process each file once, so if we're
- // hitting this path, it means the same message was defined in multiple
- // files.
- PERFETTO_FATAL("%s: %s was already defined in file %s", file_name.c_str(),
- descriptor_name.c_str(), prev_file.c_str());
- }
-}
-
-void DescriptorPool::AddNestedProtoDescriptors(
+util::Status DescriptorPool::AddNestedProtoDescriptors(
const std::string& file_name,
const std::string& package_name,
base::Optional<uint32_t> parent_idx,
protozero::ConstBytes descriptor_proto,
- std::vector<ExtensionInfo>* extensions) {
+ std::vector<ExtensionInfo>* extensions,
+ bool merge_existing_messages) {
protos::pbzero::DescriptorProto::Decoder decoder(descriptor_proto);
auto parent_name =
@@ -113,34 +101,70 @@
auto full_name =
parent_name + "." + base::StringView(decoder.name()).ToStdString();
- CheckPreviousDefinition(file_name, full_name);
+ auto prev_idx = FindDescriptorIdx(full_name);
+ if (prev_idx.has_value() && !merge_existing_messages) {
+ const auto& existing_descriptor = descriptors_[*prev_idx];
+ return util::ErrStatus("%s: %s was already defined in file %s",
+ file_name.c_str(), full_name.c_str(),
+ existing_descriptor.file_name().c_str());
+ }
+ if (!prev_idx.has_value()) {
+ prev_idx = static_cast<unsigned int>(descriptors_.size());
+ ProtoDescriptor proto_descriptor(file_name, package_name, full_name,
+ ProtoDescriptor::Type::kMessage,
+ parent_idx);
+ descriptors_.emplace_back(std::move(proto_descriptor));
+ }
+ ProtoDescriptor& proto_descriptor = descriptors_[*prev_idx];
+ if (proto_descriptor.type() != ProtoDescriptor::Type::kMessage) {
+ return util::ErrStatus("%s was enum, redefined as message",
+ full_name.c_str());
+ }
using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
- ProtoDescriptor proto_descriptor(file_name, package_name, full_name,
- ProtoDescriptor::Type::kMessage, parent_idx);
for (auto it = decoder.field(); it; ++it) {
FieldDescriptorProto::Decoder f_decoder(*it);
- proto_descriptor.AddField(CreateFieldFromDecoder(f_decoder, false));
+ auto field = CreateFieldFromDecoder(f_decoder, /*is_extension=*/false);
+ auto existing_field = proto_descriptor.FindFieldByTag(field.number());
+ if (!existing_field) {
+ proto_descriptor.AddField(std::move(field));
+ } else {
+ if (field.type() != existing_field->type()) {
+ return util::ErrStatus("Field %s is re-introduced with different type",
+ field.name().c_str());
+ }
+ if (field.type() == FieldDescriptorProto::TYPE_MESSAGE &&
+ field.resolved_type_name() != existing_field->resolved_type_name()) {
+ return util::ErrStatus(
+ "Field %s is re-introduced with different type %s (was %s)",
+ field.name().c_str(), field.resolved_type_name().c_str(),
+ existing_field->resolved_type_name().c_str());
+ }
+ }
}
- descriptors_.emplace_back(std::move(proto_descriptor));
auto idx = static_cast<uint32_t>(descriptors_.size()) - 1;
for (auto it = decoder.enum_type(); it; ++it) {
- AddEnumProtoDescriptors(file_name, package_name, idx, *it);
+ AddEnumProtoDescriptors(file_name, package_name, idx, *it,
+ merge_existing_messages);
}
for (auto it = decoder.nested_type(); it; ++it) {
- AddNestedProtoDescriptors(file_name, package_name, idx, *it, extensions);
+ RETURN_IF_ERROR(AddNestedProtoDescriptors(file_name, package_name, idx, *it,
+ extensions,
+ merge_existing_messages));
}
for (auto ext_it = decoder.extension(); ext_it; ++ext_it) {
extensions->emplace_back(package_name, *ext_it);
}
+ return util::OkStatus();
}
-void DescriptorPool::AddEnumProtoDescriptors(
+util::Status DescriptorPool::AddEnumProtoDescriptors(
const std::string& file_name,
const std::string& package_name,
base::Optional<uint32_t> parent_idx,
- protozero::ConstBytes descriptor_proto) {
+ protozero::ConstBytes descriptor_proto,
+ bool merge_existing_messages) {
protos::pbzero::EnumDescriptorProto::Decoder decoder(descriptor_proto);
auto parent_name =
@@ -148,22 +172,40 @@
auto full_name =
parent_name + "." + base::StringView(decoder.name()).ToStdString();
- CheckPreviousDefinition(file_name, full_name);
+ auto prev_idx = FindDescriptorIdx(full_name);
+ if (prev_idx.has_value() && !merge_existing_messages) {
+ const auto& existing_descriptor = descriptors_[*prev_idx];
+ return util::ErrStatus("%s: %s was already defined in file %s",
+ file_name.c_str(), full_name.c_str(),
+ existing_descriptor.file_name().c_str());
+ }
+ if (!prev_idx.has_value()) {
+ prev_idx = static_cast<unsigned int>(descriptors_.size());
+ ProtoDescriptor proto_descriptor(file_name, package_name, full_name,
+ ProtoDescriptor::Type::kEnum,
+ base::nullopt);
+ descriptors_.emplace_back(std::move(proto_descriptor));
+ }
+ ProtoDescriptor& proto_descriptor = descriptors_[*prev_idx];
+ if (proto_descriptor.type() != ProtoDescriptor::Type::kEnum) {
+ return util::ErrStatus("%s was message, redefined as enum",
+ full_name.c_str());
+ }
- ProtoDescriptor proto_descriptor(file_name, package_name, full_name,
- ProtoDescriptor::Type::kEnum, base::nullopt);
for (auto it = decoder.value(); it; ++it) {
protos::pbzero::EnumValueDescriptorProto::Decoder enum_value(it->data(),
it->size());
proto_descriptor.AddEnumValue(enum_value.number(),
enum_value.name().ToStdString());
}
- descriptors_.emplace_back(std::move(proto_descriptor));
+
+ return util::OkStatus();
}
util::Status DescriptorPool::AddFromFileDescriptorSet(
const uint8_t* file_descriptor_set_proto,
- size_t size) {
+ size_t size,
+ bool merge_existing_messages) {
// First pass: extract all the message descriptors from the file and add them
// to the pool.
protos::pbzero::FileDescriptorSet::Decoder proto(file_descriptor_set_proto,
@@ -179,11 +221,13 @@
processed_files_.insert(file_name);
std::string package = "." + base::StringView(file.package()).ToStdString();
for (auto message_it = file.message_type(); message_it; ++message_it) {
- AddNestedProtoDescriptors(file_name, package, base::nullopt, *message_it,
- &extensions);
+ RETURN_IF_ERROR(AddNestedProtoDescriptors(
+ file_name, package, base::nullopt, *message_it, &extensions,
+ merge_existing_messages));
}
for (auto enum_it = file.enum_type(); enum_it; ++enum_it) {
- AddEnumProtoDescriptors(file_name, package, base::nullopt, *enum_it);
+ AddEnumProtoDescriptors(file_name, package, base::nullopt, *enum_it,
+ merge_existing_messages);
}
for (auto ext_it = file.extension(); ext_it; ++ext_it) {
extensions.emplace_back(package, *ext_it);
@@ -200,7 +244,8 @@
// Third pass: resolve the types of all the fields to the correct indiices.
using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
for (auto& descriptor : descriptors_) {
- for (auto& field : *descriptor.mutable_fields()) {
+ for (auto& entry : *descriptor.mutable_fields()) {
+ auto& field = entry.second;
if (!field.resolved_type_name().empty())
continue;
@@ -238,7 +283,8 @@
protos::pbzero::DescriptorProto* proto_descriptor =
descs->add_descriptors();
proto_descriptor->set_name(desc.full_name());
- for (auto& field : desc.fields()) {
+ for (auto& entry : desc.fields()) {
+ auto& field = entry.second;
protos::pbzero::FieldDescriptorProto* field_descriptor =
proto_descriptor->add_field();
field_descriptor->set_name(field.name());
diff --git a/src/trace_processor/util/descriptors.h b/src/trace_processor/util/descriptors.h
index aac5d47..54a9ab1 100644
--- a/src/trace_processor/util/descriptors.h
+++ b/src/trace_processor/util/descriptors.h
@@ -20,6 +20,7 @@
#include <algorithm>
#include <set>
#include <string>
+#include <unordered_map>
#include <vector>
#include "perfetto/ext/base/optional.h"
@@ -81,42 +82,40 @@
void AddField(FieldDescriptor descriptor) {
PERFETTO_DCHECK(type_ == Type::kMessage);
- fields_.emplace_back(std::move(descriptor));
+ fields_.emplace(descriptor.number(), std::move(descriptor));
}
void AddEnumValue(int32_t integer_representation,
std::string string_representation) {
PERFETTO_DCHECK(type_ == Type::kEnum);
- enum_values_.emplace_back(integer_representation,
- std::move(string_representation));
+ enum_values_[integer_representation] = std::move(string_representation);
}
- base::Optional<uint32_t> FindFieldIdxByName(const std::string& name) const {
+ const FieldDescriptor* FindFieldByName(const std::string& name) const {
PERFETTO_DCHECK(type_ == Type::kMessage);
- auto it = std::find_if(
- fields_.begin(), fields_.end(),
- [name](const FieldDescriptor& desc) { return desc.name() == name; });
- auto idx = static_cast<uint32_t>(std::distance(fields_.begin(), it));
- return idx < fields_.size() ? base::Optional<uint32_t>(idx) : base::nullopt;
+ auto it =
+ std::find_if(fields_.begin(), fields_.end(),
+ [name](std::pair<int32_t, const FieldDescriptor&> p) {
+ return p.second.name() == name;
+ });
+ if (it == fields_.end()) {
+ return nullptr;
+ }
+ return &it->second;
}
- base::Optional<uint32_t> FindFieldIdxByTag(const uint16_t tag_number) const {
+ const FieldDescriptor* FindFieldByTag(const uint32_t tag_number) const {
PERFETTO_DCHECK(type_ == Type::kMessage);
- auto it = std::find_if(fields_.begin(), fields_.end(),
- [tag_number](const FieldDescriptor& desc) {
- return desc.number() == tag_number;
- });
- auto idx = static_cast<uint32_t>(std::distance(fields_.begin(), it));
- return idx < fields_.size() ? base::Optional<uint32_t>(idx) : base::nullopt;
+ auto it = fields_.find(tag_number);
+ if (it == fields_.end()) {
+ return nullptr;
+ }
+ return &it->second;
}
base::Optional<std::string> FindEnumString(const int32_t value) const {
PERFETTO_DCHECK(type_ == Type::kEnum);
- auto it =
- std::find_if(enum_values_.begin(), enum_values_.end(),
- [value](const std::pair<int32_t, std::string>& enum_val) {
- return enum_val.first == value;
- });
+ auto it = enum_values_.find(value);
return it == enum_values_.end() ? base::nullopt
: base::Optional<std::string>(it->second);
}
@@ -127,8 +126,14 @@
const std::string& full_name() const { return full_name_; }
- const std::vector<FieldDescriptor>& fields() const { return fields_; }
- std::vector<FieldDescriptor>* mutable_fields() { return &fields_; }
+ Type type() const { return type_; }
+
+ const std::unordered_map<uint32_t, FieldDescriptor>& fields() const {
+ return fields_;
+ }
+ std::unordered_map<uint32_t, FieldDescriptor>* mutable_fields() {
+ return &fields_;
+ }
private:
std::string file_name_; // File in which descriptor was originally defined.
@@ -136,8 +141,8 @@
std::string full_name_;
const Type type_;
base::Optional<uint32_t> parent_id_;
- std::vector<FieldDescriptor> fields_;
- std::vector<std::pair<int32_t, std::string>> enum_values_;
+ std::unordered_map<uint32_t, FieldDescriptor> fields_;
+ std::unordered_map<int32_t, std::string> enum_values_;
};
using ExtensionInfo = std::pair<std::string, protozero::ConstBytes>;
@@ -146,7 +151,8 @@
public:
util::Status AddFromFileDescriptorSet(
const uint8_t* file_descriptor_set_proto,
- size_t size);
+ size_t size,
+ bool merge_existing_messages = false);
base::Optional<uint32_t> FindDescriptorIdx(
const std::string& full_name) const;
@@ -158,18 +164,17 @@
std::vector<uint8_t> SerializeAsDescriptorSet();
private:
- void AddNestedProtoDescriptors(const std::string& file_name,
- const std::string& package_name,
- base::Optional<uint32_t> parent_idx,
- protozero::ConstBytes descriptor_proto,
- std::vector<ExtensionInfo>* extensions);
- void AddEnumProtoDescriptors(const std::string& file_name,
- const std::string& package_name,
- base::Optional<uint32_t> parent_idx,
- protozero::ConstBytes descriptor_proto);
-
- void CheckPreviousDefinition(const std::string& file_name,
- const std::string& descriptor_name);
+ util::Status AddNestedProtoDescriptors(const std::string& file_name,
+ const std::string& package_name,
+ base::Optional<uint32_t> parent_idx,
+ protozero::ConstBytes descriptor_proto,
+ std::vector<ExtensionInfo>* extensions,
+ bool merge_existing_messages);
+ util::Status AddEnumProtoDescriptors(const std::string& file_name,
+ const std::string& package_name,
+ base::Optional<uint32_t> parent_idx,
+ protozero::ConstBytes descriptor_proto,
+ bool merge_existing_messages);
util::Status AddExtensionField(const std::string& package_name,
protozero::ConstBytes field_desc_proto);
diff --git a/src/trace_processor/util/protozero_to_text.cc b/src/trace_processor/util/protozero_to_text.cc
index df7deb8..47702ed 100644
--- a/src/trace_processor/util/protozero_to_text.cc
+++ b/src/trace_processor/util/protozero_to_text.cc
@@ -172,16 +172,14 @@
protozero::ProtoDecoder decoder(protobytes.data, protobytes.size);
for (auto field = decoder.ReadField(); field.valid();
field = decoder.ReadField()) {
- auto opt_field_descriptor_idx =
- proto_descriptor.FindFieldIdxByTag(field.id());
- if (!opt_field_descriptor_idx) {
+ auto opt_field_descriptor = proto_descriptor.FindFieldByTag(field.id());
+ if (!opt_field_descriptor) {
StrAppend(
output, output->empty() ? "" : "\n", *indents,
"# Ignoring unknown field with id: ", std::to_string(field.id()));
continue;
}
- const auto& field_descriptor =
- proto_descriptor.fields()[*opt_field_descriptor_idx];
+ const auto& field_descriptor = *opt_field_descriptor;
if (field_descriptor.type() ==
protos::pbzero::FieldDescriptorProto::TYPE_MESSAGE) {
diff --git a/tools/gen_bazel b/tools/gen_bazel
index c6b7698..34a427a 100755
--- a/tools/gen_bazel
+++ b/tools/gen_bazel
@@ -146,6 +146,8 @@
gen_cc_metrics_descriptor,
'//src/trace_processor/importers:gen_cc_config_descriptor':
gen_cc_metrics_descriptor,
+ '//src/trace_processor/importers:gen_cc_chrome_track_event_descriptor':
+ gen_cc_metrics_descriptor,
}
# ------------------------------------------------------------------------------