1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SRC_TRACE_PROCESSOR_PROTO_INCREMENTAL_STATE_H_ 18 #define SRC_TRACE_PROCESSOR_PROTO_INCREMENTAL_STATE_H_ 19 20 #include <stdint.h> 21 22 #include <map> 23 #include <unordered_map> 24 25 #include "perfetto/base/optional.h" 26 #include "perfetto/protozero/proto_decoder.h" 27 #include "src/trace_processor/trace_blob_view.h" 28 #include "src/trace_processor/trace_storage.h" 29 30 #include "perfetto/trace/track_event/debug_annotation.pbzero.h" 31 #include "perfetto/trace/track_event/task_execution.pbzero.h" 32 #include "perfetto/trace/track_event/track_event.pbzero.h" 33 34 namespace perfetto { 35 namespace trace_processor { 36 37 // Specialization of member types is forbidden inside their parent class, so 38 // define the StorageReferences class outside in an internal namespace. 39 namespace proto_incremental_state_internal { 40 41 template <typename MessageType> 42 struct StorageReferences; 43 44 template <> 45 struct StorageReferences<protos::pbzero::EventCategory> { 46 StringId name_id; 47 }; 48 49 template <> 50 struct StorageReferences<protos::pbzero::LegacyEventName> { 51 StringId name_id; 52 }; 53 54 template <> 55 struct StorageReferences<protos::pbzero::DebugAnnotationName> { 56 StringId name_id; 57 }; 58 59 template <> 60 struct StorageReferences<protos::pbzero::SourceLocation> { 61 StringId file_name_id; 62 StringId function_name_id; 63 }; 64 65 } // namespace proto_incremental_state_internal 66 67 // Stores per-packet-sequence incremental state during trace parsing, such as 68 // reference timestamps for delta timestamp calculation and interned messages. 69 class ProtoIncrementalState { 70 public: 71 template <typename MessageType> 72 using StorageReferences = 73 proto_incremental_state_internal::StorageReferences<MessageType>; 74 75 // Entry in an interning index, refers to the interned message. 76 template <typename MessageType> 77 struct InternedDataView { 78 InternedDataView(TraceBlobView msg) : message(std::move(msg)) {} 79 80 typename MessageType::Decoder CreateDecoder() { 81 return typename MessageType::Decoder(message.data(), message.length()); 82 } 83 84 TraceBlobView message; 85 86 // If the data in this entry was already stored into the trace storage, this 87 // field contains message-type-specific references into the storage which 88 // can be used to look up the entry's data (e.g. indexes of interned 89 // strings). 90 base::Optional<StorageReferences<MessageType>> storage_refs; 91 }; 92 93 template <typename MessageType> 94 using InternedDataMap = 95 std::unordered_map<uint32_t, InternedDataView<MessageType>>; 96 97 class PacketSequenceState { 98 public: 99 int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) { 100 PERFETTO_DCHECK(IsTrackEventStateValid()); 101 track_event_timestamp_ns_ += delta_ns; 102 return track_event_timestamp_ns_; 103 } 104 105 int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) { 106 PERFETTO_DCHECK(IsTrackEventStateValid()); 107 track_event_thread_timestamp_ns_ += delta_ns; 108 return track_event_thread_timestamp_ns_; 109 } 110 111 void OnPacketLoss() { 112 packet_loss_ = true; 113 thread_descriptor_seen_ = false; 114 } 115 116 void OnIncrementalStateCleared() { packet_loss_ = false; } 117 118 void SetThreadDescriptor(int32_t pid, 119 int32_t tid, 120 int64_t timestamp_ns, 121 int64_t thread_timestamp_ns) { 122 thread_descriptor_seen_ = true; 123 pid_ = pid; 124 tid_ = tid; 125 track_event_timestamp_ns_ = timestamp_ns; 126 track_event_thread_timestamp_ns_ = thread_timestamp_ns; 127 } 128 129 bool IsIncrementalStateValid() const { return !packet_loss_; } 130 131 bool IsTrackEventStateValid() const { 132 return IsIncrementalStateValid() && thread_descriptor_seen_; 133 } 134 135 int32_t pid() const { return pid_; } 136 int32_t tid() const { return tid_; } 137 138 template <typename MessageType> 139 InternedDataMap<MessageType>* GetInternedDataMap(); 140 141 private: 142 // If true, incremental state on the sequence is considered invalid until we 143 // see the next packet with incremental_state_cleared. We assume that we 144 // missed some packets at the beginning of the trace. 145 bool packet_loss_ = true; 146 147 // We can only consider TrackEvent delta timestamps to be correct after we 148 // have observed a thread descriptor (since the last packet loss). 149 bool thread_descriptor_seen_ = false; 150 151 // Process/thread ID of the packet sequence. Used as default values for 152 // TrackEvents that don't specify a pid/tid override. Only valid while 153 // |seen_thread_descriptor_| is true. 154 int32_t pid_ = 0; 155 int32_t tid_ = 0; 156 157 // Current wall/thread timestamps used as reference for the next TrackEvent 158 // delta timestamp. 159 int64_t track_event_timestamp_ns_ = 0; 160 int64_t track_event_thread_timestamp_ns_ = 0; 161 162 InternedDataMap<protos::pbzero::EventCategory> event_categories_; 163 InternedDataMap<protos::pbzero::LegacyEventName> legacy_event_names_; 164 InternedDataMap<protos::pbzero::DebugAnnotationName> 165 debug_annotation_names_; 166 InternedDataMap<protos::pbzero::SourceLocation> source_locations_; 167 }; 168 169 // Returns the PacketSequenceState for the packet sequence with the given id. 170 // If this is a new sequence which we haven't tracked before, initializes and 171 // inserts a new PacketSequenceState into the state map. 172 PacketSequenceState* GetOrCreateStateForPacketSequence(uint32_t sequence_id) { 173 auto& ptr = packet_sequence_states_[sequence_id]; 174 if (!ptr) 175 ptr.reset(new PacketSequenceState()); 176 return ptr.get(); 177 } 178 179 private: 180 // Stores unique_ptrs to ensure that pointers to a PacketSequenceState remain 181 // valid even if the map rehashes. 182 std::map<uint32_t, std::unique_ptr<PacketSequenceState>> 183 packet_sequence_states_; 184 }; 185 186 template <> 187 inline ProtoIncrementalState::InternedDataMap<protos::pbzero::EventCategory>* 188 ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< 189 protos::pbzero::EventCategory>() { 190 return &event_categories_; 191 } 192 193 template <> 194 inline ProtoIncrementalState::InternedDataMap<protos::pbzero::LegacyEventName>* 195 ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< 196 protos::pbzero::LegacyEventName>() { 197 return &legacy_event_names_; 198 } 199 200 template <> 201 inline ProtoIncrementalState::InternedDataMap< 202 protos::pbzero::DebugAnnotationName>* 203 ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< 204 protos::pbzero::DebugAnnotationName>() { 205 return &debug_annotation_names_; 206 } 207 208 template <> 209 inline ProtoIncrementalState::InternedDataMap<protos::pbzero::SourceLocation>* 210 ProtoIncrementalState::PacketSequenceState::GetInternedDataMap< 211 protos::pbzero::SourceLocation>() { 212 return &source_locations_; 213 } 214 215 } // namespace trace_processor 216 } // namespace perfetto 217 218 #endif // SRC_TRACE_PROCESSOR_PROTO_INCREMENTAL_STATE_H_ 219