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