Introduce DebugAnnotationParser
Refactor the debug annotation parsing logic into a standalone class,
which later will be used to parse debug annotations for console
interceptor.
R=eseckler@google.com,lalitm@google.com
Change-Id: I6b53706c4b63d455f4df1600b30029b02cc92139
diff --git a/Android.bp b/Android.bp
index 58fadf2..a340617 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1745,8 +1745,10 @@
":perfetto_src_trace_processor_tables_tables",
":perfetto_src_trace_processor_types_types",
":perfetto_src_trace_processor_util_descriptors",
+ ":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_text",
+ ":perfetto_src_trace_processor_util_trace_blob_view",
":perfetto_src_trace_processor_util_util",
":perfetto_src_traced_probes_android_log_android_log",
":perfetto_src_traced_probes_common_common",
@@ -8032,10 +8034,16 @@
],
}
+// GN: //src/trace_processor/util:interned_message_view
+filegroup {
+ name: "perfetto_src_trace_processor_util_interned_message_view",
+}
+
// GN: //src/trace_processor/util:proto_to_args_parser
filegroup {
name: "perfetto_src_trace_processor_util_proto_to_args_parser",
srcs: [
+ "src/trace_processor/util/debug_annotation_parser.cc",
"src/trace_processor/util/proto_to_args_parser.cc",
],
}
@@ -8048,10 +8056,16 @@
],
}
+// GN: //src/trace_processor/util:trace_blob_view
+filegroup {
+ name: "perfetto_src_trace_processor_util_trace_blob_view",
+}
+
// GN: //src/trace_processor/util:unittests
filegroup {
name: "perfetto_src_trace_processor_util_unittests",
srcs: [
+ "src/trace_processor/util/debug_annotation_parser_unittest.cc",
"src/trace_processor/util/proto_to_args_parser_unittest.cc",
"src/trace_processor/util/protozero_to_text_unittests.cc",
],
@@ -9034,8 +9048,10 @@
":perfetto_src_trace_processor_types_unittests",
":perfetto_src_trace_processor_unittests",
":perfetto_src_trace_processor_util_descriptors",
+ ":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_text",
+ ":perfetto_src_trace_processor_util_trace_blob_view",
":perfetto_src_trace_processor_util_unittests",
":perfetto_src_trace_processor_util_util",
":perfetto_src_traced_probes_android_log_android_log",
@@ -9321,8 +9337,10 @@
":perfetto_src_trace_processor_tables_tables",
":perfetto_src_trace_processor_types_types",
":perfetto_src_trace_processor_util_descriptors",
+ ":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_text",
+ ":perfetto_src_trace_processor_util_trace_blob_view",
":perfetto_src_trace_processor_util_util",
"src/trace_processor/trace_processor_shell.cc",
"src/trace_processor/util/proto_to_json.cc",
@@ -9470,8 +9488,10 @@
":perfetto_src_trace_processor_tables_tables",
":perfetto_src_trace_processor_types_types",
":perfetto_src_trace_processor_util_descriptors",
+ ":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_text",
+ ":perfetto_src_trace_processor_util_trace_blob_view",
":perfetto_src_trace_processor_util_util",
":perfetto_tools_trace_to_text_common",
":perfetto_tools_trace_to_text_full",
diff --git a/BUILD b/BUILD
index 7c960f8..30bea96 100644
--- a/BUILD
+++ b/BUILD
@@ -843,7 +843,6 @@
"src/trace_processor/importers/common/slice_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_blob_view.h",
"src/trace_processor/importers/common/trace_parser.h",
"src/trace_processor/importers/common/track_tracker.cc",
"src/trace_processor/importers/common/track_tracker.h",
@@ -1113,10 +1112,20 @@
],
)
+# GN target: //src/trace_processor/util:interned_message_view
+filegroup(
+ name = "src_trace_processor_util_interned_message_view",
+ srcs = [
+ "src/trace_processor/util/interned_message_view.h",
+ ],
+)
+
# GN target: //src/trace_processor/util:proto_to_args_parser
filegroup(
name = "src_trace_processor_util_proto_to_args_parser",
srcs = [
+ "src/trace_processor/util/debug_annotation_parser.cc",
+ "src/trace_processor/util/debug_annotation_parser.h",
"src/trace_processor/util/proto_to_args_parser.cc",
"src/trace_processor/util/proto_to_args_parser.h",
],
@@ -1131,6 +1140,14 @@
],
)
+# GN target: //src/trace_processor/util:trace_blob_view
+filegroup(
+ name = "src_trace_processor_util_trace_blob_view",
+ srcs = [
+ "src/trace_processor/util/trace_blob_view.h",
+ ],
+)
+
# GN target: //src/trace_processor/util:util
filegroup(
name = "src_trace_processor_util_util",
@@ -3453,8 +3470,10 @@
":src_trace_processor_tables_tables",
":src_trace_processor_types_types",
":src_trace_processor_util_descriptors",
+ ":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_text",
+ ":src_trace_processor_util_trace_blob_view",
":src_trace_processor_util_util",
],
hdrs = [
@@ -3551,8 +3570,10 @@
":src_trace_processor_tables_tables",
":src_trace_processor_types_types",
":src_trace_processor_util_descriptors",
+ ":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_text",
+ ":src_trace_processor_util_trace_blob_view",
":src_trace_processor_util_util",
"src/trace_processor/trace_processor_shell.cc",
"src/trace_processor/util/proto_to_json.cc",
@@ -3730,8 +3751,10 @@
":src_trace_processor_tables_tables",
":src_trace_processor_types_types",
":src_trace_processor_util_descriptors",
+ ":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_text",
+ ":src_trace_processor_util_trace_blob_view",
":src_trace_processor_util_util",
":tools_trace_to_text_common",
":tools_trace_to_text_full",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 8384f51..f07f3fb 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -154,6 +154,7 @@
"types",
"util",
"util:descriptors",
+ "util:interned_message_view",
"util:proto_to_args_parser",
]
public_deps = [
@@ -172,6 +173,7 @@
"../../protos/perfetto/trace/sys_stats:zero",
"../../protos/perfetto/trace/system_info:zero",
"../../protos/perfetto/trace/track_event:zero",
+ "util:trace_blob_view",
]
# json_utils optionally depends on jsoncpp.
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index e187260..1ffb40a 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -33,7 +33,6 @@
"slice_tracker.h",
"system_info_tracker.cc",
"system_info_tracker.h",
- "trace_blob_view.h",
"trace_parser.h",
"track_tracker.cc",
"track_tracker.h",
diff --git a/src/trace_processor/importers/common/args_tracker.h b/src/trace_processor/importers/common/args_tracker.h
index 4c2c943..f891537 100644
--- a/src/trace_processor/importers/common/args_tracker.h
+++ b/src/trace_processor/importers/common/args_tracker.h
@@ -64,18 +64,19 @@
// IncrementArrayEntryIndex() and GetNextArrayEntryIndex() provide a way to
// track the next array index for an array under a specific key.
- void IncrementArrayEntryIndex(StringId key) {
- // Zero-initializes |key| in the map if it doesn't exist yet.
- args_tracker_
- ->array_indexes_[std::make_tuple(arg_set_id_column_, row_, key)]++;
- }
-
size_t GetNextArrayEntryIndex(StringId key) {
// Zero-initializes |key| in the map if it doesn't exist yet.
return args_tracker_
->array_indexes_[std::make_tuple(arg_set_id_column_, row_, key)];
}
+ // Returns the next available array index after increment.
+ size_t IncrementArrayEntryIndex(StringId key) {
+ // Zero-initializes |key| in the map if it doesn't exist yet.
+ return ++args_tracker_->array_indexes_[std::make_tuple(arg_set_id_column_,
+ row_, key)];
+ }
+
protected:
BoundInserter(ArgsTracker* args_tracker,
Column* arg_set_id_column,
diff --git a/src/trace_processor/importers/ftrace/ftrace_module_impl.cc b/src/trace_processor/importers/ftrace/ftrace_module_impl.cc
index f86bdc5..7464db5 100644
--- a/src/trace_processor/importers/ftrace/ftrace_module_impl.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_module_impl.cc
@@ -16,10 +16,10 @@
#include "src/trace_processor/importers/ftrace/ftrace_module_impl.h"
#include "perfetto/base/build_config.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/ftrace/ftrace_parser.h"
#include "src/trace_processor/importers/ftrace/ftrace_tokenizer.h"
#include "src/trace_processor/timestamped_trace_piece.h"
+#include "src/trace_processor/util/trace_blob_view.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
diff --git a/src/trace_processor/importers/ftrace/ftrace_module_impl.h b/src/trace_processor/importers/ftrace/ftrace_module_impl.h
index 2ba4d6b..488c2eb 100644
--- a/src/trace_processor/importers/ftrace/ftrace_module_impl.h
+++ b/src/trace_processor/importers/ftrace/ftrace_module_impl.h
@@ -18,12 +18,12 @@
#define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_FTRACE_MODULE_IMPL_H_
#include "perfetto/base/build_config.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
#include "src/trace_processor/importers/ftrace/ftrace_parser.h"
#include "src/trace_processor/importers/ftrace/ftrace_tokenizer.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/timestamped_trace_piece.h"
+#include "src/trace_processor/util/trace_blob_view.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index f0ef2b9..79e1c65 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -19,12 +19,12 @@
#include "perfetto/trace_processor/status.h"
#include "src/trace_processor/importers/common/event_tracker.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/ftrace/ftrace_descriptors.h"
#include "src/trace_processor/importers/ftrace/rss_stat_tracker.h"
#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/timestamped_trace_piece.h"
#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/ftrace/ftrace_tokenizer.h b/src/trace_processor/importers/ftrace/ftrace_tokenizer.h
index f4f5416..8f95fca 100644
--- a/src/trace_processor/importers/ftrace/ftrace_tokenizer.h
+++ b/src/trace_processor/importers/ftrace/ftrace_tokenizer.h
@@ -18,9 +18,9 @@
#define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_FTRACE_TOKENIZER_H_
#include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_record.h b/src/trace_processor/importers/fuchsia/fuchsia_record.h
index 9518c35..a5063ae 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_record.h
+++ b/src/trace_processor/importers/fuchsia/fuchsia_record.h
@@ -17,9 +17,9 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_FUCHSIA_FUCHSIA_RECORD_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_FUCHSIA_FUCHSIA_RECORD_H_
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/util/trace_blob_view.h"
#include <vector>
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h b/src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h
index 0881fd5..57c4718 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h
+++ b/src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h
@@ -18,9 +18,9 @@
#define SRC_TRACE_PROCESSOR_IMPORTERS_FUCHSIA_FUCHSIA_TRACE_TOKENIZER_H_
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h b/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h
index f6f99d0..73d4f0d 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h
+++ b/src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h
@@ -22,8 +22,8 @@
#include <functional>
#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/json/json_trace_tokenizer.cc b/src/trace_processor/importers/json/json_trace_tokenizer.cc
index cdf7020..695e692 100644
--- a/src/trace_processor/importers/json/json_trace_tokenizer.cc
+++ b/src/trace_processor/importers/json/json_trace_tokenizer.cc
@@ -21,12 +21,12 @@
#include "perfetto/base/build_config.h"
#include "perfetto/ext/base/string_utils.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/json/json_tracker.h"
#include "src/trace_processor/importers/json/json_utils.h"
#include "src/trace_processor/storage/stats.h"
#include "src/trace_processor/trace_sorter.h"
#include "src/trace_processor/util/status_macros.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
index fc5288c..a999f9a 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state.h
@@ -24,10 +24,11 @@
#include "perfetto/base/compiler.h"
#include "perfetto/protozero/proto_decoder.h"
-#include "src/trace_processor/importers/common/trace_blob_view.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"
+#include "src/trace_processor/util/trace_blob_view.h"
#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
@@ -35,114 +36,6 @@
namespace perfetto {
namespace trace_processor {
-#if PERFETTO_DCHECK_IS_ON()
-// When called from GetOrCreateDecoder(), should include the stringified name of
-// the MessageType.
-#define PERFETTO_TYPE_IDENTIFIER PERFETTO_DEBUG_FUNCTION_IDENTIFIER()
-#else // PERFETTO_DCHECK_IS_ON()
-#define PERFETTO_TYPE_IDENTIFIER nullptr
-#endif // PERFETTO_DCHECK_IS_ON()
-
-// Entry in an interning index, refers to the interned message.
-class InternedMessageView {
- public:
- InternedMessageView(TraceBlobView msg) : message_(std::move(msg)) {}
-
- InternedMessageView(InternedMessageView&&) = default;
- InternedMessageView& operator=(InternedMessageView&&) = default;
-
- // Allow copy by cloning the TraceBlobView. This is required for
- // UpdateTracePacketDefaults().
- InternedMessageView(const InternedMessageView& view)
- : message_(view.message_.slice(0, view.message_.length())) {}
- InternedMessageView& operator=(const InternedMessageView& view) {
- this->message_ = view.message_.slice(0, view.message_.length());
- this->decoder_ = nullptr;
- this->decoder_type_ = nullptr;
- this->submessages_.clear();
- return *this;
- }
-
- // Lazily initializes and returns the decoder object for the message. The
- // decoder is stored in the InternedMessageView to avoid having to parse the
- // message multiple times.
- template <typename MessageType>
- typename MessageType::Decoder* GetOrCreateDecoder() {
- if (!decoder_) {
- // Lazy init the decoder and save it away, so that we don't have to
- // reparse the message every time we access the interning entry.
- decoder_ = std::unique_ptr<void, std::function<void(void*)>>(
- new typename MessageType::Decoder(message_.data(), message_.length()),
- [](void* obj) {
- delete reinterpret_cast<typename MessageType::Decoder*>(obj);
- });
- decoder_type_ = PERFETTO_TYPE_IDENTIFIER;
- }
- // Verify that the type of the decoder didn't change.
- if (PERFETTO_TYPE_IDENTIFIER &&
- strcmp(decoder_type_,
- // GCC complains if this arg can be null.
- PERFETTO_TYPE_IDENTIFIER ? PERFETTO_TYPE_IDENTIFIER : "") != 0) {
- PERFETTO_FATAL(
- "Interning entry accessed under different types! previous type: "
- "%s. new type: %s.",
- decoder_type_, PERFETTO_DEBUG_FUNCTION_IDENTIFIER());
- }
- return reinterpret_cast<typename MessageType::Decoder*>(decoder_.get());
- }
-
- // Lookup a submessage of the interned message, which is then itself stored
- // as InternedMessageView, so that we only need to parse it once. Returns
- // nullptr if the field isn't set.
- // TODO(eseckler): Support repeated fields.
- template <typename MessageType, uint32_t FieldId>
- InternedMessageView* GetOrCreateSubmessageView() {
- auto it = submessages_.find(FieldId);
- if (it != submessages_.end())
- return it->second.get();
- auto* decoder = GetOrCreateDecoder<MessageType>();
- // Calls the at() template method on the decoder.
- auto field = decoder->template at<FieldId>().as_bytes();
- if (!field.data)
- return nullptr;
- const size_t offset = message_.offset_of(field.data);
- TraceBlobView submessage = message_.slice(offset, field.size);
- InternedMessageView* submessage_view =
- new InternedMessageView(std::move(submessage));
- submessages_.emplace_hint(
- it, FieldId, std::unique_ptr<InternedMessageView>(submessage_view));
- return submessage_view;
- }
-
- const TraceBlobView& message() { return message_; }
-
- private:
- using SubMessageViewMap =
- std::unordered_map<uint32_t /*field_id*/,
- std::unique_ptr<InternedMessageView>>;
-
- TraceBlobView message_;
-
- // Stores the decoder for the message_, so that the message does not have to
- // be re-decoded every time the interned message is looked up. Lazily
- // initialized in GetOrCreateDecoder(). Since we don't know the type of the
- // decoder until GetOrCreateDecoder() is called, we store the decoder as a
- // void* unique_pointer with a destructor function that's supplied in
- // GetOrCreateDecoder() when the decoder is created.
- std::unique_ptr<void, std::function<void(void*)>> decoder_;
-
- // Type identifier for the decoder. Only valid in debug builds and on
- // supported platforms. Used to verify that GetOrCreateDecoder() is always
- // called with the same template argument.
- const char* decoder_type_ = nullptr;
-
- // Views of submessages of the interned message. Submessages are lazily
- // added by GetOrCreateSubmessageView(). By storing submessages and their
- // decoders, we avoid having to decode submessages multiple times if they
- // looked up often.
- SubMessageViewMap submessages_;
-};
-
using InternedMessageMap =
std::unordered_map<uint64_t /*iid*/, InternedMessageView>;
using InternedFieldMap =
diff --git a/src/trace_processor/importers/proto/proto_importer_module.h b/src/trace_processor/importers/proto/proto_importer_module.h
index d0a023a..9a1dd5b 100644
--- a/src/trace_processor/importers/proto/proto_importer_module.h
+++ b/src/trace_processor/importers/proto/proto_importer_module.h
@@ -19,7 +19,7 @@
#include "perfetto/ext/base/optional.h"
#include "perfetto/trace_processor/status.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.h b/src/trace_processor/importers/proto/proto_trace_parser.h
index 53a6099..f33bc5f 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.h
+++ b/src/trace_processor/importers/proto/proto_trace_parser.h
@@ -25,10 +25,10 @@
#include "perfetto/ext/base/optional.h"
#include "perfetto/ext/base/string_view.h"
#include "perfetto/protozero/field.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/common/trace_parser.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/timestamped_trace_piece.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index b2f4069..9f7a403 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -22,9 +22,9 @@
#include <memory>
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
-#include "src/trace_processor/importers/common/trace_blob_view.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/util/trace_blob_view.h"
namespace protozero {
struct ConstBytes;
diff --git a/src/trace_processor/importers/proto/proto_trace_tokenizer.h b/src/trace_processor/importers/proto/proto_trace_tokenizer.h
index 76a0f42..484c674 100644
--- a/src/trace_processor/importers/proto/proto_trace_tokenizer.h
+++ b/src/trace_processor/importers/proto/proto_trace_tokenizer.h
@@ -21,9 +21,9 @@
#include "perfetto/protozero/proto_utils.h"
#include "perfetto/trace_processor/status.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/gzip/gzip_utils.h"
#include "src/trace_processor/util/status_macros.h"
+#include "src/trace_processor/util/trace_blob_view.h"
#include "protos/perfetto/trace/trace.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 8ad8177..8b93efd 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -31,6 +31,7 @@
#include "src/trace_processor/importers/json/json_utils.h"
#include "src/trace_processor/importers/proto/packet_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"
#include "src/trace_processor/util/status_macros.h"
@@ -107,10 +108,21 @@
storage_.InternString(base::StringView(key.key)),
Variadic::Boolean(value));
}
- void AddJson(const Key& key, const protozero::ConstChars& value) final {
- inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
- storage_.InternString(base::StringView(key.key)),
- Variadic::Json(storage_.InternString(value)));
+ bool AddJson(const Key& key, const protozero::ConstChars& value) final {
+ auto json_value = json::ParseJsonString(value);
+ return json::AddJsonValueToArgs(*json_value, base::StringView(key.flat_key),
+ base::StringView(key.key), &storage_,
+ &inserter_);
+ }
+
+ size_t GetArrayEntryIndex(const std::string& array_key) final {
+ return inserter_.GetNextArrayEntryIndex(
+ storage_.InternString(base::StringView(array_key)));
+ }
+
+ size_t IncrementArrayEntryIndex(const std::string& array_key) final {
+ return inserter_.IncrementArrayEntryIndex(
+ storage_.InternString(base::StringView(array_key)));
}
InternedMessageView* GetInternedMessageView(uint32_t field_id,
@@ -148,13 +160,6 @@
return base::OkStatus();
}
-std::string SanitizeDebugAnnotationName(const std::string& raw_name) {
- std::string result = raw_name;
- std::replace(result.begin(), result.end(), '.', '_');
- std::replace(result.begin(), result.end(), '[', '_');
- std::replace(result.begin(), result.end(), ']', '_');
- return result;
-}
} // namespace
class TrackEventParser::EventImporter {
@@ -1092,10 +1097,6 @@
PERFETTO_DLOG("ParseTrackEventArgs error: %s", status.c_message());
};
- for (auto it = event_.debug_annotations(); it; ++it) {
- log_errors(ParseDebugAnnotation(*it, inserter));
- }
-
if (event_.has_source_location_iid()) {
log_errors(AddSourceLocationArgs(event_.source_location_iid(), inserter));
}
@@ -1116,6 +1117,14 @@
blob_, ".perfetto.protos.TrackEvent", &parser_->reflect_fields_,
args_writer));
+ {
+ auto key = parser_->args_parser_.EnterDictionary("debug");
+ util::DebugAnnotationParser parser(parser_->args_parser_);
+ for (auto it = event_.debug_annotations(); it; ++it) {
+ log_errors(parser.Parse(*it, args_writer));
+ }
+ }
+
if (legacy_passthrough_utid_) {
inserter->AddArg(parser_->legacy_event_passthrough_utid_id_,
Variadic::UnsignedInteger(*legacy_passthrough_utid_),
@@ -1123,170 +1132,6 @@
}
}
- util::Status ParseDebugAnnotation(ConstBytes data, BoundInserter* inserter) {
- protos::pbzero::DebugAnnotation::Decoder annotation(data);
-
- std::string name;
- util::Status name_parse_result = ParseDebugAnnotationName(annotation, name);
- if (!name_parse_result.ok())
- return name_parse_result;
-
- return ParseDebugAnnotationValue(annotation, inserter, "debug." + name);
- }
-
- util::Status ParseDebugAnnotationName(
- protos::pbzero::DebugAnnotation::Decoder& annotation,
- std::string& result) {
- uint64_t name_iid = annotation.name_iid();
- if (PERFETTO_LIKELY(name_iid)) {
- auto* decoder = sequence_state_->LookupInternedMessage<
- protos::pbzero::InternedData::kDebugAnnotationNamesFieldNumber,
- protos::pbzero::DebugAnnotationName>(name_iid);
- if (!decoder)
- return util::ErrStatus("Debug annotation with invalid name_iid");
-
- result = SanitizeDebugAnnotationName(decoder->name().ToStdString());
- } else if (annotation.has_name()) {
- result = SanitizeDebugAnnotationName(annotation.name().ToStdString());
- } else {
- return util::ErrStatus("Debug annotation without name");
- }
- return util::OkStatus();
- }
-
- util::Status ParseDebugAnnotationValue(
- protos::pbzero::DebugAnnotation::Decoder& annotation,
- BoundInserter* inserter,
- const std::string& context_name) {
- StringId name_id = storage_->InternString(base::StringView(context_name));
-
- if (annotation.has_bool_value()) {
- inserter->AddArg(name_id, Variadic::Boolean(annotation.bool_value()));
- } else if (annotation.has_uint_value()) {
- inserter->AddArg(name_id,
- Variadic::UnsignedInteger(annotation.uint_value()));
- } else if (annotation.has_int_value()) {
- inserter->AddArg(name_id, Variadic::Integer(annotation.int_value()));
- } else if (annotation.has_double_value()) {
- inserter->AddArg(name_id, Variadic::Real(annotation.double_value()));
- } else if (annotation.has_string_value()) {
- inserter->AddArg(
- name_id,
- Variadic::String(storage_->InternString(annotation.string_value())));
- } else if (annotation.has_pointer_value()) {
- inserter->AddArg(name_id, Variadic::Pointer(annotation.pointer_value()));
- } else if (annotation.has_dict_entries()) {
- for (auto it = annotation.dict_entries(); it; ++it) {
- protos::pbzero::DebugAnnotation::Decoder key_value(*it);
- std::string key;
- util::Status key_parse_result =
- ParseDebugAnnotationName(key_value, key);
- if (!key_parse_result.ok())
- return key_parse_result;
-
- std::string child_flat_key = context_name + "." + key;
- util::Status value_parse_result =
- ParseDebugAnnotationValue(key_value, inserter, child_flat_key);
- if (!value_parse_result.ok())
- return value_parse_result;
- }
- } else if (annotation.has_array_values()) {
- size_t index = 0;
- for (auto it = annotation.array_values(); it; ++it) {
- protos::pbzero::DebugAnnotation::Decoder value(*it);
-
- std::string child_flat_key =
- context_name + "[" + std::to_string(index) + "]";
- util::Status value_parse_result =
- ParseDebugAnnotationValue(value, inserter, child_flat_key);
- if (!value_parse_result.ok())
- return value_parse_result;
- ++index;
- }
- } else if (annotation.has_legacy_json_value()) {
- if (!json::IsJsonSupported())
- return util::ErrStatus("Ignoring legacy_json_value (no json support)");
-
- auto value = json::ParseJsonString(annotation.legacy_json_value());
- auto name = storage_->GetString(name_id);
- json::AddJsonValueToArgs(*value, name, name, storage_, inserter);
- } else if (annotation.has_nested_value()) {
- auto name = storage_->GetString(name_id);
- ParseNestedValueArgs(annotation.nested_value(), name, name, inserter);
- }
-
- return util::OkStatus();
- }
-
- bool ParseNestedValueArgs(ConstBytes nested_value,
- base::StringView flat_key,
- base::StringView key,
- BoundInserter* inserter) {
- protos::pbzero::DebugAnnotation::NestedValue::Decoder value(nested_value);
- switch (value.nested_type()) {
- case protos::pbzero::DebugAnnotation::NestedValue::UNSPECIFIED: {
- auto flat_key_id = storage_->InternString(flat_key);
- auto key_id = storage_->InternString(key);
- // Leaf value.
- if (value.has_bool_value()) {
- inserter->AddArg(flat_key_id, key_id,
- Variadic::Boolean(value.bool_value()));
- return true;
- }
- if (value.has_int_value()) {
- inserter->AddArg(flat_key_id, key_id,
- Variadic::Integer(value.int_value()));
- return true;
- }
- if (value.has_double_value()) {
- inserter->AddArg(flat_key_id, key_id,
- Variadic::Real(value.double_value()));
- return true;
- }
- if (value.has_string_value()) {
- inserter->AddArg(
- flat_key_id, key_id,
- Variadic::String(storage_->InternString(value.string_value())));
- return true;
- }
- return false;
- }
- case protos::pbzero::DebugAnnotation::NestedValue::DICT: {
- auto key_it = value.dict_keys();
- auto value_it = value.dict_values();
- bool inserted = false;
- for (; key_it && value_it; ++key_it, ++value_it) {
- std::string child_name =
- SanitizeDebugAnnotationName((*key_it).ToStdString());
- std::string child_flat_key =
- flat_key.ToStdString() + "." + child_name;
- std::string child_key = key.ToStdString() + "." + child_name;
- inserted |=
- ParseNestedValueArgs(*value_it, base::StringView(child_flat_key),
- base::StringView(child_key), inserter);
- }
- return inserted;
- }
- case protos::pbzero::DebugAnnotation::NestedValue::ARRAY: {
- bool inserted_any = false;
- std::string array_key = key.ToStdString();
- StringId array_key_id = storage_->InternString(key);
- for (auto value_it = value.array_values(); value_it; ++value_it) {
- size_t array_index = inserter->GetNextArrayEntryIndex(array_key_id);
- std::string child_key =
- array_key + "[" + std::to_string(array_index) + "]";
- bool inserted = ParseNestedValueArgs(
- *value_it, flat_key, base::StringView(child_key), inserter);
- if (inserted)
- inserter->IncrementArrayEntryIndex(array_key_id);
- inserted_any |= inserted;
- }
- return inserted_any;
- }
- }
- return false;
- }
-
util::Status ParseTaskExecutionArgs(ConstBytes task_execution,
BoundInserter* inserter) {
protos::pbzero::TaskExecution::Decoder task(task_execution);
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index 9d28e46..056d342 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -19,7 +19,6 @@
#include "perfetto/base/logging.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/proto/proto_trace_reader.h"
@@ -27,6 +26,7 @@
#include "src/trace_processor/storage/stats.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/trace_sorter.h"
+#include "src/trace_processor/util/trace_blob_view.h"
#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
diff --git a/src/trace_processor/timestamped_trace_piece.h b/src/trace_processor/timestamped_trace_piece.h
index f775443..303e234 100644
--- a/src/trace_processor/timestamped_trace_piece.h
+++ b/src/trace_processor/timestamped_trace_piece.h
@@ -19,13 +19,13 @@
#include "perfetto/base/build_config.h"
#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/importers/fuchsia/fuchsia_record.h"
#include "src/trace_processor/importers/json/json_utils.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/systrace/systrace_line.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/trace_blob_view.h"
// GCC can't figure out the relationship between TimestampedTracePiece's type
// and the union, and thus thinks that we may be moving or destroying
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index cca6947..e9c0f37 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -25,7 +25,6 @@
#include "src/trace_processor/importers/common/flow_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/trace_blob_view.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/default_modules.h"
#include "src/trace_processor/importers/proto/async_track_set_tracker.h"
@@ -38,6 +37,7 @@
#include "src/trace_processor/importers/track_event.descriptor.h"
#include "src/trace_processor/trace_sorter.h"
#include "src/trace_processor/util/descriptors.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/trace_sorter.h b/src/trace_processor/trace_sorter.h
index 614d627..f654163 100644
--- a/src/trace_processor/trace_sorter.h
+++ b/src/trace_processor/trace_sorter.h
@@ -21,9 +21,9 @@
#include "perfetto/ext/base/circular_queue.h"
#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/timestamped_trace_piece.h"
+#include "src/trace_processor/util/trace_blob_view.h"
namespace Json {
class Value;
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index 02887ac..31925e8 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -45,6 +45,23 @@
]
}
+source_set("trace_blob_view") {
+ sources = [ "trace_blob_view.h" ]
+ deps = [
+ "../../../gn:default_deps",
+ "../../base",
+ ]
+}
+
+source_set("interned_message_view") {
+ sources = [ "interned_message_view.h" ]
+ deps = [
+ "../../../gn:default_deps",
+ "../../base",
+ ]
+ public_deps = [ ":trace_blob_view" ]
+}
+
source_set("descriptors") {
sources = [
"descriptors.cc",
@@ -55,14 +72,16 @@
"../../../gn:default_deps",
"../../../protos/perfetto/common:zero",
"../../../protos/perfetto/trace_processor:zero",
+ "../../base",
"../../protozero",
"../importers:gen_cc_track_event_descriptor",
]
- public_deps = [ "../../base" ]
}
source_set("proto_to_args_parser") {
sources = [
+ "debug_annotation_parser.cc",
+ "debug_annotation_parser.h",
"proto_to_args_parser.cc",
"proto_to_args_parser.h",
]
@@ -70,6 +89,7 @@
"../../../gn:default_deps",
"../../../protos/perfetto/common:zero",
"../../../protos/perfetto/trace/interned_data:zero",
+ "../../../protos/perfetto/trace/track_event:zero",
"../../../protos/perfetto/trace_processor:zero",
"../../protozero",
"../importers:gen_cc_track_event_descriptor",
@@ -77,17 +97,15 @@
public_deps = [
":descriptors",
+ ":interned_message_view",
":util",
"../../base",
-
- # TODO(altimin): Move InternedMessageView and TraceBlobView here and remove
- # this dependency.
- "../importers/common",
]
}
source_set("unittests") {
sources = [
+ "debug_annotation_parser_unittest.cc",
"proto_to_args_parser_unittest.cc",
"protozero_to_text_unittests.cc",
]
@@ -104,9 +122,5 @@
"../../protozero",
"../../protozero:testing_messages_zero",
"../importers:gen_cc_track_event_descriptor",
-
- # TODO(altimin): Move InternedMessageView and TraceBlobView here and remove
- # this dependency.
- "..:storage_minimal",
]
}
diff --git a/src/trace_processor/util/debug_annotation_parser.cc b/src/trace_processor/util/debug_annotation_parser.cc
new file mode 100644
index 0000000..eeaf39f
--- /dev/null
+++ b/src/trace_processor/util/debug_annotation_parser.cc
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2021 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/util/debug_annotation_parser.h"
+#include "perfetto/base/build_config.h"
+#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
+#include "src/trace_processor/util/interned_message_view.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace util {
+
+namespace {
+
+std::string SanitizeDebugAnnotationName(const std::string& raw_name) {
+ std::string result = raw_name;
+ std::replace(result.begin(), result.end(), '.', '_');
+ std::replace(result.begin(), result.end(), '[', '_');
+ std::replace(result.begin(), result.end(), ']', '_');
+ return result;
+}
+
+bool IsJsonSupported() {
+#if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
+ return true;
+#else
+ return false;
+#endif
+}
+
+} // namespace
+
+DebugAnnotationParser::DebugAnnotationParser(ProtoToArgsParser& parser)
+ : proto_to_args_parser_(parser) {}
+
+base::Status DebugAnnotationParser::ParseDebugAnnotationName(
+ protos::pbzero::DebugAnnotation::Decoder& annotation,
+ ProtoToArgsParser::Delegate& delegate,
+ std::string& result) {
+ uint64_t name_iid = annotation.name_iid();
+ if (PERFETTO_LIKELY(name_iid)) {
+ auto* decoder = delegate.GetInternedMessage(
+ protos::pbzero::InternedData::kDebugAnnotationNames, name_iid);
+ if (!decoder)
+ return base::ErrStatus("Debug annotation with invalid name_iid");
+
+ result = SanitizeDebugAnnotationName(decoder->name().ToStdString());
+ } else if (annotation.has_name()) {
+ result = SanitizeDebugAnnotationName(annotation.name().ToStdString());
+ } else {
+ return base::ErrStatus("Debug annotation without name");
+ }
+ return base::OkStatus();
+}
+
+DebugAnnotationParser::ParseResult
+DebugAnnotationParser::ParseDebugAnnotationValue(
+ protos::pbzero::DebugAnnotation::Decoder& annotation,
+ ProtoToArgsParser::Delegate& delegate,
+ const ProtoToArgsParser::Key& context_name) {
+ if (annotation.has_bool_value()) {
+ delegate.AddBoolean(context_name, annotation.bool_value());
+ } else if (annotation.has_uint_value()) {
+ delegate.AddUnsignedInteger(context_name, annotation.uint_value());
+ } else if (annotation.has_int_value()) {
+ delegate.AddInteger(context_name, annotation.int_value());
+ } else if (annotation.has_double_value()) {
+ delegate.AddDouble(context_name, annotation.double_value());
+ } else if (annotation.has_string_value()) {
+ delegate.AddString(context_name, annotation.string_value());
+ } else if (annotation.has_pointer_value()) {
+ delegate.AddPointer(context_name, reinterpret_cast<const void*>(
+ annotation.pointer_value()));
+ } else if (annotation.has_dict_entries()) {
+ bool added_entry = false;
+ for (auto it = annotation.dict_entries(); it; ++it) {
+ protos::pbzero::DebugAnnotation::Decoder key_value(*it);
+ std::string key;
+ base::Status key_parse_result =
+ ParseDebugAnnotationName(key_value, delegate, key);
+ if (!key_parse_result.ok())
+ return {key_parse_result, added_entry};
+
+ auto nested_key = proto_to_args_parser_.EnterDictionary(key);
+ ParseResult value_parse_result =
+ ParseDebugAnnotationValue(key_value, delegate, nested_key.key());
+ added_entry |= value_parse_result.added_entry;
+ if (!value_parse_result.status.ok())
+ return {value_parse_result.status, added_entry};
+ }
+ } else if (annotation.has_array_values()) {
+ size_t index = delegate.GetArrayEntryIndex(context_name.key);
+ bool added_entry = false;
+ for (auto it = annotation.array_values(); it; ++it) {
+ protos::pbzero::DebugAnnotation::Decoder value(*it);
+
+ auto nested_key = proto_to_args_parser_.EnterArray(index);
+ ParseResult value_parse_result =
+ ParseDebugAnnotationValue(value, delegate, nested_key.key());
+
+ // Reset the key here to ensure that we have the correct array key to
+ // increment.
+ nested_key.Reset();
+
+ if (value_parse_result.added_entry) {
+ index = delegate.IncrementArrayEntryIndex(context_name.key);
+ added_entry = true;
+ }
+ if (!value_parse_result.status.ok())
+ return {value_parse_result.status, added_entry};
+ }
+ } else if (annotation.has_legacy_json_value()) {
+ if (!IsJsonSupported())
+ return {base::ErrStatus("Ignoring legacy_json_value (no json support)"),
+ false};
+
+ bool added_entry =
+ delegate.AddJson(context_name, annotation.legacy_json_value());
+ return {base::OkStatus(), added_entry};
+ } else if (annotation.has_nested_value()) {
+ return ParseNestedValueArgs(annotation.nested_value(), context_name,
+ delegate);
+ } else {
+ return {base::OkStatus(), /*added_entry=*/false};
+ }
+
+ return {base::OkStatus(), /*added_entry=*/true};
+}
+
+// static
+base::Status DebugAnnotationParser::Parse(
+ protozero::ConstBytes data,
+ ProtoToArgsParser::Delegate& delegate) {
+ protos::pbzero::DebugAnnotation::Decoder annotation(data);
+
+ std::string name;
+ base::Status name_parse_result =
+ ParseDebugAnnotationName(annotation, delegate, name);
+ if (!name_parse_result.ok())
+ return name_parse_result;
+
+ auto context = proto_to_args_parser_.EnterDictionary(name);
+
+ return ParseDebugAnnotationValue(annotation, delegate, context.key()).status;
+}
+
+DebugAnnotationParser::ParseResult DebugAnnotationParser::ParseNestedValueArgs(
+ protozero::ConstBytes nested_value,
+ const ProtoToArgsParser::Key& context_name,
+ ProtoToArgsParser::Delegate& delegate) {
+ protos::pbzero::DebugAnnotation::NestedValue::Decoder value(nested_value);
+ switch (value.nested_type()) {
+ case protos::pbzero::DebugAnnotation::NestedValue::UNSPECIFIED: {
+ // Leaf value.
+ if (value.has_bool_value()) {
+ delegate.AddBoolean(context_name, value.bool_value());
+ return {base::OkStatus(), true};
+ }
+ if (value.has_int_value()) {
+ delegate.AddInteger(context_name, value.int_value());
+ return {base::OkStatus(), true};
+ }
+ if (value.has_double_value()) {
+ delegate.AddDouble(context_name, value.double_value());
+ return {base::OkStatus(), true};
+ }
+ if (value.has_string_value()) {
+ delegate.AddString(context_name, value.string_value());
+ return {base::OkStatus(), true};
+ }
+ return {base::OkStatus(), false};
+ }
+ case protos::pbzero::DebugAnnotation::NestedValue::DICT: {
+ bool added_entry = false;
+ auto key_it = value.dict_keys();
+ auto value_it = value.dict_values();
+ for (; key_it && value_it; ++key_it, ++value_it) {
+ std::string child_name =
+ SanitizeDebugAnnotationName((*key_it).ToStdString());
+ auto nested_key = proto_to_args_parser_.EnterDictionary(child_name);
+ ParseResult result =
+ ParseNestedValueArgs(*value_it, nested_key.key(), delegate);
+ added_entry |= result.added_entry;
+ if (!result.status.ok())
+ return {result.status, added_entry};
+ }
+ return {base::OkStatus(), true};
+ }
+
+ case protos::pbzero::DebugAnnotation::NestedValue::ARRAY: {
+ std::string array_key = context_name.key;
+ size_t array_index = delegate.GetArrayEntryIndex(context_name.key);
+ bool added_entry = false;
+
+ for (auto value_it = value.array_values(); value_it; ++value_it) {
+ auto nested_key = proto_to_args_parser_.EnterArray(array_index);
+ ParseResult result =
+ ParseNestedValueArgs(*value_it, nested_key.key(), delegate);
+
+ if (result.added_entry) {
+ ++array_index;
+ delegate.IncrementArrayEntryIndex(array_key);
+ added_entry = true;
+ }
+ if (!result.status.ok())
+ return {result.status, added_entry};
+ }
+ return {base::OkStatus(), added_entry};
+ }
+ }
+ return {base::OkStatus(), false};
+}
+
+} // namespace util
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/util/debug_annotation_parser.h b/src/trace_processor/util/debug_annotation_parser.h
new file mode 100644
index 0000000..0e68eec
--- /dev/null
+++ b/src/trace_processor/util/debug_annotation_parser.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 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_UTIL_DEBUG_ANNOTATION_PARSER_H_
+#define SRC_TRACE_PROCESSOR_UTIL_DEBUG_ANNOTATION_PARSER_H_
+
+#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
+#include "src/trace_processor/util/proto_to_args_parser.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace util {
+
+// |DebugAnnotationParser| is responsible for parsing DebugAnnotation protos
+// and turning it into key-value arg pairs.
+// |DebugAnnotationParser| is a logical extension of |ProtoToArgsParser|:
+// it uses |ProtoToArgsParser::Delegate| for writing the results and uses
+// |ProtoToArgsParser| to parse arbitrary protos nested inside DebugAnnotation.
+class DebugAnnotationParser {
+ public:
+ explicit DebugAnnotationParser(ProtoToArgsParser& proto_to_args_parser);
+
+ base::Status Parse(protozero::ConstBytes data,
+ ProtoToArgsParser::Delegate& delegate);
+
+ private:
+ struct ParseResult {
+ base::Status status;
+ // True if parsing of the annotation added at least one entry to the
+ // |delegate|.
+ bool added_entry;
+ };
+
+ base::Status ParseDebugAnnotationName(
+ protos::pbzero::DebugAnnotation::Decoder& annotation,
+ ProtoToArgsParser::Delegate& delegate,
+ std::string& result);
+ ParseResult ParseDebugAnnotationValue(
+ protos::pbzero::DebugAnnotation::Decoder& annotation,
+ ProtoToArgsParser::Delegate& delegate,
+ const ProtoToArgsParser::Key& context_name);
+ ParseResult ParseNestedValueArgs(protozero::ConstBytes nested_value,
+ const ProtoToArgsParser::Key& context_name,
+ ProtoToArgsParser::Delegate& delegate);
+
+ ProtoToArgsParser& proto_to_args_parser_;
+};
+
+} // namespace util
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_UTIL_DEBUG_ANNOTATION_PARSER_H_
diff --git a/src/trace_processor/util/debug_annotation_parser_unittest.cc b/src/trace_processor/util/debug_annotation_parser_unittest.cc
new file mode 100644
index 0000000..e3f3380
--- /dev/null
+++ b/src/trace_processor/util/debug_annotation_parser_unittest.cc
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2021 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/util/debug_annotation_parser.h"
+
+#include "perfetto/ext/base/string_view.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "protos/perfetto/common/descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
+#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
+#include "src/protozero/test/example_proto/test_messages.pbzero.h"
+#include "src/trace_processor/test_messages.descriptor.h"
+#include "src/trace_processor/util/interned_message_view.h"
+#include "src/trace_processor/util/proto_to_args_parser.h"
+#include "src/trace_processor/util/trace_blob_view.h"
+#include "test/gtest_and_gmock.h"
+
+#include <sstream>
+
+namespace perfetto {
+namespace trace_processor {
+namespace util {
+namespace {
+
+base::Status ParseDebugAnnotation(
+ DebugAnnotationParser& parser,
+ protozero::HeapBuffered<protos::pbzero::DebugAnnotation>& msg,
+ ProtoToArgsParser::Delegate& delegate) {
+ std::vector<uint8_t> data = msg.SerializeAsArray();
+ return parser.Parse(protozero::ConstBytes{data.data(), data.size()},
+ delegate);
+}
+
+class DebugAnnotationParserTest : public ::testing::Test,
+ public ProtoToArgsParser::Delegate {
+ protected:
+ DebugAnnotationParserTest() {}
+
+ const std::vector<std::string>& args() const { return args_; }
+
+ private:
+ using Key = ProtoToArgsParser::Key;
+
+ void AddInteger(const Key& key, int64_t value) override {
+ std::stringstream ss;
+ ss << key.flat_key << " " << key.key << " " << value;
+ args_.push_back(ss.str());
+ }
+
+ void AddUnsignedInteger(const Key& key, uint64_t value) override {
+ std::stringstream ss;
+ ss << key.flat_key << " " << key.key << " " << value;
+ args_.push_back(ss.str());
+ }
+
+ void AddString(const Key& key, const protozero::ConstChars& value) override {
+ std::stringstream ss;
+ ss << key.flat_key << " " << key.key << " " << value.ToStdString();
+ args_.push_back(ss.str());
+ }
+
+ void AddDouble(const Key& key, double value) override {
+ std::stringstream ss;
+ ss << key.flat_key << " " << key.key << " " << value;
+ args_.push_back(ss.str());
+ }
+
+ void AddPointer(const Key& key, const void* value) override {
+ std::stringstream ss;
+ ss << key.flat_key << " " << key.key << " " << std::hex
+ << reinterpret_cast<uintptr_t>(value) << std::dec;
+ args_.push_back(ss.str());
+ }
+
+ void AddBoolean(const Key& key, bool value) override {
+ std::stringstream ss;
+ ss << key.flat_key << " " << key.key << " " << (value ? "true" : "false");
+ args_.push_back(ss.str());
+ }
+
+ bool AddJson(const Key& key, const protozero::ConstChars& value) override {
+ std::stringstream ss;
+ ss << key.flat_key << " " << key.key << " " << std::hex
+ << value.ToStdString() << std::dec;
+ args_.push_back(ss.str());
+ return true;
+ }
+
+ size_t GetArrayEntryIndex(const std::string& array_key) final {
+ return array_indices_[array_key];
+ }
+
+ size_t IncrementArrayEntryIndex(const std::string& array_key) final {
+ return ++array_indices_[array_key];
+ }
+
+ InternedMessageView* GetInternedMessageView(uint32_t, uint64_t) override {
+ return nullptr;
+ }
+
+ std::vector<std::string> args_;
+ std::map<std::string, size_t> array_indices_;
+};
+
+// This test checks that in when an array is nested inside a dict which is
+// nested inside an array which is nested inside a dict, flat keys and non-flat
+// keys are parsed correctly.
+TEST_F(DebugAnnotationParserTest, DeeplyNestedDictsAndArrays) {
+ protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
+
+ msg->set_name("root");
+ auto* dict1 = msg->add_dict_entries();
+ dict1->set_name("k1");
+ auto* array1 = dict1->add_array_values();
+ auto* dict2 = array1->add_dict_entries();
+ dict2->set_name("k2");
+ auto* array2 = dict2->add_array_values();
+ array2->set_int_value(42);
+
+ DescriptorPool pool;
+ auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
+ kTestMessagesDescriptor.size());
+ EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
+ << status.message();
+
+ ProtoToArgsParser args_parser(pool);
+ DebugAnnotationParser parser(args_parser);
+
+ status = ParseDebugAnnotation(parser, msg, *this);
+ EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
+ << status.message();
+
+ EXPECT_THAT(args(), testing::ElementsAre("root.k1.k2 root.k1[0].k2[0] 42"));
+}
+
+// This test checks that array indexes are correctly merged across messages.
+TEST_F(DebugAnnotationParserTest, MergeArrays) {
+ protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg1;
+ msg1->set_name("root");
+ auto* item1 = msg1->add_array_values();
+ item1->set_int_value(1);
+
+ protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg2;
+ msg2->set_name("root");
+ auto* item2 = msg1->add_array_values();
+ item2->set_int_value(2);
+
+ DescriptorPool pool;
+ ProtoToArgsParser args_parser(pool);
+ DebugAnnotationParser parser(args_parser);
+
+ base::Status status = ParseDebugAnnotation(parser, msg1, *this);
+ EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
+ << status.message();
+
+ status = ParseDebugAnnotation(parser, msg2, *this);
+ EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
+ << status.message();
+
+ EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 2"));
+}
+
+// This test checks that nested empty dictionaries / arrays do not cause array
+// index to be incremented.
+TEST_F(DebugAnnotationParserTest, EmptyArrayIndexIsSkipped) {
+ protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
+ msg->set_name("root");
+
+ msg->add_array_values()->set_int_value(1);
+
+ // Empty item.
+ msg->add_array_values();
+
+ msg->add_array_values()->set_int_value(3);
+
+ // Empty dict.
+ msg->add_array_values()->add_dict_entries()->set_name("key1");
+
+ auto* nested_dict_entry = msg->add_array_values()->add_dict_entries();
+ nested_dict_entry->set_name("key2");
+ nested_dict_entry->set_string_value("value");
+
+ msg->add_array_values()->set_int_value(5);
+
+ DescriptorPool pool;
+ ProtoToArgsParser args_parser(pool);
+ DebugAnnotationParser parser(args_parser);
+
+ base::Status status = ParseDebugAnnotation(parser, msg, *this);
+ EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
+ << status.message();
+
+ EXPECT_THAT(args(), testing::ElementsAre("root root[0] 1", "root root[1] 3",
+ "root.key2 root[3].key2 value",
+ "root root[4] 5"));
+}
+
+TEST_F(DebugAnnotationParserTest, NestedArrays) {
+ protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
+ msg->set_name("root");
+ auto* item1 = msg->add_array_values();
+ item1->add_array_values()->set_int_value(1);
+ item1->add_array_values()->set_int_value(2);
+ auto* item2 = msg->add_array_values();
+ item2->add_array_values()->set_int_value(3);
+ item2->add_array_values()->set_int_value(4);
+
+ DescriptorPool pool;
+ ProtoToArgsParser args_parser(pool);
+ DebugAnnotationParser parser(args_parser);
+
+ base::Status status = ParseDebugAnnotation(parser, msg, *this);
+ EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
+ << status.message();
+
+ EXPECT_THAT(args(),
+ testing::ElementsAre("root root[0][0] 1", "root root[0][1] 2",
+ "root root[1][0] 3", "root root[1][1] 4"));
+}
+
+} // namespace
+} // namespace util
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/util/interned_message_view.h b/src/trace_processor/util/interned_message_view.h
new file mode 100644
index 0000000..7341aea
--- /dev/null
+++ b/src/trace_processor/util/interned_message_view.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 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_UTIL_INTERNED_MESSAGE_VIEW_H_
+#define SRC_TRACE_PROCESSOR_UTIL_INTERNED_MESSAGE_VIEW_H_
+
+#include "src/trace_processor/util/trace_blob_view.h"
+
+#include <unordered_map>
+
+namespace perfetto {
+namespace trace_processor {
+
+#if PERFETTO_DCHECK_IS_ON()
+// When called from GetOrCreateDecoder(), should include the stringified name of
+// the MessageType.
+#define PERFETTO_TYPE_IDENTIFIER PERFETTO_DEBUG_FUNCTION_IDENTIFIER()
+#else // PERFETTO_DCHECK_IS_ON()
+#define PERFETTO_TYPE_IDENTIFIER nullptr
+#endif // PERFETTO_DCHECK_IS_ON()
+
+// Entry in an interning index, refers to the interned message.
+class InternedMessageView {
+ public:
+ InternedMessageView(TraceBlobView msg) : message_(std::move(msg)) {}
+
+ InternedMessageView(InternedMessageView&&) = default;
+ InternedMessageView& operator=(InternedMessageView&&) = default;
+
+ // Allow copy by cloning the TraceBlobView. This is required for
+ // UpdateTracePacketDefaults().
+ InternedMessageView(const InternedMessageView& view)
+ : message_(view.message_.slice(0, view.message_.length())) {}
+ InternedMessageView& operator=(const InternedMessageView& view) {
+ this->message_ = view.message_.slice(0, view.message_.length());
+ this->decoder_ = nullptr;
+ this->decoder_type_ = nullptr;
+ this->submessages_.clear();
+ return *this;
+ }
+
+ // Lazily initializes and returns the decoder object for the message. The
+ // decoder is stored in the InternedMessageView to avoid having to parse the
+ // message multiple times.
+ template <typename MessageType>
+ typename MessageType::Decoder* GetOrCreateDecoder() {
+ if (!decoder_) {
+ // Lazy init the decoder and save it away, so that we don't have to
+ // reparse the message every time we access the interning entry.
+ decoder_ = std::unique_ptr<void, std::function<void(void*)>>(
+ new typename MessageType::Decoder(message_.data(), message_.length()),
+ [](void* obj) {
+ delete reinterpret_cast<typename MessageType::Decoder*>(obj);
+ });
+ decoder_type_ = PERFETTO_TYPE_IDENTIFIER;
+ }
+ // Verify that the type of the decoder didn't change.
+ if (PERFETTO_TYPE_IDENTIFIER &&
+ strcmp(decoder_type_,
+ // GCC complains if this arg can be null.
+ PERFETTO_TYPE_IDENTIFIER ? PERFETTO_TYPE_IDENTIFIER : "") != 0) {
+ PERFETTO_FATAL(
+ "Interning entry accessed under different types! previous type: "
+ "%s. new type: %s.",
+ decoder_type_, PERFETTO_DEBUG_FUNCTION_IDENTIFIER());
+ }
+ return reinterpret_cast<typename MessageType::Decoder*>(decoder_.get());
+ }
+
+ // Lookup a submessage of the interned message, which is then itself stored
+ // as InternedMessageView, so that we only need to parse it once. Returns
+ // nullptr if the field isn't set.
+ // TODO(eseckler): Support repeated fields.
+ template <typename MessageType, uint32_t FieldId>
+ InternedMessageView* GetOrCreateSubmessageView() {
+ auto it = submessages_.find(FieldId);
+ if (it != submessages_.end())
+ return it->second.get();
+ auto* decoder = GetOrCreateDecoder<MessageType>();
+ // Calls the at() template method on the decoder.
+ auto field = decoder->template at<FieldId>().as_bytes();
+ if (!field.data)
+ return nullptr;
+ const size_t offset = message_.offset_of(field.data);
+ TraceBlobView submessage = message_.slice(offset, field.size);
+ InternedMessageView* submessage_view =
+ new InternedMessageView(std::move(submessage));
+ submessages_.emplace_hint(
+ it, FieldId, std::unique_ptr<InternedMessageView>(submessage_view));
+ return submessage_view;
+ }
+
+ const TraceBlobView& message() { return message_; }
+
+ private:
+ using SubMessageViewMap =
+ std::unordered_map<uint32_t /*field_id*/,
+ std::unique_ptr<InternedMessageView>>;
+
+ TraceBlobView message_;
+
+ // Stores the decoder for the message_, so that the message does not have to
+ // be re-decoded every time the interned message is looked up. Lazily
+ // initialized in GetOrCreateDecoder(). Since we don't know the type of the
+ // decoder until GetOrCreateDecoder() is called, we store the decoder as a
+ // void* unique_pointer with a destructor function that's supplied in
+ // GetOrCreateDecoder() when the decoder is created.
+ std::unique_ptr<void, std::function<void(void*)>> decoder_;
+
+ // Type identifier for the decoder. Only valid in debug builds and on
+ // supported platforms. Used to verify that GetOrCreateDecoder() is always
+ // called with the same template argument.
+ const char* decoder_type_ = nullptr;
+
+ // Views of submessages of the interned message. Submessages are lazily
+ // added by GetOrCreateSubmessageView(). By storing submessages and their
+ // decoders, we avoid having to decode submessages multiple times if they
+ // looked up often.
+ SubMessageViewMap submessages_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_UTIL_INTERNED_MESSAGE_VIEW_H_
diff --git a/src/trace_processor/util/proto_to_args_parser.cc b/src/trace_processor/util/proto_to_args_parser.cc
index 6fec35e..8e4eb22 100644
--- a/src/trace_processor/util/proto_to_args_parser.cc
+++ b/src/trace_processor/util/proto_to_args_parser.cc
@@ -63,6 +63,33 @@
: flat_key(fk), key(k) {}
ProtoToArgsParser::Key::~Key() = default;
+ProtoToArgsParser::ScopedNestedKeyContext::ScopedNestedKeyContext(Key& key)
+ : key_(key),
+ old_flat_key_length_(key.flat_key.length()),
+ old_key_length_(key.key.length()) {}
+
+ProtoToArgsParser::ScopedNestedKeyContext::ScopedNestedKeyContext(
+ ProtoToArgsParser::ScopedNestedKeyContext&& other)
+ : key_(other.key_),
+ old_flat_key_length_(other.old_flat_key_length_),
+ old_key_length_(other.old_key_length_) {
+ other.old_flat_key_length_ = base::nullopt;
+ other.old_key_length_ = base::nullopt;
+}
+
+ProtoToArgsParser::ScopedNestedKeyContext::~ScopedNestedKeyContext() {
+ Reset();
+}
+
+void ProtoToArgsParser::ScopedNestedKeyContext::Reset() {
+ if (old_flat_key_length_)
+ key_.flat_key.resize(old_flat_key_length_.value());
+ if (old_key_length_)
+ key_.key.resize(old_key_length_.value());
+ old_flat_key_length_ = base::nullopt;
+ old_key_length_ = base::nullopt;
+}
+
ProtoToArgsParser::Delegate::~Delegate() = default;
ProtoToArgsParser::ProtoToArgsParser(const DescriptorPool& pool) : pool_(pool) {
@@ -238,6 +265,25 @@
}
}
+ProtoToArgsParser::ScopedNestedKeyContext ProtoToArgsParser::EnterArray(
+ size_t index) {
+ auto context = ScopedNestedKeyContext(key_prefix_);
+ key_prefix_.key += "[" + std::to_string(index) + "]";
+ return context;
+}
+
+ProtoToArgsParser::ScopedNestedKeyContext ProtoToArgsParser::EnterDictionary(
+ const std::string& name) {
+ auto context = ScopedNestedKeyContext(key_prefix_);
+ if (!key_prefix_.key.empty())
+ key_prefix_.key += '.';
+ key_prefix_.key += name;
+ if (!key_prefix_.flat_key.empty())
+ key_prefix_.flat_key += '.';
+ key_prefix_.flat_key += name;
+ return context;
+}
+
} // namespace util
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/util/proto_to_args_parser.h b/src/trace_processor/util/proto_to_args_parser.h
index f99179c..9110e91 100644
--- a/src/trace_processor/util/proto_to_args_parser.h
+++ b/src/trace_processor/util/proto_to_args_parser.h
@@ -83,9 +83,13 @@
virtual void AddDouble(const Key& key, double value) = 0;
virtual void AddPointer(const Key& key, const void* value) = 0;
virtual void AddBoolean(const Key& key, bool value) = 0;
- virtual void AddJson(const Key& key,
+ // Returns whether an entry was added or not.
+ virtual bool AddJson(const Key& key,
const protozero::ConstChars& value) = 0;
+ virtual size_t GetArrayEntryIndex(const std::string& array_key) = 0;
+ virtual size_t IncrementArrayEntryIndex(const std::string& array_key) = 0;
+
template <typename FieldMetadata>
typename FieldMetadata::cpp_field_type::Decoder* GetInternedMessage(
protozero::proto_utils::internal::FieldMetadataHelper<FieldMetadata>,
@@ -159,6 +163,37 @@
const std::vector<uint16_t>* allowed_fields,
Delegate& delegate);
+ struct ScopedNestedKeyContext {
+ public:
+ ~ScopedNestedKeyContext();
+ ScopedNestedKeyContext(ScopedNestedKeyContext&&);
+ ScopedNestedKeyContext(const ScopedNestedKeyContext&) = delete;
+ ScopedNestedKeyContext& operator=(const ScopedNestedKeyContext&) = delete;
+
+ const Key& key() const { return key_; }
+
+ // Reset this context, which sets |key_| to the state before the nested
+ // context was created.
+ void Reset();
+
+ private:
+ friend class ProtoToArgsParser;
+
+ ScopedNestedKeyContext(Key& old_value);
+
+ struct ScopedStringAppender;
+
+ Key& key_;
+ base::Optional<size_t> old_flat_key_length_ = base::nullopt;
+ base::Optional<size_t> old_key_length_ = base::nullopt;
+ };
+
+ // These methods can be called from parsing overrides to enter nested
+ // contexts. The contexts are left when the returned scope is destroyed or
+ // reset.
+ ScopedNestedKeyContext EnterDictionary(const std::string& key);
+ ScopedNestedKeyContext EnterArray(size_t index);
+
private:
base::Status ParseField(const FieldDescriptor& field_descriptor,
int repeated_field_number,
diff --git a/src/trace_processor/util/proto_to_args_parser_unittest.cc b/src/trace_processor/util/proto_to_args_parser_unittest.cc
index 89ee945..a8d17f6 100644
--- a/src/trace_processor/util/proto_to_args_parser_unittest.cc
+++ b/src/trace_processor/util/proto_to_args_parser_unittest.cc
@@ -21,9 +21,9 @@
#include "protos/perfetto/common/descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
#include "src/protozero/test/example_proto/test_messages.pbzero.h"
-#include "src/trace_processor/importers/common/trace_blob_view.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/test_messages.descriptor.h"
+#include "src/trace_processor/util/interned_message_view.h"
+#include "src/trace_processor/util/trace_blob_view.h"
#include "test/gtest_and_gmock.h"
#include <sstream>
@@ -92,13 +92,18 @@
args_.push_back(ss.str());
}
- void AddJson(const Key& key, const protozero::ConstChars& value) override {
+ bool AddJson(const Key& key, const protozero::ConstChars& value) override {
std::stringstream ss;
ss << key.flat_key << " " << key.key << " " << std::hex
<< value.ToStdString() << std::dec;
args_.push_back(ss.str());
+ return true;
}
+ size_t GetArrayEntryIndex(const std::string&) final { return 0; }
+
+ size_t IncrementArrayEntryIndex(const std::string&) final { return 0; }
+
InternedMessageView* GetInternedMessageView(uint32_t field_id,
uint64_t iid) override {
if (field_id != protos::pbzero::InternedData::kSourceLocationsFieldNumber)
diff --git a/src/trace_processor/importers/common/trace_blob_view.h b/src/trace_processor/util/trace_blob_view.h
similarity index 95%
rename from src/trace_processor/importers/common/trace_blob_view.h
rename to src/trace_processor/util/trace_blob_view.h
index a94a994..7d9c1a4 100644
--- a/src/trace_processor/importers/common/trace_blob_view.h
+++ b/src/trace_processor/util/trace_blob_view.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_TRACE_BLOB_VIEW_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_TRACE_BLOB_VIEW_H_
+#ifndef SRC_TRACE_PROCESSOR_UTIL_TRACE_BLOB_VIEW_H_
+#define SRC_TRACE_PROCESSOR_UTIL_TRACE_BLOB_VIEW_H_
#include <stddef.h>
#include <stdint.h>
@@ -145,4 +145,4 @@
} // namespace trace_processor
} // namespace perfetto
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_TRACE_BLOB_VIEW_H_
+#endif // SRC_TRACE_PROCESSOR_UTIL_TRACE_BLOB_VIEW_H_
diff --git a/test/trace_processor/track_event/track_event_merged_debug_annotations_args.out b/test/trace_processor/track_event/track_event_merged_debug_annotations_args.out
index b0c0529..8cecb1d 100644
--- a/test/trace_processor/track_event/track_event_merged_debug_annotations_args.out
+++ b/test/trace_processor/track_event/track_event_merged_debug_annotations_args.out
@@ -22,6 +22,6 @@
"debug.debug2.key4","debug.debug2.key4",40,"[NULL]"
"debug.debug3","debug.debug3",32,"[NULL]"
"debug.debug4.key1","debug.debug4.key1",10,"[NULL]"
-"debug.debug4.key2[0]","debug.debug4.key2[0]",20,"[NULL]"
-"debug.debug4.key2[1]","debug.debug4.key2[1]",21,"[NULL]"
+"debug.debug4.key2","debug.debug4.key2[0]",20,"[NULL]"
+"debug.debug4.key2","debug.debug4.key2[1]",21,"[NULL]"
"legacy_event.passthrough_utid","legacy_event.passthrough_utid",1,"[NULL]"