processor: Move TrackEvent tokenizing & parsing into module
Extracts the logic for tokenizing and parsing TrackEvents (+ related
descriptors) into TrackEventModule.
Bug: 141459049
Change-Id: Ib9bfe49d001b3e415be74757ff8f0c9a732b42e6
diff --git a/Android.bp b/Android.bp
index d42ffc9..e7d12ee 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4559,6 +4559,8 @@
"src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc",
"src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.cc",
"src/trace_processor/importers/fuchsia/fuchsia_trace_utils.cc",
+ "src/trace_processor/importers/proto/track_event_parser.cc",
+ "src/trace_processor/importers/proto/track_event_tokenizer.cc",
"src/trace_processor/importers/systrace/systrace_parser.cc",
"src/trace_processor/importers/systrace/systrace_trace_parser.cc",
"src/trace_processor/instants_table.cc",
diff --git a/BUILD b/BUILD
index a716bda..0965d30 100644
--- a/BUILD
+++ b/BUILD
@@ -677,8 +677,14 @@
"src/trace_processor/importers/json/json_trace_tokenizer.h",
"src/trace_processor/importers/json/json_trace_utils.cc",
"src/trace_processor/importers/json/json_trace_utils.h",
+ "src/trace_processor/importers/proto/packet_sequence_state.h",
"src/trace_processor/importers/proto/proto_importer_module.h",
+ "src/trace_processor/importers/proto/proto_incremental_state.h",
"src/trace_processor/importers/proto/track_event_module.h",
+ "src/trace_processor/importers/proto/track_event_parser.cc",
+ "src/trace_processor/importers/proto/track_event_parser.h",
+ "src/trace_processor/importers/proto/track_event_tokenizer.cc",
+ "src/trace_processor/importers/proto/track_event_tokenizer.h",
"src/trace_processor/importers/systrace/systrace_parser.cc",
"src/trace_processor/importers/systrace/systrace_parser.h",
"src/trace_processor/importers/systrace/systrace_trace_parser.cc",
@@ -692,7 +698,6 @@
"src/trace_processor/process_table.h",
"src/trace_processor/process_tracker.cc",
"src/trace_processor/process_tracker.h",
- "src/trace_processor/proto_incremental_state.h",
"src/trace_processor/proto_trace_parser.cc",
"src/trace_processor/proto_trace_parser.h",
"src/trace_processor/proto_trace_tokenizer.cc",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 4814052..9bc99ea 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -88,8 +88,14 @@
"importers/ftrace/ftrace_tokenizer.h",
"importers/ftrace/sched_event_tracker.h",
"importers/fuchsia/fuchsia_provider_view.h",
+ "importers/proto/packet_sequence_state.h",
"importers/proto/proto_importer_module.h",
+ "importers/proto/proto_incremental_state.h",
"importers/proto/track_event_module.h",
+ "importers/proto/track_event_parser.cc",
+ "importers/proto/track_event_parser.h",
+ "importers/proto/track_event_tokenizer.cc",
+ "importers/proto/track_event_tokenizer.h",
"importers/systrace/systrace_parser.h",
"importers/systrace/systrace_trace_parser.h",
"instants_table.cc",
@@ -101,7 +107,6 @@
"process_table.h",
"process_tracker.cc",
"process_tracker.h",
- "proto_incremental_state.h",
"proto_trace_parser.cc",
"proto_trace_parser.h",
"proto_trace_tokenizer.cc",
diff --git a/src/trace_processor/importers/ftrace/ftrace_module.h b/src/trace_processor/importers/ftrace/ftrace_module.h
index a08eecd..9d8d489 100644
--- a/src/trace_processor/importers/ftrace/ftrace_module.h
+++ b/src/trace_processor/importers/ftrace/ftrace_module.h
@@ -40,7 +40,8 @@
ModuleResult TokenizePacket(
const protos::pbzero::TracePacket::Decoder& decoder,
TraceBlobView* packet,
- int64_t /*packet_timestamp*/) {
+ int64_t /*packet_timestamp*/,
+ PacketSequenceState* /*state*/) {
if (decoder.has_ftrace_events()) {
auto ftrace_field = decoder.ftrace_events();
const size_t fld_off = packet->offset_of(ftrace_field.data);
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
new file mode 100644
index 0000000..8ee597b
--- /dev/null
+++ b/src/trace_processor/importers/proto/packet_sequence_state.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
+
+#include <stdint.h>
+
+#include <unordered_map>
+#include <vector>
+
+#include "perfetto/protozero/proto_decoder.h"
+#include "src/trace_processor/stack_profile_tracker.h"
+#include "src/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/trace_processor_context.h"
+#include "src/trace_processor/trace_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+#if PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
+// When called from GetOrCreateDecoder(), __PRETTY_FUNCTION__ (supported by GCC
+// + clang) should include the stringified name of the MessageType.
+#define PERFETTO_TYPE_IDENTIFIER __PRETTY_FUNCTION__
+#else // PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
+#define PERFETTO_TYPE_IDENTIFIER nullptr
+#endif // PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
+
+class PacketSequenceState {
+ public:
+ // Entry in an interning index, refers to the interned message.
+ struct InternedMessageView {
+ InternedMessageView(TraceBlobView msg) : message(std::move(msg)) {}
+
+ 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, __PRETTY_FUNCTION__);
+ }
+ return reinterpret_cast<typename MessageType::Decoder*>(decoder.get());
+ }
+
+ TraceBlobView message;
+ std::unique_ptr<void, std::function<void(void*)>> decoder;
+
+ private:
+ const char* decoder_type = nullptr;
+ };
+
+ using InternedMessageMap =
+ std::unordered_map<uint64_t /*iid*/, InternedMessageView>;
+ using InternedFieldMap =
+ std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
+ using InternedDataGenerationList = std::vector<InternedFieldMap>;
+
+ PacketSequenceState(TraceProcessorContext* context)
+ : context_(context), stack_profile_tracker_(context) {
+ interned_data_.emplace_back();
+ }
+
+ int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
+ PERFETTO_DCHECK(track_event_timestamps_valid());
+ track_event_timestamp_ns_ += delta_ns;
+ return track_event_timestamp_ns_;
+ }
+
+ int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
+ PERFETTO_DCHECK(track_event_timestamps_valid());
+ track_event_thread_timestamp_ns_ += delta_ns;
+ return track_event_thread_timestamp_ns_;
+ }
+
+ int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
+ PERFETTO_DCHECK(track_event_timestamps_valid());
+ track_event_thread_instruction_count_ += delta;
+ return track_event_thread_instruction_count_;
+ }
+
+ void OnPacketLoss() {
+ packet_loss_ = true;
+ track_event_timestamps_valid_ = false;
+ }
+
+ void OnIncrementalStateCleared() {
+ packet_loss_ = false;
+ interned_data_.emplace_back(); // Bump generation number
+ }
+
+ void SetThreadDescriptor(int32_t pid,
+ int32_t tid,
+ int64_t timestamp_ns,
+ int64_t thread_timestamp_ns,
+ int64_t thread_instruction_count) {
+ track_event_timestamps_valid_ = true;
+ pid_and_tid_valid_ = true;
+ pid_ = pid;
+ tid_ = tid;
+ track_event_timestamp_ns_ = timestamp_ns;
+ track_event_thread_timestamp_ns_ = thread_timestamp_ns;
+ track_event_thread_instruction_count_ = thread_instruction_count;
+ }
+
+ bool IsIncrementalStateValid() const { return !packet_loss_; }
+
+ StackProfileTracker& stack_profile_tracker() {
+ return stack_profile_tracker_;
+ }
+
+ // Returns the index of the current generation in the
+ // InternedDataGenerationList.
+ size_t current_generation() const { return interned_data_.size() - 1; }
+
+ bool track_event_timestamps_valid() const {
+ return track_event_timestamps_valid_;
+ }
+
+ bool pid_and_tid_valid() const { return pid_and_tid_valid_; }
+
+ int32_t pid() const { return pid_; }
+ int32_t tid() const { return tid_; }
+
+ void InternMessage(uint32_t field_id, TraceBlobView message) {
+ constexpr auto kIidFieldNumber = 1;
+
+ uint64_t iid = 0;
+ auto message_start = message.data();
+ auto message_size = message.length();
+ protozero::ProtoDecoder decoder(message_start, message_size);
+
+ auto field = decoder.FindField(kIidFieldNumber);
+ if (PERFETTO_UNLIKELY(!field)) {
+ PERFETTO_DLOG("Interned message without interning_id");
+ context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
+ return;
+ }
+ iid = field.as_uint64();
+
+ auto* map = &interned_data_.back()[field_id];
+ auto res = map->emplace(iid, InternedMessageView(std::move(message)));
+
+ // If a message with this ID is already interned in the same generation,
+ // its data should not have changed (this is forbidden by the InternedData
+ // proto).
+ // TODO(eseckler): This DCHECK assumes that the message is encoded the
+ // same way if it is re-emitted.
+ PERFETTO_DCHECK(res.second ||
+ (res.first->second.message.length() == message_size &&
+ memcmp(res.first->second.message.data(), message_start,
+ message_size) == 0));
+ }
+
+ template <uint32_t FieldId, typename MessageType>
+ typename MessageType::Decoder* LookupInternedMessage(size_t generation,
+ uint64_t iid) {
+ PERFETTO_CHECK(generation <= interned_data_.size());
+ auto* field_map = &interned_data_[generation];
+ auto field_it = field_map->find(FieldId);
+ if (field_it != field_map->end()) {
+ auto* message_map = &field_it->second;
+ auto it = message_map->find(iid);
+ if (it != message_map->end()) {
+ return it->second.GetOrCreateDecoder<MessageType>();
+ }
+ }
+ context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
+ PERFETTO_DLOG("Could not find interning entry for field ID %" PRIu32
+ ", generation %zu, and IID %" PRIu64,
+ FieldId, generation, iid);
+ return nullptr;
+ }
+
+ private:
+ TraceProcessorContext* context_;
+
+ // If true, incremental state on the sequence is considered invalid until we
+ // see the next packet with incremental_state_cleared. We assume that we
+ // missed some packets at the beginning of the trace.
+ bool packet_loss_ = true;
+
+ // We can only consider TrackEvent delta timestamps to be correct after we
+ // have observed a thread descriptor (since the last packet loss).
+ bool track_event_timestamps_valid_ = false;
+
+ // |pid_| and |tid_| are only valid after we parsed at least one
+ // ThreadDescriptor packet on the sequence.
+ bool pid_and_tid_valid_ = false;
+
+ // Process/thread ID of the packet sequence set by a ThreadDescriptor
+ // packet. Used as default values for TrackEvents that don't specify a
+ // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
+ int32_t pid_ = 0;
+ int32_t tid_ = 0;
+
+ // Current wall/thread timestamps/counters used as reference for the next
+ // TrackEvent delta timestamp.
+ int64_t track_event_timestamp_ns_ = 0;
+ int64_t track_event_thread_timestamp_ns_ = 0;
+ int64_t track_event_thread_instruction_count_ = 0;
+
+ InternedDataGenerationList interned_data_;
+ StackProfileTracker stack_profile_tracker_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/proto_importer_module.h b/src/trace_processor/importers/proto/proto_importer_module.h
index 23b3fac..d7efaf9 100644
--- a/src/trace_processor/importers/proto/proto_importer_module.h
+++ b/src/trace_processor/importers/proto/proto_importer_module.h
@@ -26,6 +26,7 @@
namespace perfetto {
namespace trace_processor {
+class PacketSequenceState;
struct TimestampedTracePiece;
class TraceProcessorContext;
@@ -121,9 +122,11 @@
ModuleResult TokenizePacket(
const protos::pbzero::TracePacket::Decoder& decoder,
TraceBlobView* packet,
- int64_t packet_timestamp) {
- if (ModuleType::kEnabled)
- return impl_->TokenizePacket(decoder, packet, packet_timestamp);
+ int64_t packet_timestamp,
+ PacketSequenceState* state) {
+ if (ModuleType::kEnabled) {
+ return impl_->TokenizePacket(decoder, packet, packet_timestamp, state);
+ }
return ModuleResult::Ignored();
}
diff --git a/src/trace_processor/importers/proto/proto_incremental_state.h b/src/trace_processor/importers/proto/proto_incremental_state.h
new file mode 100644
index 0000000..aaac42f
--- /dev/null
+++ b/src/trace_processor/importers/proto/proto_incremental_state.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
+
+#include <stdint.h>
+
+#include <map>
+
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+// Stores per-packet-sequence incremental state during trace parsing, such as
+// reference timestamps for delta timestamp calculation and interned messages.
+class ProtoIncrementalState {
+ public:
+ ProtoIncrementalState(TraceProcessorContext* context) : context_(context) {}
+
+ // Returns the PacketSequenceState for the packet sequence with the given id.
+ // If this is a new sequence which we haven't tracked before, initializes and
+ // inserts a new PacketSequenceState into the state map.
+ PacketSequenceState* GetOrCreateStateForPacketSequence(uint32_t sequence_id) {
+ auto& ptr = packet_sequence_states_[sequence_id];
+ if (!ptr)
+ ptr.reset(new PacketSequenceState(context_));
+ return ptr.get();
+ }
+
+ private:
+ // Stores unique_ptrs to ensure that pointers to a PacketSequenceState remain
+ // valid even if the map rehashes.
+ std::map<uint32_t, std::unique_ptr<PacketSequenceState>>
+ packet_sequence_states_;
+
+ TraceProcessorContext* context_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
diff --git a/src/trace_processor/importers/proto/track_event_module.h b/src/trace_processor/importers/proto/track_event_module.h
index 1c66d34..6822139 100644
--- a/src/trace_processor/importers/proto/track_event_module.h
+++ b/src/trace_processor/importers/proto/track_event_module.h
@@ -19,6 +19,9 @@
#include "perfetto/base/build_config.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
+#include "src/trace_processor/importers/proto/track_event_parser.h"
+#include "src/trace_processor/importers/proto/track_event_tokenizer.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
namespace perfetto {
namespace trace_processor {
@@ -26,20 +29,56 @@
class TrackEventModule : public ProtoImporterModuleBase</*IsEnabled=*/1> {
public:
explicit TrackEventModule(TraceProcessorContext* context)
- : ProtoImporterModuleBase(context) {}
+ : ProtoImporterModuleBase(context),
+ tokenizer_(context),
+ parser_(context) {}
- ModuleResult TokenizePacket(const protos::pbzero::TracePacket::Decoder&,
- TraceBlobView* /*packet*/,
- int64_t /*packet_timestamp*/) {
- // TODO(eseckler): implement.
+ ModuleResult TokenizePacket(
+ const protos::pbzero::TracePacket::Decoder& decoder,
+ TraceBlobView* packet,
+ int64_t packet_timestamp,
+ PacketSequenceState* state) {
+ if (decoder.has_track_descriptor()) {
+ tokenizer_.TokenizeTrackDescriptorPacket(decoder);
+ return ModuleResult::Handled();
+ }
+
+ if (decoder.has_track_event()) {
+ tokenizer_.TokenizeTrackEventPacket(state, decoder, packet,
+ packet_timestamp);
+ return ModuleResult::Handled();
+ }
+
+ // TODO(eseckler): Remove these once Chrome has switched fully over to
+ // TrackDescriptors.
+ if (decoder.has_thread_descriptor()) {
+ tokenizer_.TokenizeThreadDescriptorPacket(state, decoder);
+ return ModuleResult::Handled();
+ }
+ if (decoder.has_process_descriptor()) {
+ tokenizer_.TokenizeProcessDescriptorPacket(decoder);
+ return ModuleResult::Handled();
+ }
+
return ModuleResult::Ignored();
}
- ModuleResult ParsePacket(const protos::pbzero::TracePacket::Decoder&,
- const TimestampedTracePiece&) {
+ ModuleResult ParsePacket(const protos::pbzero::TracePacket::Decoder& decoder,
+ const TimestampedTracePiece& ttp) {
// TODO(eseckler): implement.
+ if (decoder.has_track_event()) {
+ parser_.ParseTrackEvent(
+ ttp.timestamp, ttp.thread_timestamp, ttp.thread_instruction_count,
+ ttp.packet_sequence_state, ttp.packet_sequence_state_generation,
+ decoder.track_event());
+ return ModuleResult::Handled();
+ }
return ModuleResult::Ignored();
}
+
+ private:
+ TrackEventTokenizer tokenizer_;
+ TrackEventParser parser_;
};
} // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
new file mode 100644
index 0000000..6f2b46f
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -0,0 +1,893 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/importers/proto/track_event_parser.h"
+
+#include <string>
+
+#include "perfetto/base/logging.h"
+#include "src/trace_processor/args_tracker.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/process_tracker.h"
+#include "src/trace_processor/track_tracker.h"
+
+#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
+#include "protos/perfetto/trace/track_event/log_message.pbzero.h"
+#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
+#include "protos/perfetto/trace/track_event/task_execution.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+namespace {
+using protozero::ConstBytes;
+
+// Slices which have been opened but haven't been closed yet will be marked
+// with these placeholder values.
+constexpr int64_t kPendingThreadDuration = -1;
+constexpr int64_t kPendingThreadInstructionDelta = -1;
+} // namespace
+
+TrackEventParser::TrackEventParser(TraceProcessorContext* context)
+ : context_(context),
+ task_file_name_args_key_id_(
+ context->storage->InternString("task.posted_from.file_name")),
+ task_function_name_args_key_id_(
+ context->storage->InternString("task.posted_from.function_name")),
+ task_line_number_args_key_id_(
+ context->storage->InternString("task.posted_from.line_number")),
+ log_message_body_key_id_(
+ context->storage->InternString("track_event.log_message")),
+ raw_legacy_event_id_(
+ context->storage->InternString("track_event.legacy_event")),
+ legacy_event_category_key_id_(
+ context->storage->InternString("legacy_event.category")),
+ legacy_event_name_key_id_(
+ context->storage->InternString("legacy_event.name")),
+ legacy_event_phase_key_id_(
+ context->storage->InternString("legacy_event.phase")),
+ legacy_event_duration_ns_key_id_(
+ context->storage->InternString("legacy_event.duration_ns")),
+ legacy_event_thread_timestamp_ns_key_id_(
+ context->storage->InternString("legacy_event.thread_timestamp_ns")),
+ legacy_event_thread_duration_ns_key_id_(
+ context->storage->InternString("legacy_event.thread_duration_ns")),
+ legacy_event_thread_instruction_count_key_id_(
+ context->storage->InternString(
+ "legacy_event.thread_instruction_count")),
+ legacy_event_thread_instruction_delta_key_id_(
+ context->storage->InternString(
+ "legacy_event.thread_instruction_delta")),
+ legacy_event_use_async_tts_key_id_(
+ context->storage->InternString("legacy_event.use_async_tts")),
+ legacy_event_unscoped_id_key_id_(
+ context->storage->InternString("legacy_event.unscoped_id")),
+ legacy_event_global_id_key_id_(
+ context->storage->InternString("legacy_event.global_id")),
+ legacy_event_local_id_key_id_(
+ context->storage->InternString("legacy_event.local_id")),
+ legacy_event_id_scope_key_id_(
+ context->storage->InternString("legacy_event.id_scope")),
+ legacy_event_bind_id_key_id_(
+ context->storage->InternString("legacy_event.bind_id")),
+ legacy_event_bind_to_enclosing_key_id_(
+ context->storage->InternString("legacy_event.bind_to_enclosing")),
+ legacy_event_flow_direction_key_id_(
+ context->storage->InternString("legacy_event.flow_direction")),
+ flow_direction_value_in_id_(context->storage->InternString("in")),
+ flow_direction_value_out_id_(context->storage->InternString("out")),
+ flow_direction_value_inout_id_(context->storage->InternString("inout")) {}
+
+void TrackEventParser::ParseTrackEvent(int64_t ts,
+ int64_t tts,
+ int64_t ticount,
+ PacketSequenceState* sequence_state,
+ size_t sequence_state_generation,
+ ConstBytes blob) {
+ using LegacyEvent = protos::pbzero::TrackEvent::LegacyEvent;
+
+ protos::pbzero::TrackEvent::Decoder event(blob.data, blob.size);
+
+ const auto legacy_event_blob = event.legacy_event();
+ LegacyEvent::Decoder legacy_event(legacy_event_blob.data,
+ legacy_event_blob.size);
+
+ // TODO(eseckler): This legacy event field will eventually be replaced by
+ // fields in TrackEvent itself.
+ if (PERFETTO_UNLIKELY(!event.type() && !legacy_event.has_phase())) {
+ context_->storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("TrackEvent without type or phase");
+ return;
+ }
+
+ ProcessTracker* procs = context_->process_tracker.get();
+ TraceStorage* storage = context_->storage.get();
+ TrackTracker* track_tracker = context_->track_tracker.get();
+ SliceTracker* slice_tracker = context_->slice_tracker.get();
+
+ std::vector<uint64_t> category_iids;
+ for (auto it = event.category_iids(); it; ++it) {
+ category_iids.push_back(*it);
+ }
+ std::vector<protozero::ConstChars> category_strings;
+ for (auto it = event.categories(); it; ++it) {
+ category_strings.push_back(*it);
+ }
+
+ StringId category_id = 0;
+
+ // If there's a single category, we can avoid building a concatenated
+ // string.
+ if (PERFETTO_LIKELY(category_iids.size() == 1 && category_strings.empty())) {
+ auto* decoder = sequence_state->LookupInternedMessage<
+ protos::pbzero::InternedData::kEventCategoriesFieldNumber,
+ protos::pbzero::EventCategory>(sequence_state_generation,
+ category_iids[0]);
+ if (decoder)
+ category_id = storage->InternString(decoder->name());
+ } else if (category_iids.empty() && category_strings.size() == 1) {
+ category_id = storage->InternString(category_strings[0]);
+ } else if (category_iids.size() + category_strings.size() > 1) {
+ // We concatenate the category strings together since we currently only
+ // support a single "cat" column.
+ // TODO(eseckler): Support multi-category events in the table schema.
+ std::string categories;
+ for (uint64_t iid : category_iids) {
+ auto* decoder = sequence_state->LookupInternedMessage<
+ protos::pbzero::InternedData::kEventCategoriesFieldNumber,
+ protos::pbzero::EventCategory>(sequence_state_generation, iid);
+ if (!decoder)
+ continue;
+ base::StringView name = decoder->name();
+ if (!categories.empty())
+ categories.append(",");
+ categories.append(name.data(), name.size());
+ }
+ for (const protozero::ConstChars& cat : category_strings) {
+ if (!categories.empty())
+ categories.append(",");
+ categories.append(cat.data, cat.size);
+ }
+ if (!categories.empty())
+ category_id = storage->InternString(base::StringView(categories));
+ }
+
+ StringId name_id = 0;
+
+ uint64_t name_iid = event.name_iid();
+ if (!name_iid)
+ name_iid = legacy_event.name_iid();
+
+ if (PERFETTO_LIKELY(name_iid)) {
+ auto* decoder = sequence_state->LookupInternedMessage<
+ protos::pbzero::InternedData::kEventNamesFieldNumber,
+ protos::pbzero::EventName>(sequence_state_generation, name_iid);
+ if (decoder)
+ name_id = storage->InternString(decoder->name());
+ } else if (event.has_name()) {
+ name_id = storage->InternString(event.name());
+ }
+
+ // TODO(eseckler): Also consider track_uuid from TrackEventDefaults.
+ // Fall back to the default descriptor track (uuid 0).
+ uint64_t track_uuid = event.has_track_uuid() ? event.track_uuid() : 0u;
+ TrackId track_id;
+ base::Optional<UniqueTid> utid;
+ base::Optional<UniqueTid> upid;
+
+ // Determine track from track_uuid specified in either TrackEvent or
+ // TrackEventDefaults. If none is set, fall back to the track specified by the
+ // sequence's (or event's) pid + tid or a default track.
+ if (track_uuid) {
+ base::Optional<TrackId> opt_track_id =
+ track_tracker->GetDescriptorTrack(track_uuid);
+ if (!opt_track_id) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("TrackEvent with unknown track_uuid %" PRIu64, track_uuid);
+ return;
+ }
+ track_id = *opt_track_id;
+
+ auto thread_track_row =
+ context_->storage->thread_track_table().id().IndexOf(
+ SqlValue::Long(track_id));
+ if (thread_track_row) {
+ utid = storage->thread_track_table().utid()[*thread_track_row];
+ upid = storage->GetThread(*utid).upid;
+ } else {
+ auto process_track_row =
+ context_->storage->process_track_table().id().IndexOf(
+ SqlValue::Long(track_id));
+ if (process_track_row)
+ upid = storage->process_track_table().upid()[*process_track_row];
+ }
+ } else if (sequence_state->pid_and_tid_valid() ||
+ (legacy_event.has_pid_override() &&
+ legacy_event.has_tid_override())) {
+ uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
+ uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
+ if (legacy_event.has_pid_override())
+ pid = static_cast<uint32_t>(legacy_event.pid_override());
+ if (legacy_event.has_tid_override())
+ tid = static_cast<uint32_t>(legacy_event.tid_override());
+
+ utid = procs->UpdateThread(tid, pid);
+ upid = storage->GetThread(*utid).upid;
+ track_id = track_tracker->GetOrCreateDescriptorTrackForThread(*utid);
+ } else {
+ track_id = track_tracker->GetOrCreateDefaultDescriptorTrack();
+ }
+
+ // TODO(eseckler): Replace phase with type and remove handling of
+ // legacy_event.phase() once it is no longer used by producers.
+ int32_t phase = 0;
+ if (legacy_event.has_phase()) {
+ phase = legacy_event.phase();
+
+ switch (phase) {
+ case 'b':
+ case 'e':
+ case 'n': {
+ // Intern tracks for legacy async events based on legacy event ids.
+ int64_t source_id = 0;
+ bool source_id_is_process_scoped = false;
+ if (legacy_event.has_unscoped_id()) {
+ source_id = static_cast<int64_t>(legacy_event.unscoped_id());
+ } else if (legacy_event.has_global_id()) {
+ source_id = static_cast<int64_t>(legacy_event.global_id());
+ } else if (legacy_event.has_local_id()) {
+ if (!upid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG(
+ "TrackEvent with local_id without process association");
+ return;
+ }
+
+ source_id = static_cast<int64_t>(legacy_event.local_id());
+ source_id_is_process_scoped = true;
+ } else {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("Async LegacyEvent without ID");
+ return;
+ }
+
+ // Catapult treats nestable async events of different categories with
+ // the same ID as separate tracks. We replicate the same behavior here.
+ StringId id_scope = category_id;
+ if (legacy_event.has_id_scope()) {
+ std::string concat = storage->GetString(category_id).ToStdString() +
+ ":" + legacy_event.id_scope().ToStdString();
+ id_scope = storage->InternString(base::StringView(concat));
+ }
+
+ track_id = context_->track_tracker->InternLegacyChromeAsyncTrack(
+ name_id, upid ? *upid : 0, source_id, source_id_is_process_scoped,
+ id_scope);
+ break;
+ }
+ case 'i':
+ case 'I': {
+ // Intern tracks for global or process-scoped legacy instant events.
+ switch (legacy_event.instant_event_scope()) {
+ case LegacyEvent::SCOPE_UNSPECIFIED:
+ case LegacyEvent::SCOPE_THREAD:
+ // Thread-scoped legacy instant events already have the right track
+ // based on the tid/pid of the sequence.
+ if (!utid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG(
+ "Thread-scoped instant event without thread association");
+ return;
+ }
+ break;
+ case LegacyEvent::SCOPE_GLOBAL:
+ track_id = context_->track_tracker
+ ->GetOrCreateLegacyChromeGlobalInstantTrack();
+ break;
+ case LegacyEvent::SCOPE_PROCESS:
+ if (!upid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG(
+ "Process-scoped instant event without process association");
+ return;
+ }
+
+ track_id =
+ context_->track_tracker->InternLegacyChromeProcessInstantTrack(
+ *upid);
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } else {
+ switch (event.type()) {
+ case protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN:
+ phase = utid ? 'B' : 'b';
+ break;
+ case protos::pbzero::TrackEvent::TYPE_SLICE_END:
+ phase = utid ? 'E' : 'e';
+ break;
+ case protos::pbzero::TrackEvent::TYPE_INSTANT:
+ phase = utid ? 'i' : 'n';
+ break;
+ default:
+ PERFETTO_FATAL("unexpected event type %d", event.type());
+ return;
+ }
+ }
+
+ auto args_callback = [this, &event, &legacy_event, &sequence_state,
+ sequence_state_generation, ts,
+ utid](ArgsTracker* args_tracker, RowId row_id) {
+ for (auto it = event.debug_annotations(); it; ++it) {
+ ParseDebugAnnotationArgs(*it, sequence_state, sequence_state_generation,
+ args_tracker, row_id);
+ }
+
+ if (event.has_task_execution()) {
+ ParseTaskExecutionArgs(event.task_execution(), sequence_state,
+ sequence_state_generation, args_tracker, row_id);
+ }
+
+ if (event.has_log_message()) {
+ ParseLogMessage(event.log_message(), sequence_state,
+ sequence_state_generation, ts, utid, args_tracker,
+ row_id);
+ }
+
+ // TODO(eseckler): Parse legacy flow events into flow events table once we
+ // have a design for it.
+ if (legacy_event.has_bind_id()) {
+ args_tracker->AddArg(row_id, legacy_event_bind_id_key_id_,
+ legacy_event_bind_id_key_id_,
+ Variadic::UnsignedInteger(legacy_event.bind_id()));
+ }
+
+ if (legacy_event.bind_to_enclosing()) {
+ args_tracker->AddArg(row_id, legacy_event_bind_to_enclosing_key_id_,
+ legacy_event_bind_to_enclosing_key_id_,
+ Variadic::Boolean(true));
+ }
+
+ if (legacy_event.flow_direction()) {
+ StringId value;
+ switch (legacy_event.flow_direction()) {
+ case protos::pbzero::TrackEvent::LegacyEvent::FLOW_IN:
+ value = flow_direction_value_in_id_;
+ break;
+ case protos::pbzero::TrackEvent::LegacyEvent::FLOW_OUT:
+ value = flow_direction_value_out_id_;
+ break;
+ case protos::pbzero::TrackEvent::LegacyEvent::FLOW_INOUT:
+ value = flow_direction_value_inout_id_;
+ break;
+ default:
+ PERFETTO_FATAL("Unknown flow direction: %d",
+ legacy_event.flow_direction());
+ break;
+ }
+ args_tracker->AddArg(row_id, legacy_event_flow_direction_key_id_,
+ legacy_event_flow_direction_key_id_,
+ Variadic::String(value));
+ }
+ };
+
+ switch (static_cast<char>(phase)) {
+ case 'B': { // TRACE_EVENT_PHASE_BEGIN.
+ if (!utid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("TrackEvent with phase B without thread association");
+ return;
+ }
+
+ auto opt_slice_id =
+ slice_tracker->Begin(ts, track_id, *utid, RefType::kRefUtid,
+ category_id, name_id, args_callback);
+ if (opt_slice_id.has_value()) {
+ auto* thread_slices = storage->mutable_thread_slices();
+ PERFETTO_DCHECK(!thread_slices->slice_count() ||
+ thread_slices->slice_ids().back() <
+ opt_slice_id.value());
+ thread_slices->AddThreadSlice(opt_slice_id.value(), tts,
+ kPendingThreadDuration, ticount,
+ kPendingThreadInstructionDelta);
+ }
+ break;
+ }
+ case 'E': { // TRACE_EVENT_PHASE_END.
+ if (!utid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("TrackEvent with phase E without thread association");
+ return;
+ }
+
+ auto opt_slice_id =
+ slice_tracker->End(ts, track_id, category_id, name_id, args_callback);
+ if (opt_slice_id.has_value()) {
+ auto* thread_slices = storage->mutable_thread_slices();
+ thread_slices->UpdateThreadDeltasForSliceId(opt_slice_id.value(), tts,
+ ticount);
+ }
+ break;
+ }
+ case 'X': { // TRACE_EVENT_PHASE_COMPLETE.
+ if (!utid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("TrackEvent with phase X without thread association");
+ return;
+ }
+
+ auto duration_ns = legacy_event.duration_us() * 1000;
+ if (duration_ns < 0)
+ return;
+ auto opt_slice_id = slice_tracker->Scoped(
+ ts, track_id, *utid, RefType::kRefUtid, category_id, name_id,
+ duration_ns, args_callback);
+ if (opt_slice_id.has_value()) {
+ auto* thread_slices = storage->mutable_thread_slices();
+ PERFETTO_DCHECK(!thread_slices->slice_count() ||
+ thread_slices->slice_ids().back() <
+ opt_slice_id.value());
+ auto thread_duration_ns = legacy_event.thread_duration_us() * 1000;
+ thread_slices->AddThreadSlice(opt_slice_id.value(), tts,
+ thread_duration_ns, ticount,
+ legacy_event.thread_instruction_delta());
+ }
+ break;
+ }
+ case 'i':
+ case 'I': { // TRACE_EVENT_PHASE_INSTANT.
+ // Handle instant events as slices with zero duration, so that they end
+ // up nested underneath their parent slices.
+ int64_t duration_ns = 0;
+ int64_t tidelta = 0;
+
+ switch (legacy_event.instant_event_scope()) {
+ case LegacyEvent::SCOPE_UNSPECIFIED:
+ case LegacyEvent::SCOPE_THREAD: {
+ // TODO(lalitm): Associate thread slices with track instead.
+ auto opt_slice_id = slice_tracker->Scoped(
+ ts, track_id, *utid, RefType::kRefUtid, category_id, name_id,
+ duration_ns, args_callback);
+ if (opt_slice_id.has_value()) {
+ auto* thread_slices = storage->mutable_thread_slices();
+ PERFETTO_DCHECK(!thread_slices->slice_count() ||
+ thread_slices->slice_ids().back() <
+ opt_slice_id.value());
+ thread_slices->AddThreadSlice(opt_slice_id.value(), tts,
+ duration_ns, ticount, tidelta);
+ }
+ break;
+ }
+ case LegacyEvent::SCOPE_GLOBAL: {
+ slice_tracker->Scoped(ts, track_id, /*ref=*/0, RefType::kRefNoRef,
+ category_id, name_id, duration_ns,
+ args_callback);
+ break;
+ }
+ case LegacyEvent::SCOPE_PROCESS: {
+ slice_tracker->Scoped(ts, track_id, *upid, RefType::kRefUpid,
+ category_id, name_id, duration_ns,
+ args_callback);
+ break;
+ }
+ default: {
+ PERFETTO_FATAL("Unknown instant event scope: %u",
+ legacy_event.instant_event_scope());
+ break;
+ }
+ }
+ break;
+ }
+ case 'b': { // TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN
+ auto opt_slice_id =
+ slice_tracker->Begin(ts, track_id, track_id, RefType::kRefTrack,
+ category_id, name_id, args_callback);
+ // For the time beeing, we only create vtrack slice rows if we need to
+ // store thread timestamps/counters.
+ if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
+ auto* vtrack_slices = storage->mutable_virtual_track_slices();
+ PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
+ vtrack_slices->slice_ids().back() <
+ opt_slice_id.value());
+ vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
+ kPendingThreadDuration, ticount,
+ kPendingThreadInstructionDelta);
+ }
+ break;
+ }
+ case 'e': { // TRACE_EVENT_PHASE_NESTABLE_ASYNC_END
+ auto opt_slice_id =
+ slice_tracker->End(ts, track_id, category_id, name_id, args_callback);
+ if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
+ auto* vtrack_slices = storage->mutable_virtual_track_slices();
+ vtrack_slices->UpdateThreadDeltasForSliceId(opt_slice_id.value(), tts,
+ ticount);
+ }
+ break;
+ }
+ case 'n': { // TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT
+ // Handle instant events as slices with zero duration, so that they end up
+ // nested underneath their parent slices.
+ int64_t duration_ns = 0;
+ int64_t tidelta = 0;
+ auto opt_slice_id = slice_tracker->Scoped(
+ ts, track_id, track_id, RefType::kRefTrack, category_id, name_id,
+ duration_ns, args_callback);
+ if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
+ auto* vtrack_slices = storage->mutable_virtual_track_slices();
+ PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
+ vtrack_slices->slice_ids().back() <
+ opt_slice_id.value());
+ vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
+ duration_ns, ticount, tidelta);
+ }
+ break;
+ }
+ case 'M': { // TRACE_EVENT_PHASE_METADATA (process and thread names).
+ // Parse process and thread names from correspondingly named events.
+ // TODO(eseckler): Also consider names from process/thread descriptors.
+ NullTermStringView event_name = storage->GetString(name_id);
+ PERFETTO_DCHECK(event_name.data());
+ if (strcmp(event_name.c_str(), "thread_name") == 0) {
+ if (!utid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG(
+ "thread_name metadata event without thread association");
+ return;
+ }
+
+ auto it = event.debug_annotations();
+ if (!it)
+ break;
+ protos::pbzero::DebugAnnotation::Decoder annotation(*it);
+ auto thread_name = annotation.string_value();
+ if (!thread_name.size)
+ break;
+ auto thread_name_id = storage->InternString(thread_name);
+ procs->UpdateThreadName(storage->GetThread(*utid).tid, thread_name_id);
+ break;
+ }
+ if (strcmp(event_name.c_str(), "process_name") == 0) {
+ if (!upid) {
+ storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG(
+ "process_name metadata event without process association");
+ return;
+ }
+
+ auto it = event.debug_annotations();
+ if (!it)
+ break;
+ protos::pbzero::DebugAnnotation::Decoder annotation(*it);
+ auto process_name = annotation.string_value();
+ if (!process_name.size)
+ break;
+ procs->SetProcessMetadata(storage->GetProcess(*upid).pid, base::nullopt,
+ process_name);
+ break;
+ }
+ // Other metadata events are proxied via the raw table for JSON export.
+ ParseLegacyEventAsRawEvent(ts, tts, ticount, utid, category_id, name_id,
+ legacy_event, args_callback);
+ break;
+ }
+ default: {
+ // Other events are proxied via the raw table for JSON export.
+ ParseLegacyEventAsRawEvent(ts, tts, ticount, utid, category_id, name_id,
+ legacy_event, args_callback);
+ }
+ }
+}
+
+void TrackEventParser::ParseLegacyEventAsRawEvent(
+ int64_t ts,
+ int64_t tts,
+ int64_t ticount,
+ base::Optional<UniqueTid> utid,
+ StringId category_id,
+ StringId name_id,
+ const protos::pbzero::TrackEvent::LegacyEvent::Decoder& legacy_event,
+ SliceTracker::SetArgsCallback args_callback) {
+ if (!utid) {
+ context_->storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("raw legacy event without thread association");
+ return;
+ }
+
+ RowId row_id = context_->storage->mutable_raw_events()->AddRawEvent(
+ ts, raw_legacy_event_id_, 0, *utid);
+ ArgsTracker args(context_);
+ args.AddArg(row_id, legacy_event_category_key_id_,
+ legacy_event_category_key_id_, Variadic::String(category_id));
+ args.AddArg(row_id, legacy_event_name_key_id_, legacy_event_name_key_id_,
+ Variadic::String(name_id));
+
+ std::string phase_string(1, static_cast<char>(legacy_event.phase()));
+ StringId phase_id = context_->storage->InternString(phase_string.c_str());
+ args.AddArg(row_id, legacy_event_phase_key_id_, legacy_event_phase_key_id_,
+ Variadic::String(phase_id));
+
+ if (legacy_event.has_duration_us()) {
+ args.AddArg(row_id, legacy_event_duration_ns_key_id_,
+ legacy_event_duration_ns_key_id_,
+ Variadic::Integer(legacy_event.duration_us() * 1000));
+ }
+
+ if (tts) {
+ args.AddArg(row_id, legacy_event_thread_timestamp_ns_key_id_,
+ legacy_event_thread_timestamp_ns_key_id_,
+ Variadic::Integer(tts));
+ if (legacy_event.has_thread_duration_us()) {
+ args.AddArg(row_id, legacy_event_thread_duration_ns_key_id_,
+ legacy_event_thread_duration_ns_key_id_,
+ Variadic::Integer(legacy_event.thread_duration_us() * 1000));
+ }
+ }
+
+ if (ticount) {
+ args.AddArg(row_id, legacy_event_thread_instruction_count_key_id_,
+ legacy_event_thread_instruction_count_key_id_,
+ Variadic::Integer(tts));
+ if (legacy_event.has_thread_instruction_delta()) {
+ args.AddArg(row_id, legacy_event_thread_instruction_delta_key_id_,
+ legacy_event_thread_instruction_delta_key_id_,
+ Variadic::Integer(legacy_event.thread_instruction_delta()));
+ }
+ }
+
+ if (legacy_event.use_async_tts()) {
+ args.AddArg(row_id, legacy_event_use_async_tts_key_id_,
+ legacy_event_use_async_tts_key_id_, Variadic::Boolean(true));
+ }
+
+ bool has_id = false;
+ if (legacy_event.has_unscoped_id()) {
+ // Unscoped ids are either global or local depending on the phase. Pass them
+ // through as unscoped IDs to JSON export to preserve this behavior.
+ args.AddArg(row_id, legacy_event_unscoped_id_key_id_,
+ legacy_event_unscoped_id_key_id_,
+ Variadic::UnsignedInteger(legacy_event.unscoped_id()));
+ has_id = true;
+ } else if (legacy_event.has_global_id()) {
+ args.AddArg(row_id, legacy_event_global_id_key_id_,
+ legacy_event_global_id_key_id_,
+ Variadic::UnsignedInteger(legacy_event.global_id()));
+ has_id = true;
+ } else if (legacy_event.has_local_id()) {
+ args.AddArg(row_id, legacy_event_local_id_key_id_,
+ legacy_event_local_id_key_id_,
+ Variadic::UnsignedInteger(legacy_event.local_id()));
+ has_id = true;
+ }
+
+ if (has_id && legacy_event.has_id_scope() && legacy_event.id_scope().size) {
+ args.AddArg(row_id, legacy_event_id_scope_key_id_,
+ legacy_event_id_scope_key_id_,
+ Variadic::String(
+ context_->storage->InternString(legacy_event.id_scope())));
+ }
+
+ // No need to parse legacy_event.instant_event_scope() because we import
+ // instant events into the slice table.
+
+ args_callback(&args, row_id);
+}
+
+void TrackEventParser::ParseDebugAnnotationArgs(
+ ConstBytes debug_annotation,
+ PacketSequenceState* sequence_state,
+ size_t sequence_state_generation,
+ ArgsTracker* args_tracker,
+ RowId row_id) {
+ TraceStorage* storage = context_->storage.get();
+
+ protos::pbzero::DebugAnnotation::Decoder annotation(debug_annotation.data,
+ debug_annotation.size);
+
+ StringId name_id = 0;
+
+ uint64_t name_iid = annotation.name_iid();
+ if (PERFETTO_LIKELY(name_iid)) {
+ auto* decoder = sequence_state->LookupInternedMessage<
+ protos::pbzero::InternedData::kDebugAnnotationNamesFieldNumber,
+ protos::pbzero::DebugAnnotationName>(sequence_state_generation,
+ name_iid);
+ if (!decoder)
+ return;
+
+ std::string name_prefixed = "debug." + decoder->name().ToStdString();
+ name_id = storage->InternString(base::StringView(name_prefixed));
+ } else if (annotation.has_name()) {
+ name_id = storage->InternString(annotation.name());
+ } else {
+ context_->storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("Debug annotation without name");
+ return;
+ }
+
+ if (annotation.has_bool_value()) {
+ args_tracker->AddArg(row_id, name_id, name_id,
+ Variadic::Boolean(annotation.bool_value()));
+ } else if (annotation.has_uint_value()) {
+ args_tracker->AddArg(row_id, name_id, name_id,
+ Variadic::UnsignedInteger(annotation.uint_value()));
+ } else if (annotation.has_int_value()) {
+ args_tracker->AddArg(row_id, name_id, name_id,
+ Variadic::Integer(annotation.int_value()));
+ } else if (annotation.has_double_value()) {
+ args_tracker->AddArg(row_id, name_id, name_id,
+ Variadic::Real(annotation.double_value()));
+ } else if (annotation.has_string_value()) {
+ args_tracker->AddArg(
+ row_id, name_id, name_id,
+ Variadic::String(storage->InternString(annotation.string_value())));
+ } else if (annotation.has_pointer_value()) {
+ args_tracker->AddArg(row_id, name_id, name_id,
+ Variadic::Pointer(annotation.pointer_value()));
+ } else if (annotation.has_legacy_json_value()) {
+ args_tracker->AddArg(
+ row_id, name_id, name_id,
+ Variadic::Json(storage->InternString(annotation.legacy_json_value())));
+ } else if (annotation.has_nested_value()) {
+ auto name = storage->GetString(name_id);
+ ParseNestedValueArgs(annotation.nested_value(), name, name, args_tracker,
+ row_id);
+ }
+}
+
+void TrackEventParser::ParseNestedValueArgs(ConstBytes nested_value,
+ base::StringView flat_key,
+ base::StringView key,
+ ArgsTracker* args_tracker,
+ RowId row_id) {
+ protos::pbzero::DebugAnnotation::NestedValue::Decoder value(
+ nested_value.data, nested_value.size);
+ switch (value.nested_type()) {
+ case protos::pbzero::DebugAnnotation::NestedValue::UNSPECIFIED: {
+ auto flat_key_id = context_->storage->InternString(flat_key);
+ auto key_id = context_->storage->InternString(key);
+ // Leaf value.
+ if (value.has_bool_value()) {
+ args_tracker->AddArg(row_id, flat_key_id, key_id,
+ Variadic::Boolean(value.bool_value()));
+ } else if (value.has_int_value()) {
+ args_tracker->AddArg(row_id, flat_key_id, key_id,
+ Variadic::Integer(value.int_value()));
+ } else if (value.has_double_value()) {
+ args_tracker->AddArg(row_id, flat_key_id, key_id,
+ Variadic::Real(value.double_value()));
+ } else if (value.has_string_value()) {
+ args_tracker->AddArg(row_id, flat_key_id, key_id,
+ Variadic::String(context_->storage->InternString(
+ value.string_value())));
+ }
+ break;
+ }
+ case protos::pbzero::DebugAnnotation::NestedValue::DICT: {
+ 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 = (*key_it).ToStdString();
+ std::string child_flat_key = flat_key.ToStdString() + "." + child_name;
+ std::string child_key = key.ToStdString() + "." + child_name;
+ ParseNestedValueArgs(*value_it, base::StringView(child_flat_key),
+ base::StringView(child_key), args_tracker, row_id);
+ }
+ break;
+ }
+ case protos::pbzero::DebugAnnotation::NestedValue::ARRAY: {
+ int child_index = 0;
+ std::string child_flat_key = flat_key.ToStdString();
+ for (auto value_it = value.array_values(); value_it;
+ ++value_it, ++child_index) {
+ std::string child_key =
+ key.ToStdString() + "[" + std::to_string(child_index) + "]";
+ ParseNestedValueArgs(*value_it, base::StringView(child_flat_key),
+ base::StringView(child_key), args_tracker, row_id);
+ }
+ break;
+ }
+ }
+}
+
+void TrackEventParser::ParseTaskExecutionArgs(
+ ConstBytes task_execution,
+ PacketSequenceState* sequence_state,
+ size_t sequence_state_generation,
+ ArgsTracker* args_tracker,
+ RowId row) {
+ protos::pbzero::TaskExecution::Decoder task(task_execution.data,
+ task_execution.size);
+ uint64_t iid = task.posted_from_iid();
+ if (!iid)
+ return;
+
+ auto* decoder = sequence_state->LookupInternedMessage<
+ protos::pbzero::InternedData::kSourceLocationsFieldNumber,
+ protos::pbzero::SourceLocation>(sequence_state_generation, iid);
+ if (!decoder)
+ return;
+
+ StringId file_name_id = 0;
+ StringId function_name_id = 0;
+ uint32_t line_number = 0;
+
+ TraceStorage* storage = context_->storage.get();
+ file_name_id = storage->InternString(decoder->file_name());
+ function_name_id = storage->InternString(decoder->function_name());
+ line_number = decoder->line_number();
+
+ args_tracker->AddArg(row, task_file_name_args_key_id_,
+ task_file_name_args_key_id_,
+ Variadic::String(file_name_id));
+ args_tracker->AddArg(row, task_function_name_args_key_id_,
+ task_function_name_args_key_id_,
+ Variadic::String(function_name_id));
+
+ args_tracker->AddArg(row, task_line_number_args_key_id_,
+ task_line_number_args_key_id_,
+ Variadic::UnsignedInteger(line_number));
+}
+
+void TrackEventParser::ParseLogMessage(ConstBytes blob,
+ PacketSequenceState* sequence_state,
+ size_t sequence_state_generation,
+ int64_t ts,
+ base::Optional<UniqueTid> utid,
+ ArgsTracker* args_tracker,
+ RowId row) {
+ if (!utid) {
+ context_->storage->IncrementStats(stats::track_event_parser_errors);
+ PERFETTO_DLOG("LogMessage without thread association");
+ return;
+ }
+
+ protos::pbzero::LogMessage::Decoder message(blob.data, blob.size);
+
+ TraceStorage* storage = context_->storage.get();
+
+ StringId log_message_id = 0;
+
+ auto* decoder = sequence_state->LookupInternedMessage<
+ protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
+ protos::pbzero::LogMessageBody>(sequence_state_generation,
+ message.body_iid());
+ if (!decoder)
+ return;
+
+ log_message_id = storage->InternString(decoder->body());
+
+ // TODO(nicomazz): LogMessage also contains the source of the message (file
+ // and line number). Android logs doesn't support this so far.
+ context_->storage->mutable_android_log()->AddLogEvent(
+ ts, *utid,
+ /*priority*/ 0,
+ /*tag_id*/ 0, // TODO(nicomazz): Abuse tag_id to display
+ // "file_name:line_number".
+ log_message_id);
+
+ args_tracker->AddArg(row, log_message_body_key_id_, log_message_body_key_id_,
+ Variadic::String(log_message_id));
+ // TODO(nicomazz): Add the source location as an argument.
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/track_event_parser.h b/src/trace_processor/importers/proto/track_event_parser.h
new file mode 100644
index 0000000..7e39eb1
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_parser.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_PARSER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_PARSER_H_
+
+#include "src/trace_processor/slice_tracker.h"
+#include "src/trace_processor/trace_storage.h"
+
+#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class PacketSequenceState;
+class TraceProcessorContext;
+
+class TrackEventParser {
+ public:
+ explicit TrackEventParser(TraceProcessorContext* context);
+
+ void ParseTrackEvent(int64_t ts,
+ int64_t tts,
+ int64_t ticount,
+ PacketSequenceState*,
+ size_t sequence_state_generation,
+ protozero::ConstBytes);
+ void ParseLegacyEventAsRawEvent(
+ int64_t ts,
+ int64_t tts,
+ int64_t ticount,
+ base::Optional<UniqueTid> utid,
+ StringId category_id,
+ StringId name_id,
+ const protos::pbzero::TrackEvent::LegacyEvent::Decoder& legacy_event,
+ SliceTracker::SetArgsCallback args_callback);
+ void ParseDebugAnnotationArgs(protozero::ConstBytes debug_annotation,
+ PacketSequenceState*,
+ size_t sequence_state_generation,
+ ArgsTracker* args_tracker,
+ RowId row);
+ void ParseNestedValueArgs(protozero::ConstBytes nested_value,
+ base::StringView flat_key,
+ base::StringView key,
+ ArgsTracker* args_tracker,
+ RowId row);
+ void ParseTaskExecutionArgs(protozero::ConstBytes task_execution,
+ PacketSequenceState*,
+ size_t sequence_state_generation,
+ ArgsTracker* args_tracker,
+ RowId row);
+ void ParseLogMessage(protozero::ConstBytes,
+ PacketSequenceState*,
+ size_t sequence_state_generation,
+ int64_t,
+ base::Optional<UniqueTid>,
+ ArgsTracker*,
+ RowId);
+
+ private:
+ TraceProcessorContext* context_;
+
+ const StringId task_file_name_args_key_id_;
+ const StringId task_function_name_args_key_id_;
+ const StringId task_line_number_args_key_id_;
+ const StringId log_message_body_key_id_;
+ const StringId raw_legacy_event_id_;
+ const StringId legacy_event_category_key_id_;
+ const StringId legacy_event_name_key_id_;
+ const StringId legacy_event_phase_key_id_;
+ const StringId legacy_event_duration_ns_key_id_;
+ const StringId legacy_event_thread_timestamp_ns_key_id_;
+ const StringId legacy_event_thread_duration_ns_key_id_;
+ const StringId legacy_event_thread_instruction_count_key_id_;
+ const StringId legacy_event_thread_instruction_delta_key_id_;
+ const StringId legacy_event_use_async_tts_key_id_;
+ const StringId legacy_event_unscoped_id_key_id_;
+ const StringId legacy_event_global_id_key_id_;
+ const StringId legacy_event_local_id_key_id_;
+ const StringId legacy_event_id_scope_key_id_;
+ const StringId legacy_event_bind_id_key_id_;
+ const StringId legacy_event_bind_to_enclosing_key_id_;
+ const StringId legacy_event_flow_direction_key_id_;
+ const StringId flow_direction_value_in_id_;
+ const StringId flow_direction_value_out_id_;
+ const StringId flow_direction_value_inout_id_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_PARSER_H_
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
new file mode 100644
index 0000000..15ba499
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/importers/proto/track_event_tokenizer.h"
+
+#include "perfetto/base/logging.h"
+#include "perfetto/protozero/proto_decoder.h"
+#include "src/trace_processor/clock_tracker.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/process_tracker.h"
+#include "src/trace_processor/proto_trace_tokenizer.h"
+#include "src/trace_processor/stats.h"
+#include "src/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/trace_sorter.h"
+#include "src/trace_processor/trace_storage.h"
+#include "src/trace_processor/track_tracker.h"
+
+#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
+#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+void TrackEventTokenizer::TokenizeTrackDescriptorPacket(
+ const protos::pbzero::TracePacket::Decoder& packet_decoder) {
+ auto track_descriptor_field = packet_decoder.track_descriptor();
+ protos::pbzero::TrackDescriptor::Decoder track_descriptor_decoder(
+ track_descriptor_field.data, track_descriptor_field.size);
+
+ if (!track_descriptor_decoder.has_uuid()) {
+ PERFETTO_ELOG("TrackDescriptor packet without trusted_packet_sequence_id");
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return;
+ }
+
+ base::Optional<UniquePid> upid;
+ base::Optional<UniqueTid> utid;
+
+ if (track_descriptor_decoder.has_process()) {
+ auto process_descriptor_field = track_descriptor_decoder.process();
+ protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
+ process_descriptor_field.data, process_descriptor_field.size);
+
+ // TODO(eseckler): Also parse process name / type here.
+
+ upid = context_->process_tracker->GetOrCreateProcess(
+ static_cast<uint32_t>(process_descriptor_decoder.pid()));
+ }
+
+ if (track_descriptor_decoder.has_thread()) {
+ auto thread_descriptor_field = track_descriptor_decoder.thread();
+ protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
+ thread_descriptor_field.data, thread_descriptor_field.size);
+
+ TokenizeThreadDescriptor(thread_descriptor_decoder);
+ utid = context_->process_tracker->UpdateThread(
+ static_cast<uint32_t>(thread_descriptor_decoder.tid()),
+ static_cast<uint32_t>(thread_descriptor_decoder.pid()));
+ upid = *context_->storage->GetThread(*utid).upid;
+ }
+
+ StringId name_id =
+ context_->storage->InternString(track_descriptor_decoder.name());
+
+ context_->track_tracker->UpdateDescriptorTrack(
+ track_descriptor_decoder.uuid(), name_id, upid, utid);
+}
+
+void TrackEventTokenizer::TokenizeProcessDescriptorPacket(
+ const protos::pbzero::TracePacket::Decoder& packet_decoder) {
+ protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
+ packet_decoder.process_descriptor());
+ if (!process_descriptor_decoder.has_chrome_process_type())
+ return;
+ base::StringView name = "Unknown";
+ switch (process_descriptor_decoder.chrome_process_type()) {
+ case protos::pbzero::ProcessDescriptor::PROCESS_BROWSER:
+ name = "Browser";
+ break;
+ case protos::pbzero::ProcessDescriptor::PROCESS_RENDERER:
+ name = "Renderer";
+ break;
+ case protos::pbzero::ProcessDescriptor::PROCESS_UTILITY:
+ name = "Utility";
+ break;
+ case protos::pbzero::ProcessDescriptor::PROCESS_ZYGOTE:
+ name = "Zygote";
+ break;
+ case protos::pbzero::ProcessDescriptor::PROCESS_SANDBOX_HELPER:
+ name = "SandboxHelper";
+ break;
+ case protos::pbzero::ProcessDescriptor::PROCESS_GPU:
+ name = "Gpu";
+ break;
+ case protos::pbzero::ProcessDescriptor::PROCESS_PPAPI_PLUGIN:
+ name = "PpapiPlugin";
+ break;
+ case protos::pbzero::ProcessDescriptor::PROCESS_PPAPI_BROKER:
+ name = "PpapiBroker";
+ break;
+ }
+ context_->process_tracker->SetProcessMetadata(
+ static_cast<uint32_t>(process_descriptor_decoder.pid()), base::nullopt,
+ name);
+}
+
+void TrackEventTokenizer::TokenizeThreadDescriptorPacket(
+ PacketSequenceState* state,
+ const protos::pbzero::TracePacket::Decoder& packet_decoder) {
+ if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
+ PERFETTO_ELOG("ThreadDescriptor packet without trusted_packet_sequence_id");
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return;
+ }
+
+ // TrackEvents will be ignored while incremental state is invalid. As a
+ // consequence, we should also ignore any ThreadDescriptors received in this
+ // state. Otherwise, any delta-encoded timestamps would be calculated
+ // incorrectly once we move out of the packet loss state. Instead, wait until
+ // the first subsequent descriptor after incremental state is cleared.
+ if (!state->IsIncrementalStateValid()) {
+ context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
+ return;
+ }
+
+ auto thread_descriptor_field = packet_decoder.thread_descriptor();
+ protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
+ thread_descriptor_field.data, thread_descriptor_field.size);
+
+ state->SetThreadDescriptor(
+ thread_descriptor_decoder.pid(), thread_descriptor_decoder.tid(),
+ thread_descriptor_decoder.reference_timestamp_us() * 1000,
+ thread_descriptor_decoder.reference_thread_time_us() * 1000,
+ thread_descriptor_decoder.reference_thread_instruction_count());
+
+ TokenizeThreadDescriptor(thread_descriptor_decoder);
+}
+
+void TrackEventTokenizer::TokenizeThreadDescriptor(
+ const protos::pbzero::ThreadDescriptor::Decoder&
+ thread_descriptor_decoder) {
+ base::StringView name;
+ if (thread_descriptor_decoder.has_thread_name()) {
+ name = thread_descriptor_decoder.thread_name();
+ } else if (thread_descriptor_decoder.has_chrome_thread_type()) {
+ using protos::pbzero::ThreadDescriptor;
+ switch (thread_descriptor_decoder.chrome_thread_type()) {
+ case ThreadDescriptor::CHROME_THREAD_MAIN:
+ name = "CrProcessMain";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_IO:
+ name = "ChromeIOThread";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_POOL_FG_WORKER:
+ name = "ThreadPoolForegroundWorker&";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_POOL_BG_WORKER:
+ name = "ThreadPoolBackgroundWorker&";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_POOL_FB_BLOCKING:
+ name = "ThreadPoolSingleThreadForegroundBlocking&";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_POOL_BG_BLOCKING:
+ name = "ThreadPoolSingleThreadBackgroundBlocking&";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_POOL_SERVICE:
+ name = "ThreadPoolService";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_COMPOSITOR_WORKER:
+ name = "CompositorTileWorker&";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_COMPOSITOR:
+ name = "Compositor";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_VIZ_COMPOSITOR:
+ name = "VizCompositorThread";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_SERVICE_WORKER:
+ name = "ServiceWorkerThread&";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_MEMORY_INFRA:
+ name = "MemoryInfra";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_SAMPLING_PROFILER:
+ name = "StackSamplingProfiler";
+ break;
+ case ThreadDescriptor::CHROME_THREAD_UNSPECIFIED:
+ name = "ChromeUnspecified";
+ break;
+ }
+ }
+
+ if (!name.empty()) {
+ auto thread_name_id = context_->storage->InternString(name);
+ ProcessTracker* procs = context_->process_tracker.get();
+ procs->UpdateThreadName(
+ static_cast<uint32_t>(thread_descriptor_decoder.tid()), thread_name_id);
+ }
+}
+
+void TrackEventTokenizer::TokenizeTrackEventPacket(
+ PacketSequenceState* state,
+ const protos::pbzero::TracePacket::Decoder& packet_decoder,
+ TraceBlobView* packet,
+ int64_t packet_timestamp) {
+ constexpr auto kTimestampDeltaUsFieldNumber =
+ protos::pbzero::TrackEvent::kTimestampDeltaUsFieldNumber;
+ constexpr auto kTimestampAbsoluteUsFieldNumber =
+ protos::pbzero::TrackEvent::kTimestampAbsoluteUsFieldNumber;
+ constexpr auto kThreadTimeDeltaUsFieldNumber =
+ protos::pbzero::TrackEvent::kThreadTimeDeltaUsFieldNumber;
+ constexpr auto kThreadTimeAbsoluteUsFieldNumber =
+ protos::pbzero::TrackEvent::kThreadTimeAbsoluteUsFieldNumber;
+ constexpr auto kThreadInstructionCountDeltaFieldNumber =
+ protos::pbzero::TrackEvent::kThreadInstructionCountDeltaFieldNumber;
+ constexpr auto kThreadInstructionCountAbsoluteFieldNumber =
+ protos::pbzero::TrackEvent::kThreadInstructionCountAbsoluteFieldNumber;
+
+ if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
+ PERFETTO_ELOG("TrackEvent packet without trusted_packet_sequence_id");
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return;
+ }
+
+ // TODO(eseckler): For now, TrackEvents can only be parsed correctly while
+ // incremental state for their sequence is valid, because chromium doesn't set
+ // SEQ_NEEDS_INCREMENTAL_STATE yet. Remove this once it does.
+ if (!state->IsIncrementalStateValid()) {
+ context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
+ return;
+ }
+
+ auto field = packet_decoder.track_event();
+ protozero::ProtoDecoder event_decoder(field.data, field.size);
+
+ int64_t timestamp;
+ int64_t thread_timestamp = 0;
+ int64_t thread_instructions = 0;
+
+ // TODO(eseckler): Remove handling of timestamps relative to ThreadDescriptors
+ // once all producers have switched to clock-domain timestamps (e.g.
+ // TracePacket's timestamp).
+
+ if (auto ts_delta_field =
+ event_decoder.FindField(kTimestampDeltaUsFieldNumber)) {
+ // Delta timestamps require a valid ThreadDescriptor packet since the last
+ // packet loss.
+ if (!state->track_event_timestamps_valid()) {
+ context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
+ return;
+ }
+ timestamp = state->IncrementAndGetTrackEventTimeNs(
+ ts_delta_field.as_int64() * 1000);
+
+ // Legacy TrackEvent timestamp fields are in MONOTONIC domain. Adjust to
+ // trace time if we have a clock snapshot.
+ auto trace_ts = context_->clock_tracker->ToTraceTime(
+ protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
+ if (trace_ts.has_value())
+ timestamp = trace_ts.value();
+ } else if (auto ts_absolute_field =
+ event_decoder.FindField(kTimestampAbsoluteUsFieldNumber)) {
+ // One-off absolute timestamps don't affect delta computation.
+ timestamp = ts_absolute_field.as_int64() * 1000;
+
+ // Legacy TrackEvent timestamp fields are in MONOTONIC domain. Adjust to
+ // trace time if we have a clock snapshot.
+ auto trace_ts = context_->clock_tracker->ToTraceTime(
+ protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
+ if (trace_ts.has_value())
+ timestamp = trace_ts.value();
+ } else if (packet_decoder.has_timestamp()) {
+ timestamp = packet_timestamp;
+ } else {
+ PERFETTO_ELOG("TrackEvent without timestamp");
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return;
+ }
+
+ if (auto tt_delta_field =
+ event_decoder.FindField(kThreadTimeDeltaUsFieldNumber)) {
+ // Delta timestamps require a valid ThreadDescriptor packet since the last
+ // packet loss.
+ if (!state->track_event_timestamps_valid()) {
+ context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
+ return;
+ }
+ thread_timestamp = state->IncrementAndGetTrackEventThreadTimeNs(
+ tt_delta_field.as_int64() * 1000);
+ } else if (auto tt_absolute_field =
+ event_decoder.FindField(kThreadTimeAbsoluteUsFieldNumber)) {
+ // One-off absolute timestamps don't affect delta computation.
+ thread_timestamp = tt_absolute_field.as_int64() * 1000;
+ }
+
+ if (auto ti_delta_field =
+ event_decoder.FindField(kThreadInstructionCountDeltaFieldNumber)) {
+ // Delta timestamps require a valid ThreadDescriptor packet since the last
+ // packet loss.
+ if (!state->track_event_timestamps_valid()) {
+ context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
+ return;
+ }
+ thread_instructions =
+ state->IncrementAndGetTrackEventThreadInstructionCount(
+ ti_delta_field.as_int64());
+ } else if (auto ti_absolute_field = event_decoder.FindField(
+ kThreadInstructionCountAbsoluteFieldNumber)) {
+ // One-off absolute timestamps don't affect delta computation.
+ thread_instructions = ti_absolute_field.as_int64();
+ }
+
+ context_->sorter->PushTrackEventPacket(timestamp, thread_timestamp,
+ thread_instructions, state,
+ std::move(*packet));
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.h b/src/trace_processor/importers/proto/track_event_tokenizer.h
new file mode 100644
index 0000000..32e3446
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TOKENIZER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TOKENIZER_H_
+
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class PacketSequenceState;
+class TraceProcessorContext;
+class TraceBlobView;
+
+class TrackEventTokenizer {
+ public:
+ explicit TrackEventTokenizer(TraceProcessorContext* context)
+ : context_(context) {}
+
+ void TokenizeTrackDescriptorPacket(
+ const protos::pbzero::TracePacket::Decoder&);
+ void TokenizeProcessDescriptorPacket(
+ const protos::pbzero::TracePacket::Decoder&);
+ void TokenizeThreadDescriptorPacket(
+ PacketSequenceState* state,
+ const protos::pbzero::TracePacket::Decoder&);
+ void TokenizeThreadDescriptor(
+ const protos::pbzero::ThreadDescriptor::Decoder&);
+ void TokenizeTrackEventPacket(PacketSequenceState* state,
+ const protos::pbzero::TracePacket::Decoder&,
+ TraceBlobView* packet,
+ int64_t packet_timestamp);
+
+ private:
+ TraceProcessorContext* context_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TOKENIZER_H_
diff --git a/src/trace_processor/proto_incremental_state.h b/src/trace_processor/proto_incremental_state.h
deleted file mode 100644
index 7dbfdf3..0000000
--- a/src/trace_processor/proto_incremental_state.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_PROTO_INCREMENTAL_STATE_H_
-#define SRC_TRACE_PROCESSOR_PROTO_INCREMENTAL_STATE_H_
-
-#include <stdint.h>
-#include <string.h>
-
-#include <map>
-#include <unordered_map>
-#include <vector>
-
-#include "perfetto/protozero/proto_decoder.h"
-#include "src/trace_processor/stack_profile_tracker.h"
-#include "src/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/trace_processor_context.h"
-#include "src/trace_processor/trace_storage.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-struct DefaultFieldName;
-struct BuildIdFieldName;
-struct MappingPathsFieldName;
-struct FunctionNamesFieldName;
-struct VulkanAnnotationsFieldName;
-
-#if PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
-// When called from GetOrCreateDecoder(), __PRETTY_FUNCTION__ (supported by GCC
-// + clang) should include the stringified name of the MessageType.
-#define PERFETTO_TYPE_IDENTIFIER __PRETTY_FUNCTION__
-#else // PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
-#define PERFETTO_TYPE_IDENTIFIER nullptr
-#endif // PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
-
-// Stores per-packet-sequence incremental state during trace parsing, such as
-// reference timestamps for delta timestamp calculation and interned messages.
-class ProtoIncrementalState {
- public:
- ProtoIncrementalState(TraceProcessorContext* context) : context_(context) {}
-
- // Entry in an interning index, refers to the interned message.
- struct InternedMessageView {
- InternedMessageView(TraceBlobView msg) : message(std::move(msg)) {}
-
- 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, __PRETTY_FUNCTION__);
- }
- return reinterpret_cast<typename MessageType::Decoder*>(decoder.get());
- }
-
- TraceBlobView message;
- std::unique_ptr<void, std::function<void(void*)>> decoder;
-
- private:
- const char* decoder_type = nullptr;
- };
-
- using InternedMessageMap =
- std::unordered_map<uint64_t /*iid*/, InternedMessageView>;
- using InternedFieldMap =
- std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
- using InternedDataGenerationList = std::vector<InternedFieldMap>;
-
- class PacketSequenceState {
- public:
- PacketSequenceState(TraceProcessorContext* context)
- : context_(context), stack_profile_tracker_(context) {
- interned_data_.emplace_back();
- }
-
- int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_timestamp_ns_ += delta_ns;
- return track_event_timestamp_ns_;
- }
-
- int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_thread_timestamp_ns_ += delta_ns;
- return track_event_thread_timestamp_ns_;
- }
-
- int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_thread_instruction_count_ += delta;
- return track_event_thread_instruction_count_;
- }
-
- void OnPacketLoss() {
- packet_loss_ = true;
- track_event_timestamps_valid_ = false;
- }
-
- void OnIncrementalStateCleared() {
- packet_loss_ = false;
- interned_data_.emplace_back(); // Bump generation number
- }
-
- void SetThreadDescriptor(int32_t pid,
- int32_t tid,
- int64_t timestamp_ns,
- int64_t thread_timestamp_ns,
- int64_t thread_instruction_count) {
- track_event_timestamps_valid_ = true;
- pid_and_tid_valid_ = true;
- pid_ = pid;
- tid_ = tid;
- track_event_timestamp_ns_ = timestamp_ns;
- track_event_thread_timestamp_ns_ = thread_timestamp_ns;
- track_event_thread_instruction_count_ = thread_instruction_count;
- }
-
- bool IsIncrementalStateValid() const { return !packet_loss_; }
-
- StackProfileTracker& stack_profile_tracker() {
- return stack_profile_tracker_;
- }
-
- // Returns the index of the current generation in the
- // InternedDataGenerationList.
- size_t current_generation() const { return interned_data_.size() - 1; }
-
- bool track_event_timestamps_valid() const {
- return track_event_timestamps_valid_;
- }
-
- bool pid_and_tid_valid() const { return pid_and_tid_valid_; }
-
- int32_t pid() const { return pid_; }
- int32_t tid() const { return tid_; }
-
- void InternMessage(uint32_t field_id, TraceBlobView message) {
- constexpr auto kIidFieldNumber = 1;
-
- uint64_t iid = 0;
- auto message_start = message.data();
- auto message_size = message.length();
- protozero::ProtoDecoder decoder(message_start, message_size);
-
- auto field = decoder.FindField(kIidFieldNumber);
- if (PERFETTO_UNLIKELY(!field)) {
- PERFETTO_DLOG("Interned message without interning_id");
- context_->storage->IncrementStats(
- stats::interned_data_tokenizer_errors);
- return;
- }
- iid = field.as_uint64();
-
- auto* map = &interned_data_.back()[field_id];
- auto res = map->emplace(iid, InternedMessageView(std::move(message)));
-
- // If a message with this ID is already interned in the same generation,
- // its data should not have changed (this is forbidden by the InternedData
- // proto).
- // TODO(eseckler): This DCHECK assumes that the message is encoded the
- // same way if it is re-emitted.
- PERFETTO_DCHECK(res.second ||
- (res.first->second.message.length() == message_size &&
- memcmp(res.first->second.message.data(), message_start,
- message_size) == 0));
- }
-
- template <uint32_t FieldId, typename MessageType>
- typename MessageType::Decoder* LookupInternedMessage(size_t generation,
- uint64_t iid) {
- PERFETTO_CHECK(generation <= interned_data_.size());
- auto* field_map = &interned_data_[generation];
- auto field_it = field_map->find(FieldId);
- if (field_it != field_map->end()) {
- auto* message_map = &field_it->second;
- auto it = message_map->find(iid);
- if (it != message_map->end()) {
- return it->second.GetOrCreateDecoder<MessageType>();
- }
- }
- context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
- PERFETTO_DLOG("Could not find interning entry for field ID %" PRIu32
- ", generation %zu, and IID %" PRIu64,
- FieldId, generation, iid);
- return nullptr;
- }
-
- private:
- TraceProcessorContext* context_;
-
- // If true, incremental state on the sequence is considered invalid until we
- // see the next packet with incremental_state_cleared. We assume that we
- // missed some packets at the beginning of the trace.
- bool packet_loss_ = true;
-
- // We can only consider TrackEvent delta timestamps to be correct after we
- // have observed a thread descriptor (since the last packet loss).
- bool track_event_timestamps_valid_ = false;
-
- // |pid_| and |tid_| are only valid after we parsed at least one
- // ThreadDescriptor packet on the sequence.
- bool pid_and_tid_valid_ = false;
-
- // Process/thread ID of the packet sequence set by a ThreadDescriptor
- // packet. Used as default values for TrackEvents that don't specify a
- // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
- int32_t pid_ = 0;
- int32_t tid_ = 0;
-
- // Current wall/thread timestamps/counters used as reference for the next
- // TrackEvent delta timestamp.
- int64_t track_event_timestamp_ns_ = 0;
- int64_t track_event_thread_timestamp_ns_ = 0;
- int64_t track_event_thread_instruction_count_ = 0;
-
- InternedDataGenerationList interned_data_;
- StackProfileTracker stack_profile_tracker_;
- };
-
- // Returns the PacketSequenceState for the packet sequence with the given id.
- // If this is a new sequence which we haven't tracked before, initializes and
- // inserts a new PacketSequenceState into the state map.
- PacketSequenceState* GetOrCreateStateForPacketSequence(uint32_t sequence_id) {
- auto& ptr = packet_sequence_states_[sequence_id];
- if (!ptr)
- ptr.reset(new PacketSequenceState(context_));
- return ptr.get();
- }
-
- private:
- // Stores unique_ptrs to ensure that pointers to a PacketSequenceState remain
- // valid even if the map rehashes.
- std::map<uint32_t, std::unique_ptr<PacketSequenceState>>
- packet_sequence_states_;
-
- TraceProcessorContext* context_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_PROTO_INCREMENTAL_STATE_H_
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index 42daa08..98ea5f5 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -36,16 +36,16 @@
#include "src/trace_processor/heap_graph_tracker.h"
#include "src/trace_processor/heap_profile_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/proto/track_event_module.h"
#include "src/trace_processor/importers/systrace/systrace_parser.h"
#include "src/trace_processor/metadata.h"
#include "src/trace_processor/process_tracker.h"
-#include "src/trace_processor/proto_incremental_state.h"
+#include "src/trace_processor/slice_tracker.h"
#include "src/trace_processor/stack_profile_tracker.h"
#include "src/trace_processor/syscall_tracker.h"
#include "src/trace_processor/timestamped_trace_piece.h"
#include "src/trace_processor/trace_processor_context.h"
-#include "src/trace_processor/track_tracker.h"
#include "src/trace_processor/variadic.h"
#include "protos/perfetto/common/android_log_constants.pbzero.h"
@@ -69,10 +69,6 @@
#include "protos/perfetto/trace/system_info.pbzero.h"
#include "protos/perfetto/trace/trace.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
-#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
-#include "protos/perfetto/trace/track_event/log_message.pbzero.h"
-#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
-#include "protos/perfetto/trace/track_event/task_execution.pbzero.h"
namespace perfetto {
namespace trace_processor {
@@ -120,9 +116,8 @@
class ProfilePacketInternLookup : public StackProfileTracker::InternLookup {
public:
- ProfilePacketInternLookup(
- ProtoIncrementalState::PacketSequenceState* seq_state,
- size_t seq_state_generation)
+ ProfilePacketInternLookup(PacketSequenceState* seq_state,
+ size_t seq_state_generation)
: seq_state_(seq_state), seq_state_generation_(seq_state_generation) {}
base::Optional<base::StringView> GetString(
@@ -183,17 +178,10 @@
}
private:
- ProtoIncrementalState::PacketSequenceState* seq_state_;
+ PacketSequenceState* seq_state_;
size_t seq_state_generation_;
};
-namespace {
-// Slices which have been opened but haven't been closed yet will be marked
-// with these placeholder values.
-constexpr int64_t kPendingThreadDuration = -1;
-constexpr int64_t kPendingThreadInstructionDelta = -1;
-} // namespace
-
const char* HeapGraphRootTypeToString(int32_t type) {
switch (type) {
case protos::pbzero::HeapGraphRoot::ROOT_UNKNOWN:
@@ -263,60 +251,13 @@
context->storage->InternString("batt.current.avg_ua")),
oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
metatrace_id_(context->storage->InternString("metatrace")),
- task_file_name_args_key_id_(
- context->storage->InternString("task.posted_from.file_name")),
- task_function_name_args_key_id_(
- context->storage->InternString("task.posted_from.function_name")),
- task_line_number_args_key_id_(
- context->storage->InternString("task.posted_from.line_number")),
- log_message_body_key_id_(
- context->storage->InternString("track_event.log_message")),
data_name_id_(context->storage->InternString("data")),
raw_chrome_metadata_event_id_(
context->storage->InternString("chrome_event.metadata")),
raw_chrome_legacy_system_trace_event_id_(
context->storage->InternString("chrome_event.legacy_system_trace")),
raw_chrome_legacy_user_trace_event_id_(
- context->storage->InternString("chrome_event.legacy_user_trace")),
- raw_legacy_event_id_(
- context->storage->InternString("track_event.legacy_event")),
- legacy_event_category_key_id_(
- context->storage->InternString("legacy_event.category")),
- legacy_event_name_key_id_(
- context->storage->InternString("legacy_event.name")),
- legacy_event_phase_key_id_(
- context->storage->InternString("legacy_event.phase")),
- legacy_event_duration_ns_key_id_(
- context->storage->InternString("legacy_event.duration_ns")),
- legacy_event_thread_timestamp_ns_key_id_(
- context->storage->InternString("legacy_event.thread_timestamp_ns")),
- legacy_event_thread_duration_ns_key_id_(
- context->storage->InternString("legacy_event.thread_duration_ns")),
- legacy_event_thread_instruction_count_key_id_(
- context->storage->InternString(
- "legacy_event.thread_instruction_count")),
- legacy_event_thread_instruction_delta_key_id_(
- context->storage->InternString(
- "legacy_event.thread_instruction_delta")),
- legacy_event_use_async_tts_key_id_(
- context->storage->InternString("legacy_event.use_async_tts")),
- legacy_event_unscoped_id_key_id_(
- context->storage->InternString("legacy_event.unscoped_id")),
- legacy_event_global_id_key_id_(
- context->storage->InternString("legacy_event.global_id")),
- legacy_event_local_id_key_id_(
- context->storage->InternString("legacy_event.local_id")),
- legacy_event_id_scope_key_id_(
- context->storage->InternString("legacy_event.id_scope")),
- legacy_event_bind_id_key_id_(
- context->storage->InternString("legacy_event.bind_id")),
- legacy_event_bind_to_enclosing_key_id_(
- context->storage->InternString("legacy_event.bind_to_enclosing")),
- legacy_event_flow_direction_key_id_(
- context->storage->InternString("legacy_event.flow_direction")),
- flow_direction_value_in_id_(context->storage->InternString("in")),
- flow_direction_value_out_id_(context->storage->InternString("out")),
- flow_direction_value_inout_id_(context->storage->InternString("inout")) {
+ context->storage->InternString("chrome_event.legacy_user_trace")) {
for (const auto& name : BuildMeminfoCounterNames()) {
meminfo_strs_id_.emplace_back(context->storage->InternString(name));
}
@@ -413,12 +354,6 @@
if (packet.has_system_info())
ParseSystemInfo(packet.system_info());
- if (packet.has_track_event()) {
- ParseTrackEvent(ts, ttp.thread_timestamp, ttp.thread_instruction_count,
- ttp.packet_sequence_state,
- ttp.packet_sequence_state_generation, packet.track_event());
- }
-
if (packet.has_chrome_benchmark_metadata()) {
ParseChromeBenchmarkMetadata(packet.chrome_benchmark_metadata());
}
@@ -865,11 +800,10 @@
}
}
-void ProtoTraceParser::ParseProfilePacket(
- int64_t,
- ProtoIncrementalState::PacketSequenceState* sequence_state,
- size_t sequence_state_generation,
- ConstBytes blob) {
+void ProtoTraceParser::ParseProfilePacket(int64_t,
+ PacketSequenceState* sequence_state,
+ size_t sequence_state_generation,
+ ConstBytes blob) {
protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
context_->heap_profile_tracker->SetProfilePacketIndex(packet.index());
@@ -942,7 +876,7 @@
}
void ProtoTraceParser::ParseStreamingProfilePacket(
- ProtoIncrementalState::PacketSequenceState* sequence_state,
+ PacketSequenceState* sequence_state,
size_t sequence_state_generation,
ConstBytes blob) {
protos::pbzero::StreamingProfilePacket::Decoder packet(blob.data, blob.size);
@@ -1002,805 +936,6 @@
}
}
-void ProtoTraceParser::ParseTrackEvent(
- int64_t ts,
- int64_t tts,
- int64_t ticount,
- ProtoIncrementalState::PacketSequenceState* sequence_state,
- size_t sequence_state_generation,
- ConstBytes blob) {
- using LegacyEvent = protos::pbzero::TrackEvent::LegacyEvent;
-
- protos::pbzero::TrackEvent::Decoder event(blob.data, blob.size);
-
- const auto legacy_event_blob = event.legacy_event();
- LegacyEvent::Decoder legacy_event(legacy_event_blob.data,
- legacy_event_blob.size);
-
- // TODO(eseckler): This legacy event field will eventually be replaced by
- // fields in TrackEvent itself.
- if (PERFETTO_UNLIKELY(!event.type() && !legacy_event.has_phase())) {
- context_->storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("TrackEvent without type or phase");
- return;
- }
-
- ProcessTracker* procs = context_->process_tracker.get();
- TraceStorage* storage = context_->storage.get();
- TrackTracker* track_tracker = context_->track_tracker.get();
- SliceTracker* slice_tracker = context_->slice_tracker.get();
-
- std::vector<uint64_t> category_iids;
- for (auto it = event.category_iids(); it; ++it) {
- category_iids.push_back(*it);
- }
- std::vector<protozero::ConstChars> category_strings;
- for (auto it = event.categories(); it; ++it) {
- category_strings.push_back(*it);
- }
-
- StringId category_id = 0;
-
- // If there's a single category, we can avoid building a concatenated
- // string.
- if (PERFETTO_LIKELY(category_iids.size() == 1 && category_strings.empty())) {
- auto* decoder = sequence_state->LookupInternedMessage<
- protos::pbzero::InternedData::kEventCategoriesFieldNumber,
- protos::pbzero::EventCategory>(sequence_state_generation,
- category_iids[0]);
- if (decoder)
- category_id = storage->InternString(decoder->name());
- } else if (category_iids.empty() && category_strings.size() == 1) {
- category_id = storage->InternString(category_strings[0]);
- } else if (category_iids.size() + category_strings.size() > 1) {
- // We concatenate the category strings together since we currently only
- // support a single "cat" column.
- // TODO(eseckler): Support multi-category events in the table schema.
- std::string categories;
- for (uint64_t iid : category_iids) {
- auto* decoder = sequence_state->LookupInternedMessage<
- protos::pbzero::InternedData::kEventCategoriesFieldNumber,
- protos::pbzero::EventCategory>(sequence_state_generation, iid);
- if (!decoder)
- continue;
- base::StringView name = decoder->name();
- if (!categories.empty())
- categories.append(",");
- categories.append(name.data(), name.size());
- }
- for (const protozero::ConstChars& cat : category_strings) {
- if (!categories.empty())
- categories.append(",");
- categories.append(cat.data, cat.size);
- }
- if (!categories.empty())
- category_id = storage->InternString(base::StringView(categories));
- }
-
- StringId name_id = 0;
-
- uint64_t name_iid = event.name_iid();
- if (!name_iid)
- name_iid = legacy_event.name_iid();
-
- if (PERFETTO_LIKELY(name_iid)) {
- auto* decoder = sequence_state->LookupInternedMessage<
- protos::pbzero::InternedData::kEventNamesFieldNumber,
- protos::pbzero::EventName>(sequence_state_generation, name_iid);
- if (decoder)
- name_id = storage->InternString(decoder->name());
- } else if (event.has_name()) {
- name_id = storage->InternString(event.name());
- }
-
- // TODO(eseckler): Also consider track_uuid from TrackEventDefaults.
- // Fall back to the default descriptor track (uuid 0).
- uint64_t track_uuid = event.has_track_uuid() ? event.track_uuid() : 0u;
- TrackId track_id;
- base::Optional<UniqueTid> utid;
- base::Optional<UniqueTid> upid;
-
- // Determine track from track_uuid specified in either TrackEvent or
- // TrackEventDefaults. If none is set, fall back to the track specified by the
- // sequence's (or event's) pid + tid or a default track.
- if (track_uuid) {
- base::Optional<TrackId> opt_track_id =
- track_tracker->GetDescriptorTrack(track_uuid);
- if (!opt_track_id) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("TrackEvent with unknown track_uuid %" PRIu64, track_uuid);
- return;
- }
- track_id = *opt_track_id;
-
- auto thread_track_row =
- context_->storage->thread_track_table().id().IndexOf(
- SqlValue::Long(track_id));
- if (thread_track_row) {
- utid = storage->thread_track_table().utid()[*thread_track_row];
- upid = storage->GetThread(*utid).upid;
- } else {
- auto process_track_row =
- context_->storage->process_track_table().id().IndexOf(
- SqlValue::Long(track_id));
- if (process_track_row)
- upid = storage->process_track_table().upid()[*process_track_row];
- }
- } else if (sequence_state->pid_and_tid_valid() ||
- (legacy_event.has_pid_override() &&
- legacy_event.has_tid_override())) {
- uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
- uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
- if (legacy_event.has_pid_override())
- pid = static_cast<uint32_t>(legacy_event.pid_override());
- if (legacy_event.has_tid_override())
- tid = static_cast<uint32_t>(legacy_event.tid_override());
-
- utid = procs->UpdateThread(tid, pid);
- upid = storage->GetThread(*utid).upid;
- track_id = track_tracker->GetOrCreateDescriptorTrackForThread(*utid);
- } else {
- track_id = track_tracker->GetOrCreateDefaultDescriptorTrack();
- }
-
- // TODO(eseckler): Replace phase with type and remove handling of
- // legacy_event.phase() once it is no longer used by producers.
- int32_t phase = 0;
- if (legacy_event.has_phase()) {
- phase = legacy_event.phase();
-
- switch (phase) {
- case 'b':
- case 'e':
- case 'n': {
- // Intern tracks for legacy async events based on legacy event ids.
- int64_t source_id = 0;
- bool source_id_is_process_scoped = false;
- if (legacy_event.has_unscoped_id()) {
- source_id = static_cast<int64_t>(legacy_event.unscoped_id());
- } else if (legacy_event.has_global_id()) {
- source_id = static_cast<int64_t>(legacy_event.global_id());
- } else if (legacy_event.has_local_id()) {
- if (!upid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG(
- "TrackEvent with local_id without process association");
- return;
- }
-
- source_id = static_cast<int64_t>(legacy_event.local_id());
- source_id_is_process_scoped = true;
- } else {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("Async LegacyEvent without ID");
- return;
- }
-
- // Catapult treats nestable async events of different categories with
- // the same ID as separate tracks. We replicate the same behavior here.
- StringId id_scope = category_id;
- if (legacy_event.has_id_scope()) {
- std::string concat = storage->GetString(category_id).ToStdString() +
- ":" + legacy_event.id_scope().ToStdString();
- id_scope = storage->InternString(base::StringView(concat));
- }
-
- track_id = context_->track_tracker->InternLegacyChromeAsyncTrack(
- name_id, upid ? *upid : 0, source_id, source_id_is_process_scoped,
- id_scope);
- break;
- }
- case 'i':
- case 'I': {
- // Intern tracks for global or process-scoped legacy instant events.
- switch (legacy_event.instant_event_scope()) {
- case LegacyEvent::SCOPE_UNSPECIFIED:
- case LegacyEvent::SCOPE_THREAD:
- // Thread-scoped legacy instant events already have the right track
- // based on the tid/pid of the sequence.
- if (!utid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG(
- "Thread-scoped instant event without thread association");
- return;
- }
- break;
- case LegacyEvent::SCOPE_GLOBAL:
- track_id = context_->track_tracker
- ->GetOrCreateLegacyChromeGlobalInstantTrack();
- break;
- case LegacyEvent::SCOPE_PROCESS:
- if (!upid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG(
- "Process-scoped instant event without process association");
- return;
- }
-
- track_id =
- context_->track_tracker->InternLegacyChromeProcessInstantTrack(
- *upid);
- break;
- }
- break;
- }
- default:
- break;
- }
- } else {
- switch (event.type()) {
- case protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN:
- phase = utid ? 'B' : 'b';
- break;
- case protos::pbzero::TrackEvent::TYPE_SLICE_END:
- phase = utid ? 'E' : 'e';
- break;
- case protos::pbzero::TrackEvent::TYPE_INSTANT:
- phase = utid ? 'i' : 'n';
- break;
- default:
- PERFETTO_FATAL("unexpected event type %d", event.type());
- return;
- }
- }
-
- auto args_callback = [this, &event, &legacy_event, &sequence_state,
- sequence_state_generation, ts,
- utid](ArgsTracker* args_tracker, RowId row_id) {
- for (auto it = event.debug_annotations(); it; ++it) {
- ParseDebugAnnotationArgs(*it, sequence_state, sequence_state_generation,
- args_tracker, row_id);
- }
-
- if (event.has_task_execution()) {
- ParseTaskExecutionArgs(event.task_execution(), sequence_state,
- sequence_state_generation, args_tracker, row_id);
- }
-
- if (event.has_log_message()) {
- ParseLogMessage(event.log_message(), sequence_state,
- sequence_state_generation, ts, utid, args_tracker,
- row_id);
- }
-
- // TODO(eseckler): Parse legacy flow events into flow events table once we
- // have a design for it.
- if (legacy_event.has_bind_id()) {
- args_tracker->AddArg(row_id, legacy_event_bind_id_key_id_,
- legacy_event_bind_id_key_id_,
- Variadic::UnsignedInteger(legacy_event.bind_id()));
- }
-
- if (legacy_event.bind_to_enclosing()) {
- args_tracker->AddArg(row_id, legacy_event_bind_to_enclosing_key_id_,
- legacy_event_bind_to_enclosing_key_id_,
- Variadic::Boolean(true));
- }
-
- if (legacy_event.flow_direction()) {
- StringId value;
- switch (legacy_event.flow_direction()) {
- case protos::pbzero::TrackEvent::LegacyEvent::FLOW_IN:
- value = flow_direction_value_in_id_;
- break;
- case protos::pbzero::TrackEvent::LegacyEvent::FLOW_OUT:
- value = flow_direction_value_out_id_;
- break;
- case protos::pbzero::TrackEvent::LegacyEvent::FLOW_INOUT:
- value = flow_direction_value_inout_id_;
- break;
- default:
- PERFETTO_FATAL("Unknown flow direction: %d",
- legacy_event.flow_direction());
- break;
- }
- args_tracker->AddArg(row_id, legacy_event_flow_direction_key_id_,
- legacy_event_flow_direction_key_id_,
- Variadic::String(value));
- }
- };
-
- switch (static_cast<char>(phase)) {
- case 'B': { // TRACE_EVENT_PHASE_BEGIN.
- if (!utid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("TrackEvent with phase B without thread association");
- return;
- }
-
- auto opt_slice_id =
- slice_tracker->Begin(ts, track_id, *utid, RefType::kRefUtid,
- category_id, name_id, args_callback);
- if (opt_slice_id.has_value()) {
- auto* thread_slices = storage->mutable_thread_slices();
- PERFETTO_DCHECK(!thread_slices->slice_count() ||
- thread_slices->slice_ids().back() <
- opt_slice_id.value());
- thread_slices->AddThreadSlice(opt_slice_id.value(), tts,
- kPendingThreadDuration, ticount,
- kPendingThreadInstructionDelta);
- }
- break;
- }
- case 'E': { // TRACE_EVENT_PHASE_END.
- if (!utid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("TrackEvent with phase E without thread association");
- return;
- }
-
- auto opt_slice_id =
- slice_tracker->End(ts, track_id, category_id, name_id, args_callback);
- if (opt_slice_id.has_value()) {
- auto* thread_slices = storage->mutable_thread_slices();
- thread_slices->UpdateThreadDeltasForSliceId(opt_slice_id.value(), tts,
- ticount);
- }
- break;
- }
- case 'X': { // TRACE_EVENT_PHASE_COMPLETE.
- if (!utid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("TrackEvent with phase X without thread association");
- return;
- }
-
- auto duration_ns = legacy_event.duration_us() * 1000;
- if (duration_ns < 0)
- return;
- auto opt_slice_id = slice_tracker->Scoped(
- ts, track_id, *utid, RefType::kRefUtid, category_id, name_id,
- duration_ns, args_callback);
- if (opt_slice_id.has_value()) {
- auto* thread_slices = storage->mutable_thread_slices();
- PERFETTO_DCHECK(!thread_slices->slice_count() ||
- thread_slices->slice_ids().back() <
- opt_slice_id.value());
- auto thread_duration_ns = legacy_event.thread_duration_us() * 1000;
- thread_slices->AddThreadSlice(opt_slice_id.value(), tts,
- thread_duration_ns, ticount,
- legacy_event.thread_instruction_delta());
- }
- break;
- }
- case 'i':
- case 'I': { // TRACE_EVENT_PHASE_INSTANT.
- // Handle instant events as slices with zero duration, so that they end
- // up nested underneath their parent slices.
- int64_t duration_ns = 0;
- int64_t tidelta = 0;
-
- switch (legacy_event.instant_event_scope()) {
- case LegacyEvent::SCOPE_UNSPECIFIED:
- case LegacyEvent::SCOPE_THREAD: {
- // TODO(lalitm): Associate thread slices with track instead.
- auto opt_slice_id = slice_tracker->Scoped(
- ts, track_id, *utid, RefType::kRefUtid, category_id, name_id,
- duration_ns, args_callback);
- if (opt_slice_id.has_value()) {
- auto* thread_slices = storage->mutable_thread_slices();
- PERFETTO_DCHECK(!thread_slices->slice_count() ||
- thread_slices->slice_ids().back() <
- opt_slice_id.value());
- thread_slices->AddThreadSlice(opt_slice_id.value(), tts,
- duration_ns, ticount, tidelta);
- }
- break;
- }
- case LegacyEvent::SCOPE_GLOBAL: {
- slice_tracker->Scoped(ts, track_id, /*ref=*/0, RefType::kRefNoRef,
- category_id, name_id, duration_ns,
- args_callback);
- break;
- }
- case LegacyEvent::SCOPE_PROCESS: {
- slice_tracker->Scoped(ts, track_id, *upid, RefType::kRefUpid,
- category_id, name_id, duration_ns,
- args_callback);
- break;
- }
- default: {
- PERFETTO_FATAL("Unknown instant event scope: %u",
- legacy_event.instant_event_scope());
- break;
- }
- }
- break;
- }
- case 'b': { // TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN
- auto opt_slice_id =
- slice_tracker->Begin(ts, track_id, track_id, RefType::kRefTrack,
- category_id, name_id, args_callback);
- // For the time beeing, we only create vtrack slice rows if we need to
- // store thread timestamps/counters.
- if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
- auto* vtrack_slices = storage->mutable_virtual_track_slices();
- PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
- vtrack_slices->slice_ids().back() <
- opt_slice_id.value());
- vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
- kPendingThreadDuration, ticount,
- kPendingThreadInstructionDelta);
- }
- break;
- }
- case 'e': { // TRACE_EVENT_PHASE_NESTABLE_ASYNC_END
- auto opt_slice_id =
- slice_tracker->End(ts, track_id, category_id, name_id, args_callback);
- if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
- auto* vtrack_slices = storage->mutable_virtual_track_slices();
- vtrack_slices->UpdateThreadDeltasForSliceId(opt_slice_id.value(), tts,
- ticount);
- }
- break;
- }
- case 'n': { // TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT
- // Handle instant events as slices with zero duration, so that they end up
- // nested underneath their parent slices.
- int64_t duration_ns = 0;
- int64_t tidelta = 0;
- auto opt_slice_id = slice_tracker->Scoped(
- ts, track_id, track_id, RefType::kRefTrack, category_id, name_id,
- duration_ns, args_callback);
- if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
- auto* vtrack_slices = storage->mutable_virtual_track_slices();
- PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
- vtrack_slices->slice_ids().back() <
- opt_slice_id.value());
- vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
- duration_ns, ticount, tidelta);
- }
- break;
- }
- case 'M': { // TRACE_EVENT_PHASE_METADATA (process and thread names).
- // Parse process and thread names from correspondingly named events.
- // TODO(eseckler): Also consider names from process/thread descriptors.
- NullTermStringView event_name = storage->GetString(name_id);
- PERFETTO_DCHECK(event_name.data());
- if (strcmp(event_name.c_str(), "thread_name") == 0) {
- if (!utid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG(
- "thread_name metadata event without thread association");
- return;
- }
-
- auto it = event.debug_annotations();
- if (!it)
- break;
- protos::pbzero::DebugAnnotation::Decoder annotation(*it);
- auto thread_name = annotation.string_value();
- if (!thread_name.size)
- break;
- auto thread_name_id = storage->InternString(thread_name);
- procs->UpdateThreadName(storage->GetThread(*utid).tid, thread_name_id);
- break;
- }
- if (strcmp(event_name.c_str(), "process_name") == 0) {
- if (!upid) {
- storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG(
- "process_name metadata event without process association");
- return;
- }
-
- auto it = event.debug_annotations();
- if (!it)
- break;
- protos::pbzero::DebugAnnotation::Decoder annotation(*it);
- auto process_name = annotation.string_value();
- if (!process_name.size)
- break;
- procs->SetProcessMetadata(storage->GetProcess(*upid).pid, base::nullopt,
- process_name);
- break;
- }
- // Other metadata events are proxied via the raw table for JSON export.
- ParseLegacyEventAsRawEvent(ts, tts, ticount, utid, category_id, name_id,
- legacy_event, args_callback);
- break;
- }
- default: {
- // Other events are proxied via the raw table for JSON export.
- ParseLegacyEventAsRawEvent(ts, tts, ticount, utid, category_id, name_id,
- legacy_event, args_callback);
- }
- }
-}
-
-void ProtoTraceParser::ParseLegacyEventAsRawEvent(
- int64_t ts,
- int64_t tts,
- int64_t ticount,
- base::Optional<UniqueTid> utid,
- StringId category_id,
- StringId name_id,
- const protos::pbzero::TrackEvent::LegacyEvent::Decoder& legacy_event,
- SliceTracker::SetArgsCallback args_callback) {
- if (!utid) {
- context_->storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("raw legacy event without thread association");
- return;
- }
-
- RowId row_id = context_->storage->mutable_raw_events()->AddRawEvent(
- ts, raw_legacy_event_id_, 0, *utid);
- ArgsTracker args(context_);
- args.AddArg(row_id, legacy_event_category_key_id_,
- legacy_event_category_key_id_, Variadic::String(category_id));
- args.AddArg(row_id, legacy_event_name_key_id_, legacy_event_name_key_id_,
- Variadic::String(name_id));
-
- std::string phase_string(1, static_cast<char>(legacy_event.phase()));
- StringId phase_id = context_->storage->InternString(phase_string.c_str());
- args.AddArg(row_id, legacy_event_phase_key_id_, legacy_event_phase_key_id_,
- Variadic::String(phase_id));
-
- if (legacy_event.has_duration_us()) {
- args.AddArg(row_id, legacy_event_duration_ns_key_id_,
- legacy_event_duration_ns_key_id_,
- Variadic::Integer(legacy_event.duration_us() * 1000));
- }
-
- if (tts) {
- args.AddArg(row_id, legacy_event_thread_timestamp_ns_key_id_,
- legacy_event_thread_timestamp_ns_key_id_,
- Variadic::Integer(tts));
- if (legacy_event.has_thread_duration_us()) {
- args.AddArg(row_id, legacy_event_thread_duration_ns_key_id_,
- legacy_event_thread_duration_ns_key_id_,
- Variadic::Integer(legacy_event.thread_duration_us() * 1000));
- }
- }
-
- if (ticount) {
- args.AddArg(row_id, legacy_event_thread_instruction_count_key_id_,
- legacy_event_thread_instruction_count_key_id_,
- Variadic::Integer(tts));
- if (legacy_event.has_thread_instruction_delta()) {
- args.AddArg(row_id, legacy_event_thread_instruction_delta_key_id_,
- legacy_event_thread_instruction_delta_key_id_,
- Variadic::Integer(legacy_event.thread_instruction_delta()));
- }
- }
-
- if (legacy_event.use_async_tts()) {
- args.AddArg(row_id, legacy_event_use_async_tts_key_id_,
- legacy_event_use_async_tts_key_id_, Variadic::Boolean(true));
- }
-
- bool has_id = false;
- if (legacy_event.has_unscoped_id()) {
- // Unscoped ids are either global or local depending on the phase. Pass them
- // through as unscoped IDs to JSON export to preserve this behavior.
- args.AddArg(row_id, legacy_event_unscoped_id_key_id_,
- legacy_event_unscoped_id_key_id_,
- Variadic::UnsignedInteger(legacy_event.unscoped_id()));
- has_id = true;
- } else if (legacy_event.has_global_id()) {
- args.AddArg(row_id, legacy_event_global_id_key_id_,
- legacy_event_global_id_key_id_,
- Variadic::UnsignedInteger(legacy_event.global_id()));
- has_id = true;
- } else if (legacy_event.has_local_id()) {
- args.AddArg(row_id, legacy_event_local_id_key_id_,
- legacy_event_local_id_key_id_,
- Variadic::UnsignedInteger(legacy_event.local_id()));
- has_id = true;
- }
-
- if (has_id && legacy_event.has_id_scope() && legacy_event.id_scope().size) {
- args.AddArg(row_id, legacy_event_id_scope_key_id_,
- legacy_event_id_scope_key_id_,
- Variadic::String(
- context_->storage->InternString(legacy_event.id_scope())));
- }
-
- // No need to parse legacy_event.instant_event_scope() because we import
- // instant events into the slice table.
-
- args_callback(&args, row_id);
-}
-
-void ProtoTraceParser::ParseDebugAnnotationArgs(
- ConstBytes debug_annotation,
- ProtoIncrementalState::PacketSequenceState* sequence_state,
- size_t sequence_state_generation,
- ArgsTracker* args_tracker,
- RowId row_id) {
- TraceStorage* storage = context_->storage.get();
-
- protos::pbzero::DebugAnnotation::Decoder annotation(debug_annotation.data,
- debug_annotation.size);
-
- StringId name_id = 0;
-
- uint64_t name_iid = annotation.name_iid();
- if (PERFETTO_LIKELY(name_iid)) {
- auto* decoder = sequence_state->LookupInternedMessage<
- protos::pbzero::InternedData::kDebugAnnotationNamesFieldNumber,
- protos::pbzero::DebugAnnotationName>(sequence_state_generation,
- name_iid);
- if (!decoder)
- return;
-
- std::string name_prefixed = "debug." + decoder->name().ToStdString();
- name_id = storage->InternString(base::StringView(name_prefixed));
- } else if (annotation.has_name()) {
- name_id = storage->InternString(annotation.name());
- } else {
- context_->storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("Debug annotation without name");
- return;
- }
-
- if (annotation.has_bool_value()) {
- args_tracker->AddArg(row_id, name_id, name_id,
- Variadic::Boolean(annotation.bool_value()));
- } else if (annotation.has_uint_value()) {
- args_tracker->AddArg(row_id, name_id, name_id,
- Variadic::UnsignedInteger(annotation.uint_value()));
- } else if (annotation.has_int_value()) {
- args_tracker->AddArg(row_id, name_id, name_id,
- Variadic::Integer(annotation.int_value()));
- } else if (annotation.has_double_value()) {
- args_tracker->AddArg(row_id, name_id, name_id,
- Variadic::Real(annotation.double_value()));
- } else if (annotation.has_string_value()) {
- args_tracker->AddArg(
- row_id, name_id, name_id,
- Variadic::String(storage->InternString(annotation.string_value())));
- } else if (annotation.has_pointer_value()) {
- args_tracker->AddArg(row_id, name_id, name_id,
- Variadic::Pointer(annotation.pointer_value()));
- } else if (annotation.has_legacy_json_value()) {
- args_tracker->AddArg(
- row_id, name_id, name_id,
- Variadic::Json(storage->InternString(annotation.legacy_json_value())));
- } else if (annotation.has_nested_value()) {
- auto name = storage->GetString(name_id);
- ParseNestedValueArgs(annotation.nested_value(), name, name, args_tracker,
- row_id);
- }
-}
-
-void ProtoTraceParser::ParseNestedValueArgs(ConstBytes nested_value,
- base::StringView flat_key,
- base::StringView key,
- ArgsTracker* args_tracker,
- RowId row_id) {
- protos::pbzero::DebugAnnotation::NestedValue::Decoder value(
- nested_value.data, nested_value.size);
- switch (value.nested_type()) {
- case protos::pbzero::DebugAnnotation::NestedValue::UNSPECIFIED: {
- auto flat_key_id = context_->storage->InternString(flat_key);
- auto key_id = context_->storage->InternString(key);
- // Leaf value.
- if (value.has_bool_value()) {
- args_tracker->AddArg(row_id, flat_key_id, key_id,
- Variadic::Boolean(value.bool_value()));
- } else if (value.has_int_value()) {
- args_tracker->AddArg(row_id, flat_key_id, key_id,
- Variadic::Integer(value.int_value()));
- } else if (value.has_double_value()) {
- args_tracker->AddArg(row_id, flat_key_id, key_id,
- Variadic::Real(value.double_value()));
- } else if (value.has_string_value()) {
- args_tracker->AddArg(row_id, flat_key_id, key_id,
- Variadic::String(context_->storage->InternString(
- value.string_value())));
- }
- break;
- }
- case protos::pbzero::DebugAnnotation::NestedValue::DICT: {
- 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 = (*key_it).ToStdString();
- std::string child_flat_key = flat_key.ToStdString() + "." + child_name;
- std::string child_key = key.ToStdString() + "." + child_name;
- ParseNestedValueArgs(*value_it, base::StringView(child_flat_key),
- base::StringView(child_key), args_tracker, row_id);
- }
- break;
- }
- case protos::pbzero::DebugAnnotation::NestedValue::ARRAY: {
- int child_index = 0;
- std::string child_flat_key = flat_key.ToStdString();
- for (auto value_it = value.array_values(); value_it;
- ++value_it, ++child_index) {
- std::string child_key =
- key.ToStdString() + "[" + std::to_string(child_index) + "]";
- ParseNestedValueArgs(*value_it, base::StringView(child_flat_key),
- base::StringView(child_key), args_tracker, row_id);
- }
- break;
- }
- }
-}
-
-void ProtoTraceParser::ParseTaskExecutionArgs(
- ConstBytes task_execution,
- ProtoIncrementalState::PacketSequenceState* sequence_state,
- size_t sequence_state_generation,
- ArgsTracker* args_tracker,
- RowId row) {
- protos::pbzero::TaskExecution::Decoder task(task_execution.data,
- task_execution.size);
- uint64_t iid = task.posted_from_iid();
- if (!iid)
- return;
-
- auto* decoder = sequence_state->LookupInternedMessage<
- protos::pbzero::InternedData::kSourceLocationsFieldNumber,
- protos::pbzero::SourceLocation>(sequence_state_generation, iid);
- if (!decoder)
- return;
-
- StringId file_name_id = 0;
- StringId function_name_id = 0;
- uint32_t line_number = 0;
-
- TraceStorage* storage = context_->storage.get();
- file_name_id = storage->InternString(decoder->file_name());
- function_name_id = storage->InternString(decoder->function_name());
- line_number = decoder->line_number();
-
- args_tracker->AddArg(row, task_file_name_args_key_id_,
- task_file_name_args_key_id_,
- Variadic::String(file_name_id));
- args_tracker->AddArg(row, task_function_name_args_key_id_,
- task_function_name_args_key_id_,
- Variadic::String(function_name_id));
-
- args_tracker->AddArg(row, task_line_number_args_key_id_,
- task_line_number_args_key_id_,
- Variadic::UnsignedInteger(line_number));
-}
-
-void ProtoTraceParser::ParseLogMessage(
- ConstBytes blob,
- ProtoIncrementalState::PacketSequenceState* sequence_state,
- size_t sequence_state_generation,
- int64_t ts,
- base::Optional<UniqueTid> utid,
- ArgsTracker* args_tracker,
- RowId row) {
- if (!utid) {
- context_->storage->IncrementStats(stats::track_event_parser_errors);
- PERFETTO_DLOG("LogMessage without thread association");
- return;
- }
-
- protos::pbzero::LogMessage::Decoder message(blob.data, blob.size);
-
- TraceStorage* storage = context_->storage.get();
-
- StringId log_message_id = 0;
-
- auto* decoder = sequence_state->LookupInternedMessage<
- protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
- protos::pbzero::LogMessageBody>(sequence_state_generation,
- message.body_iid());
- if (!decoder)
- return;
-
- log_message_id = storage->InternString(decoder->body());
-
- // TODO(nicomazz): LogMessage also contains the source of the message (file
- // and line number). Android logs doesn't support this so far.
- context_->storage->mutable_android_log()->AddLogEvent(
- ts, *utid,
- /*priority*/ 0,
- /*tag_id*/ 0, // TODO(nicomazz): Abuse tag_id to display
- // "file_name:line_number".
- log_message_id);
-
- args_tracker->AddArg(row, log_message_body_key_id_, log_message_body_key_id_,
- Variadic::String(log_message_id));
- // TODO(nicomazz): Add the source location as an argument.
-}
-
void ProtoTraceParser::ParseChromeBenchmarkMetadata(ConstBytes blob) {
TraceStorage* storage = context_->storage.get();
protos::pbzero::ChromeBenchmarkMetadata::Decoder packet(blob.data, blob.size);
diff --git a/src/trace_processor/proto_trace_parser.h b/src/trace_processor/proto_trace_parser.h
index 1ed2ac7..8e52c8a 100644
--- a/src/trace_processor/proto_trace_parser.h
+++ b/src/trace_processor/proto_trace_parser.h
@@ -26,20 +26,18 @@
#include "perfetto/ext/base/string_view.h"
#include "perfetto/protozero/field.h"
#include "src/trace_processor/graphics_event_parser.h"
-#include "src/trace_processor/proto_incremental_state.h"
-#include "src/trace_processor/slice_tracker.h"
#include "src/trace_processor/timestamped_trace_piece.h"
#include "src/trace_processor/trace_blob_view.h"
#include "src/trace_processor/trace_parser.h"
#include "src/trace_processor/trace_storage.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
-#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace perfetto {
namespace trace_processor {
class ArgsTracker;
+class PacketSequenceState;
class TraceProcessorContext;
class ProtoTraceParser : public TraceParser {
@@ -68,56 +66,19 @@
void ParseAndroidLogStats(ConstBytes);
void ParseTraceStats(ConstBytes);
void ParseProfilePacket(int64_t ts,
- ProtoIncrementalState::PacketSequenceState*,
+ PacketSequenceState*,
size_t sequence_state_generation,
ConstBytes);
- void ParseStreamingProfilePacket(ProtoIncrementalState::PacketSequenceState*,
+ void ParseStreamingProfilePacket(PacketSequenceState*,
size_t sequence_state_generation,
ConstBytes);
void ParseSystemInfo(ConstBytes);
- void ParseTrackEvent(int64_t ts,
- int64_t tts,
- int64_t ticount,
- ProtoIncrementalState::PacketSequenceState*,
- size_t sequence_state_generation,
- ConstBytes);
- void ParseLegacyEventAsRawEvent(
- int64_t ts,
- int64_t tts,
- int64_t ticount,
- base::Optional<UniqueTid> utid,
- StringId category_id,
- StringId name_id,
- const protos::pbzero::TrackEvent::LegacyEvent::Decoder& legacy_event,
- SliceTracker::SetArgsCallback args_callback);
- void ParseDebugAnnotationArgs(ConstBytes debug_annotation,
- ProtoIncrementalState::PacketSequenceState*,
- size_t sequence_state_generation,
- ArgsTracker* args_tracker,
- RowId row);
- void ParseNestedValueArgs(ConstBytes nested_value,
- base::StringView flat_key,
- base::StringView key,
- ArgsTracker* args_tracker,
- RowId row);
- void ParseTaskExecutionArgs(ConstBytes task_execution,
- ProtoIncrementalState::PacketSequenceState*,
- size_t sequence_state_generation,
- ArgsTracker* args_tracker,
- RowId row);
void ParseChromeBenchmarkMetadata(ConstBytes);
void ParseChromeEvents(int64_t ts, ConstBytes);
void ParseMetatraceEvent(int64_t ts, ConstBytes);
void ParseTraceConfig(ConstBytes);
void ParseStatsdMetadata(ConstBytes);
void ParseAndroidPackagesList(ConstBytes);
- void ParseLogMessage(ConstBytes,
- ProtoIncrementalState::PacketSequenceState*,
- size_t sequence_state_generation,
- int64_t,
- base::Optional<UniqueTid>,
- ArgsTracker*,
- RowId);
void ParseModuleSymbols(ConstBytes);
void ParseHeapGraph(int64_t ts, ConstBytes);
@@ -144,34 +105,10 @@
const StringId batt_current_avg_id_;
const StringId oom_score_adj_id_;
const StringId metatrace_id_;
- const StringId task_file_name_args_key_id_;
- const StringId task_function_name_args_key_id_;
- const StringId task_line_number_args_key_id_;
- const StringId log_message_body_key_id_;
const StringId data_name_id_;
const StringId raw_chrome_metadata_event_id_;
const StringId raw_chrome_legacy_system_trace_event_id_;
const StringId raw_chrome_legacy_user_trace_event_id_;
- const StringId raw_legacy_event_id_;
- const StringId legacy_event_category_key_id_;
- const StringId legacy_event_name_key_id_;
- const StringId legacy_event_phase_key_id_;
- const StringId legacy_event_duration_ns_key_id_;
- const StringId legacy_event_thread_timestamp_ns_key_id_;
- const StringId legacy_event_thread_duration_ns_key_id_;
- const StringId legacy_event_thread_instruction_count_key_id_;
- const StringId legacy_event_thread_instruction_delta_key_id_;
- const StringId legacy_event_use_async_tts_key_id_;
- const StringId legacy_event_unscoped_id_key_id_;
- const StringId legacy_event_global_id_key_id_;
- const StringId legacy_event_local_id_key_id_;
- const StringId legacy_event_id_scope_key_id_;
- const StringId legacy_event_bind_id_key_id_;
- const StringId legacy_event_bind_to_enclosing_key_id_;
- const StringId legacy_event_flow_direction_key_id_;
- const StringId flow_direction_value_in_id_;
- const StringId flow_direction_value_out_id_;
- const StringId flow_direction_value_inout_id_;
std::vector<StringId> meminfo_strs_id_;
std::vector<StringId> vmstat_strs_id_;
std::vector<StringId> power_rails_strs_id_;
diff --git a/src/trace_processor/proto_trace_tokenizer.cc b/src/trace_processor/proto_trace_tokenizer.cc
index 379573b..17afd4e 100644
--- a/src/trace_processor/proto_trace_tokenizer.cc
+++ b/src/trace_processor/proto_trace_tokenizer.cc
@@ -30,14 +30,12 @@
#include "src/trace_processor/clock_tracker.h"
#include "src/trace_processor/event_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/track_event_module.h"
-#include "src/trace_processor/process_tracker.h"
-#include "src/trace_processor/proto_incremental_state.h"
#include "src/trace_processor/stats.h"
-#include "src/trace_processor/trace_blob_view.h"
#include "src/trace_processor/trace_sorter.h"
#include "src/trace_processor/trace_storage.h"
-#include "src/trace_processor/track_tracker.h"
#include "protos/perfetto/config/trace_config.pbzero.h"
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
@@ -45,17 +43,10 @@
#include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
#include "protos/perfetto/trace/trace.pbzero.h"
-#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
-#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
-#include "protos/perfetto/trace/track_event/task_execution.pbzero.h"
-#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
-#include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
-#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace perfetto {
namespace trace_processor {
-using protozero::ProtoDecoder;
using protozero::proto_utils::MakeTagLengthDelimited;
using protozero::proto_utils::ParseVarInt;
@@ -287,36 +278,16 @@
}
ModuleResult res = ModuleResult::Ignored();
- res = context_->ftrace_module->TokenizePacket(decoder, &packet, timestamp);
+ res = context_->ftrace_module->TokenizePacket(decoder, &packet, timestamp,
+ state);
if (!res.ignored())
return res.ToStatus();
- res =
- context_->track_event_module->TokenizePacket(decoder, &packet, timestamp);
+ res = context_->track_event_module->TokenizePacket(decoder, &packet,
+ timestamp, state);
if (!res.ignored())
return res.ToStatus();
- if (decoder.has_track_descriptor()) {
- ParseTrackDescriptorPacket(decoder);
- return util::OkStatus();
- }
-
- if (decoder.has_track_event()) {
- ParseTrackEventPacket(decoder, std::move(packet), timestamp);
- return util::OkStatus();
- }
-
- // TODO(eseckler): Remove this once Chrome has switched fully over to
- // TrackDescriptors.
- if (decoder.has_thread_descriptor()) {
- ParseThreadDescriptorPacket(decoder);
- return util::OkStatus();
- }
- if (decoder.has_process_descriptor()) {
- ParseProcessDescriptorPacket(decoder);
- return util::OkStatus();
- }
-
if (decoder.has_compressed_packets()) {
protozero::ConstBytes field = decoder.compressed_packets();
const size_t field_off = packet.offset_of(field.data);
@@ -431,185 +402,6 @@
}
}
-void ProtoTraceTokenizer::ParseTrackDescriptorPacket(
- const protos::pbzero::TracePacket::Decoder& packet_decoder) {
- auto track_descriptor_field = packet_decoder.track_descriptor();
- protos::pbzero::TrackDescriptor::Decoder track_descriptor_decoder(
- track_descriptor_field.data, track_descriptor_field.size);
-
- if (!track_descriptor_decoder.has_uuid()) {
- PERFETTO_ELOG("TrackDescriptor packet without trusted_packet_sequence_id");
- context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
- return;
- }
-
- base::Optional<UniquePid> upid;
- base::Optional<UniqueTid> utid;
-
- if (track_descriptor_decoder.has_process()) {
- auto process_descriptor_field = track_descriptor_decoder.process();
- protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
- process_descriptor_field.data, process_descriptor_field.size);
-
- // TODO(eseckler): Also parse process name / type here.
-
- upid = context_->process_tracker->GetOrCreateProcess(
- static_cast<uint32_t>(process_descriptor_decoder.pid()));
- }
-
- if (track_descriptor_decoder.has_thread()) {
- auto thread_descriptor_field = track_descriptor_decoder.thread();
- protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
- thread_descriptor_field.data, thread_descriptor_field.size);
-
- ParseThreadDescriptor(thread_descriptor_decoder);
- utid = context_->process_tracker->UpdateThread(
- static_cast<uint32_t>(thread_descriptor_decoder.tid()),
- static_cast<uint32_t>(thread_descriptor_decoder.pid()));
- upid = *context_->storage->GetThread(*utid).upid;
- }
-
- StringId name_id =
- context_->storage->InternString(track_descriptor_decoder.name());
-
- context_->track_tracker->UpdateDescriptorTrack(
- track_descriptor_decoder.uuid(), name_id, upid, utid);
-}
-
-void ProtoTraceTokenizer::ParseProcessDescriptorPacket(
- const protos::pbzero::TracePacket::Decoder& packet_decoder) {
- protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
- packet_decoder.process_descriptor());
- if (!process_descriptor_decoder.has_chrome_process_type())
- return;
- base::StringView name = "Unknown";
- switch (process_descriptor_decoder.chrome_process_type()) {
- case protos::pbzero::ProcessDescriptor::PROCESS_BROWSER:
- name = "Browser";
- break;
- case protos::pbzero::ProcessDescriptor::PROCESS_RENDERER:
- name = "Renderer";
- break;
- case protos::pbzero::ProcessDescriptor::PROCESS_UTILITY:
- name = "Utility";
- break;
- case protos::pbzero::ProcessDescriptor::PROCESS_ZYGOTE:
- name = "Zygote";
- break;
- case protos::pbzero::ProcessDescriptor::PROCESS_SANDBOX_HELPER:
- name = "SandboxHelper";
- break;
- case protos::pbzero::ProcessDescriptor::PROCESS_GPU:
- name = "Gpu";
- break;
- case protos::pbzero::ProcessDescriptor::PROCESS_PPAPI_PLUGIN:
- name = "PpapiPlugin";
- break;
- case protos::pbzero::ProcessDescriptor::PROCESS_PPAPI_BROKER:
- name = "PpapiBroker";
- break;
- }
- context_->process_tracker->SetProcessMetadata(
- static_cast<uint32_t>(process_descriptor_decoder.pid()), base::nullopt,
- name);
-}
-
-void ProtoTraceTokenizer::ParseThreadDescriptorPacket(
- const protos::pbzero::TracePacket::Decoder& packet_decoder) {
- if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
- PERFETTO_ELOG("ThreadDescriptor packet without trusted_packet_sequence_id");
- context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
- return;
- }
-
- auto* state = GetIncrementalStateForPacketSequence(
- packet_decoder.trusted_packet_sequence_id());
-
- // TrackEvents will be ignored while incremental state is invalid. As a
- // consequence, we should also ignore any ThreadDescriptors received in this
- // state. Otherwise, any delta-encoded timestamps would be calculated
- // incorrectly once we move out of the packet loss state. Instead, wait until
- // the first subsequent descriptor after incremental state is cleared.
- if (!state->IsIncrementalStateValid()) {
- context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
- return;
- }
-
- auto thread_descriptor_field = packet_decoder.thread_descriptor();
- protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
- thread_descriptor_field.data, thread_descriptor_field.size);
-
- state->SetThreadDescriptor(
- thread_descriptor_decoder.pid(), thread_descriptor_decoder.tid(),
- thread_descriptor_decoder.reference_timestamp_us() * 1000,
- thread_descriptor_decoder.reference_thread_time_us() * 1000,
- thread_descriptor_decoder.reference_thread_instruction_count());
-
- ParseThreadDescriptor(thread_descriptor_decoder);
-}
-
-void ProtoTraceTokenizer::ParseThreadDescriptor(
- const protos::pbzero::ThreadDescriptor::Decoder&
- thread_descriptor_decoder) {
- base::StringView name;
- if (thread_descriptor_decoder.has_thread_name()) {
- name = thread_descriptor_decoder.thread_name();
- } else if (thread_descriptor_decoder.has_chrome_thread_type()) {
- using protos::pbzero::ThreadDescriptor;
- switch (thread_descriptor_decoder.chrome_thread_type()) {
- case ThreadDescriptor::CHROME_THREAD_MAIN:
- name = "CrProcessMain";
- break;
- case ThreadDescriptor::CHROME_THREAD_IO:
- name = "ChromeIOThread";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_FG_WORKER:
- name = "ThreadPoolForegroundWorker&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_BG_WORKER:
- name = "ThreadPoolBackgroundWorker&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_FB_BLOCKING:
- name = "ThreadPoolSingleThreadForegroundBlocking&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_BG_BLOCKING:
- name = "ThreadPoolSingleThreadBackgroundBlocking&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_SERVICE:
- name = "ThreadPoolService";
- break;
- case ThreadDescriptor::CHROME_THREAD_COMPOSITOR_WORKER:
- name = "CompositorTileWorker&";
- break;
- case ThreadDescriptor::CHROME_THREAD_COMPOSITOR:
- name = "Compositor";
- break;
- case ThreadDescriptor::CHROME_THREAD_VIZ_COMPOSITOR:
- name = "VizCompositorThread";
- break;
- case ThreadDescriptor::CHROME_THREAD_SERVICE_WORKER:
- name = "ServiceWorkerThread&";
- break;
- case ThreadDescriptor::CHROME_THREAD_MEMORY_INFRA:
- name = "MemoryInfra";
- break;
- case ThreadDescriptor::CHROME_THREAD_SAMPLING_PROFILER:
- name = "StackSamplingProfiler";
- break;
- case ThreadDescriptor::CHROME_THREAD_UNSPECIFIED:
- name = "ChromeUnspecified";
- break;
- }
- }
-
- if (!name.empty()) {
- auto thread_name_id = context_->storage->InternString(name);
- ProcessTracker* procs = context_->process_tracker.get();
- procs->UpdateThreadName(
- static_cast<uint32_t>(thread_descriptor_decoder.tid()), thread_name_id);
- }
-}
-
util::Status ProtoTraceTokenizer::ParseClockSnapshot(ConstBytes blob,
uint32_t seq_id) {
std::map<ClockTracker::ClockId, int64_t> clock_map;
@@ -632,124 +424,5 @@
return util::OkStatus();
}
-void ProtoTraceTokenizer::ParseTrackEventPacket(
- const protos::pbzero::TracePacket::Decoder& packet_decoder,
- TraceBlobView packet,
- int64_t packet_timestamp) {
- constexpr auto kTimestampDeltaUsFieldNumber =
- protos::pbzero::TrackEvent::kTimestampDeltaUsFieldNumber;
- constexpr auto kTimestampAbsoluteUsFieldNumber =
- protos::pbzero::TrackEvent::kTimestampAbsoluteUsFieldNumber;
- constexpr auto kThreadTimeDeltaUsFieldNumber =
- protos::pbzero::TrackEvent::kThreadTimeDeltaUsFieldNumber;
- constexpr auto kThreadTimeAbsoluteUsFieldNumber =
- protos::pbzero::TrackEvent::kThreadTimeAbsoluteUsFieldNumber;
- constexpr auto kThreadInstructionCountDeltaFieldNumber =
- protos::pbzero::TrackEvent::kThreadInstructionCountDeltaFieldNumber;
- constexpr auto kThreadInstructionCountAbsoluteFieldNumber =
- protos::pbzero::TrackEvent::kThreadInstructionCountAbsoluteFieldNumber;
-
- if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
- PERFETTO_ELOG("TrackEvent packet without trusted_packet_sequence_id");
- context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
- return;
- }
-
- auto* state = GetIncrementalStateForPacketSequence(
- packet_decoder.trusted_packet_sequence_id());
-
- // TODO(eseckler): For now, TrackEvents can only be parsed correctly while
- // incremental state for their sequence is valid, because chromium doesn't set
- // SEQ_NEEDS_INCREMENTAL_STATE yet. Remove this once it does.
- if (!state->IsIncrementalStateValid()) {
- context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
- return;
- }
-
- auto field = packet_decoder.track_event();
- ProtoDecoder event_decoder(field.data, field.size);
-
- int64_t timestamp;
- int64_t thread_timestamp = 0;
- int64_t thread_instructions = 0;
-
- // TODO(eseckler): Remove handling of timestamps relative to ThreadDescriptors
- // once all producers have switched to clock-domain timestamps (e.g.
- // TracePacket's timestamp).
-
- if (auto ts_delta_field =
- event_decoder.FindField(kTimestampDeltaUsFieldNumber)) {
- // Delta timestamps require a valid ThreadDescriptor packet since the last
- // packet loss.
- if (!state->track_event_timestamps_valid()) {
- context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
- return;
- }
- timestamp = state->IncrementAndGetTrackEventTimeNs(
- ts_delta_field.as_int64() * 1000);
-
- // Legacy TrackEvent timestamp fields are in MONOTONIC domain. Adjust to
- // trace time if we have a clock snapshot.
- auto trace_ts = context_->clock_tracker->ToTraceTime(
- protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
- if (trace_ts.has_value())
- timestamp = trace_ts.value();
- } else if (auto ts_absolute_field =
- event_decoder.FindField(kTimestampAbsoluteUsFieldNumber)) {
- // One-off absolute timestamps don't affect delta computation.
- timestamp = ts_absolute_field.as_int64() * 1000;
-
- // Legacy TrackEvent timestamp fields are in MONOTONIC domain. Adjust to
- // trace time if we have a clock snapshot.
- auto trace_ts = context_->clock_tracker->ToTraceTime(
- protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
- if (trace_ts.has_value())
- timestamp = trace_ts.value();
- } else if (packet_decoder.has_timestamp()) {
- timestamp = packet_timestamp;
- } else {
- PERFETTO_ELOG("TrackEvent without timestamp");
- context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
- return;
- }
-
- if (auto tt_delta_field =
- event_decoder.FindField(kThreadTimeDeltaUsFieldNumber)) {
- // Delta timestamps require a valid ThreadDescriptor packet since the last
- // packet loss.
- if (!state->track_event_timestamps_valid()) {
- context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
- return;
- }
- thread_timestamp = state->IncrementAndGetTrackEventThreadTimeNs(
- tt_delta_field.as_int64() * 1000);
- } else if (auto tt_absolute_field =
- event_decoder.FindField(kThreadTimeAbsoluteUsFieldNumber)) {
- // One-off absolute timestamps don't affect delta computation.
- thread_timestamp = tt_absolute_field.as_int64() * 1000;
- }
-
- if (auto ti_delta_field =
- event_decoder.FindField(kThreadInstructionCountDeltaFieldNumber)) {
- // Delta timestamps require a valid ThreadDescriptor packet since the last
- // packet loss.
- if (!state->track_event_timestamps_valid()) {
- context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
- return;
- }
- thread_instructions =
- state->IncrementAndGetTrackEventThreadInstructionCount(
- ti_delta_field.as_int64());
- } else if (auto ti_absolute_field = event_decoder.FindField(
- kThreadInstructionCountAbsoluteFieldNumber)) {
- // One-off absolute timestamps don't affect delta computation.
- thread_instructions = ti_absolute_field.as_int64();
- }
-
- context_->sorter->PushTrackEventPacket(timestamp, thread_timestamp,
- thread_instructions, state,
- std::move(packet));
-}
-
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/proto_trace_tokenizer.h b/src/trace_processor/proto_trace_tokenizer.h
index 40564f3..81d0425 100644
--- a/src/trace_processor/proto_trace_tokenizer.h
+++ b/src/trace_processor/proto_trace_tokenizer.h
@@ -23,12 +23,10 @@
#include <vector>
#include "src/trace_processor/chunked_trace_reader.h"
-#include "src/trace_processor/proto_incremental_state.h"
+#include "src/trace_processor/importers/proto/proto_incremental_state.h"
+#include "src/trace_processor/trace_blob_view.h"
#include "src/trace_processor/trace_processor_impl.h"
-#include "protos/perfetto/trace/trace_packet.pbzero.h"
-#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
-
namespace protozero {
struct ConstBytes;
}
@@ -36,8 +34,8 @@
namespace perfetto {
namespace trace_processor {
+class PacketSequenceState;
class TraceProcessorContext;
-class TraceBlobView;
class TraceSorter;
class TraceStorage;
@@ -65,17 +63,8 @@
void HandlePreviousPacketDropped(const protos::pbzero::TracePacket::Decoder&);
void ParseInternedData(const protos::pbzero::TracePacket::Decoder&,
TraceBlobView interned_data);
- void ParseTrackDescriptorPacket(const protos::pbzero::TracePacket::Decoder&);
- void ParseProcessDescriptorPacket(
- const protos::pbzero::TracePacket::Decoder&);
- void ParseThreadDescriptorPacket(const protos::pbzero::TracePacket::Decoder&);
- void ParseThreadDescriptor(const protos::pbzero::ThreadDescriptor::Decoder&);
- void ParseTrackEventPacket(const protos::pbzero::TracePacket::Decoder&,
- TraceBlobView packet,
- int64_t packet_timestamp);
-
- ProtoIncrementalState::PacketSequenceState*
- GetIncrementalStateForPacketSequence(uint32_t sequence_id) {
+ PacketSequenceState* GetIncrementalStateForPacketSequence(
+ uint32_t sequence_id) {
if (!incremental_state)
incremental_state.reset(new ProtoIncrementalState(context_));
return incremental_state->GetOrCreateStateForPacketSequence(sequence_id);
diff --git a/src/trace_processor/timestamped_trace_piece.h b/src/trace_processor/timestamped_trace_piece.h
index ac3fd26..dded81b 100644
--- a/src/trace_processor/timestamped_trace_piece.h
+++ b/src/trace_processor/timestamped_trace_piece.h
@@ -20,7 +20,7 @@
#include "perfetto/base/build_config.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/importers/fuchsia/fuchsia_provider_view.h"
-#include "src/trace_processor/proto_incremental_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/trace_blob_view.h"
#include "src/trace_processor/trace_processor_context.h"
#include "src/trace_processor/trace_storage.h"
@@ -65,11 +65,10 @@
// A TimestampedTracePiece is (usually a reference to) a piece of a trace that
// is sorted by TraceSorter.
struct TimestampedTracePiece {
- TimestampedTracePiece(
- int64_t ts,
- uint64_t idx,
- TraceBlobView tbv,
- ProtoIncrementalState::PacketSequenceState* sequence_state)
+ TimestampedTracePiece(int64_t ts,
+ uint64_t idx,
+ TraceBlobView tbv,
+ PacketSequenceState* sequence_state)
: TimestampedTracePiece(ts,
/*thread_ts=*/0,
/*thread_instructions=*/0,
@@ -120,13 +119,12 @@
/*sequence_state=*/nullptr,
InlineEvent{}) {}
- TimestampedTracePiece(
- int64_t ts,
- int64_t thread_ts,
- int64_t thread_instructions,
- uint64_t idx,
- TraceBlobView tbv,
- ProtoIncrementalState::PacketSequenceState* sequence_state)
+ TimestampedTracePiece(int64_t ts,
+ int64_t thread_ts,
+ int64_t thread_instructions,
+ uint64_t idx,
+ TraceBlobView tbv,
+ PacketSequenceState* sequence_state)
: TimestampedTracePiece(ts,
thread_ts,
thread_instructions,
@@ -148,16 +146,15 @@
/*sequence_state=*/nullptr,
inline_evt) {}
- TimestampedTracePiece(
- int64_t ts,
- int64_t thread_ts,
- int64_t thread_instructions,
- uint64_t idx,
- TraceBlobView tbv,
- std::unique_ptr<Json::Value> value,
- std::unique_ptr<FuchsiaProviderView> fpv,
- ProtoIncrementalState::PacketSequenceState* sequence_state,
- InlineEvent inline_evt)
+ TimestampedTracePiece(int64_t ts,
+ int64_t thread_ts,
+ int64_t thread_instructions,
+ uint64_t idx,
+ TraceBlobView tbv,
+ std::unique_ptr<Json::Value> value,
+ std::unique_ptr<FuchsiaProviderView> fpv,
+ PacketSequenceState* sequence_state,
+ InlineEvent inline_evt)
: json_value(std::move(value)),
fuchsia_provider_view(std::move(fpv)),
packet_sequence_state(sequence_state),
@@ -186,7 +183,7 @@
std::unique_ptr<Json::Value> json_value;
std::unique_ptr<FuchsiaProviderView> fuchsia_provider_view;
- ProtoIncrementalState::PacketSequenceState* packet_sequence_state;
+ PacketSequenceState* packet_sequence_state;
size_t packet_sequence_state_generation;
int64_t timestamp;
diff --git a/src/trace_processor/trace_sorter.h b/src/trace_processor/trace_sorter.h
index 6320fad..82f5acd 100644
--- a/src/trace_processor/trace_sorter.h
+++ b/src/trace_processor/trace_sorter.h
@@ -21,7 +21,6 @@
#include "perfetto/ext/base/circular_queue.h"
#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/proto_incremental_state.h"
#include "src/trace_processor/timestamped_trace_piece.h"
#include "src/trace_processor/trace_blob_view.h"
#include "src/trace_processor/trace_processor_context.h"
@@ -35,6 +34,7 @@
namespace trace_processor {
class FuchsiaProviderView;
+class PacketSequenceState;
// This class takes care of sorting events parsed from the trace stream in
// arbitrary order and pushing them to the next pipeline stages (parsing) in
@@ -68,7 +68,7 @@
TraceSorter(TraceProcessorContext*, int64_t window_size_ns);
inline void PushTracePacket(int64_t timestamp,
- ProtoIncrementalState::PacketSequenceState* state,
+ PacketSequenceState* state,
TraceBlobView packet) {
DCHECK_ftrace_batch_cpu(kNoBatch);
auto* queue = GetQueue(0);
@@ -124,12 +124,11 @@
TimestampedTracePiece(timestamp, packet_idx_++, inline_event));
}
- inline void PushTrackEventPacket(
- int64_t timestamp,
- int64_t thread_time,
- int64_t thread_instruction_count,
- ProtoIncrementalState::PacketSequenceState* state,
- TraceBlobView packet) {
+ inline void PushTrackEventPacket(int64_t timestamp,
+ int64_t thread_time,
+ int64_t thread_instruction_count,
+ PacketSequenceState* state,
+ TraceBlobView packet) {
auto* queue = GetQueue(0);
queue->Append(TimestampedTracePiece(timestamp, thread_time,
thread_instruction_count, packet_idx_++,