/* * 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 <map> #include <unordered_map> #include "perfetto/base/optional.h" #include "perfetto/protozero/proto_decoder.h" #include "src/trace_processor/trace_blob_view.h" #include "src/trace_processor/trace_storage.h" #include "perfetto/trace/track_event/debug_annotation.pbzero.h" #include "perfetto/trace/track_event/task_execution.pbzero.h" #include "perfetto/trace/track_event/track_event.pbzero.h" namespace perfetto { namespace trace_processor { // Specialization of member types is forbidden inside their parent class, so // define the StorageReferences class outside in an internal namespace. namespace proto_incremental_state_internal { template <typename MessageType> struct StorageReferences; template <> struct StorageReferences<protos::pbzero::EventCategory> { StringId name_id; }; template <> struct StorageReferences<protos::pbzero::LegacyEventName> { StringId name_id; }; template <> struct StorageReferences<protos::pbzero::DebugAnnotationName> { StringId name_id; }; template <> struct StorageReferences<protos::pbzero::SourceLocation> { StringId file_name_id; StringId function_name_id; }; } // namespace proto_incremental_state_internal // Stores per-packet-sequence incremental state during trace parsing, such as // reference timestamps for delta timestamp calculation and interned messages. class ProtoIncrementalState { public: template <typename MessageType> using StorageReferences = proto_incremental_state_internal::StorageReferences<MessageType>; // Entry in an interning index, refers to the interned message. template <typename MessageType> struct InternedDataView { InternedDataView(TraceBlobView msg) : message(std::move(msg)) {} typename MessageType::Decoder CreateDecoder() { return typename MessageType::Decoder(message.data(), message.length()); } TraceBlobView message; // If the data in this entry was already stored into the trace storage, this // field contains message-type-specific references into the storage which // can be used to look up the entry's data (e.g. indexes of interned // strings). base::Optional<StorageReferences<MessageType>> storage_refs; }; template <typename MessageType> using InternedDataMap = std::unordered_map<uint32_t, InternedDataView<MessageType>>; class PacketSequenceState { public: int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) { PERFETTO_DCHECK(IsTrackEventStateValid()); track_event_timestamp_ns_ += delta_ns; return track_event_timestamp_ns_; } int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) { PERFETTO_DCHECK(IsTrackEventStateValid()); track_event_thread_timestamp_ns_ += delta_ns; return track_event_thread_timestamp_ns_; } void OnPacketLoss() { packet_loss_ = true; thread_descriptor_seen_ = false; } void OnIncrementalStateCleared() { packet_loss_ = false; } void SetThreadDescriptor(int32_t pid, int32_t tid, int64_t timestamp_ns, int64_t thread_timestamp_ns) { thread_descriptor_seen_ = true; pid_ = pid; tid_ = tid; track_event_timestamp_ns_ = timestamp_ns; track_event_thread_timestamp_ns_ = thread_timestamp_ns; } bool IsIncrementalStateValid() const { return !packet_loss_; } bool IsTrackEventStateValid() const { return IsIncrementalStateValid() && thread_descriptor_seen_; } int32_t pid() const { return pid_; } int32_t tid() const { return tid_; } template <typename MessageType> InternedDataMap<MessageType>* GetInternedDataMap(); private: // 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 thread_descriptor_seen_ = false; // Process/thread ID of the packet sequence. Used as default values for // TrackEvents that don't specify a pid/tid override. Only valid while // |seen_thread_descriptor_| is true. int32_t pid_ = 0; int32_t tid_ = 0; // Current wall/thread timestamps used as reference for the next TrackEvent // delta timestamp. int64_t track_event_timestamp_ns_ = 0; int64_t track_event_thread_timestamp_ns_ = 0; InternedDataMap<protos::pbzero::EventCategory> event_categories_; InternedDataMap<protos::pbzero::LegacyEventName> legacy_event_names_; InternedDataMap<protos::pbzero::DebugAnnotationName> debug_annotation_names_; InternedDataMap<protos::pbzero::SourceLocation> source_locations_; }; // 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()); 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_; }; template <> inline ProtoIncrementalState::InternedDataMap<protos::pbzero::EventCategory>* ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< protos::pbzero::EventCategory>() { return &event_categories_; } template <> inline ProtoIncrementalState::InternedDataMap<protos::pbzero::LegacyEventName>* ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< protos::pbzero::LegacyEventName>() { return &legacy_event_names_; } template <> inline ProtoIncrementalState::InternedDataMap< protos::pbzero::DebugAnnotationName>* ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< protos::pbzero::DebugAnnotationName>() { return &debug_annotation_names_; } template <> inline ProtoIncrementalState::InternedDataMap<protos::pbzero::SourceLocation>* ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< protos::pbzero::SourceLocation>() { return &source_locations_; } } // namespace trace_processor } // namespace perfetto #endif // SRC_TRACE_PROCESSOR_PROTO_INCREMENTAL_STATE_H_