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_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
19 
20 #include <optional>
21 #include <unordered_map>
22 
23 #include "perfetto/trace_processor/ref_counted.h"
24 #include "perfetto/trace_processor/trace_blob_view.h"
25 #include "src/trace_processor/importers/proto/track_event_sequence_state.h"
26 #include "src/trace_processor/util/interned_message_view.h"
27 
28 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
29 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
30 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
31 
32 namespace perfetto {
33 namespace trace_processor {
34 
35 using InternedMessageMap =
36     std::unordered_map<uint64_t /*iid*/, InternedMessageView>;
37 using InternedFieldMap =
38     std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
39 
40 class TraceProcessorContext;
41 
42 class StackProfileSequenceState;
43 class ProfilePacketSequenceState;
44 class V8SequenceState;
45 
46 using CustomStateClasses = std::tuple<StackProfileSequenceState,
47                                       ProfilePacketSequenceState,
48                                       V8SequenceState>;
49 
50 // This is the public API exposed to packet tokenizers and parsers to access
51 // state attached to a packet sequence. This state evolves as packets are
52 // processed in sequence order. A packet that requires sequence state to be
53 // properly parsed should snapshot this state by taking a copy of the RefPtr to
54 // the currently active generation and passing it along with parsing specific
55 // data to the sorting stage.
56 class PacketSequenceStateGeneration : public RefCounted {
57  public:
58   // Base class to attach custom state to the sequence state. This state is keep
59   // per sequence and per incremental state interval, that is, each time
60   // incremental state is reset a new instance is created but not each time
61   // `TracePacketDefaults` are updated. Note that this means that different
62   // `PacketSequenceStateGeneration` instances might point to the same
63   // `CustomState` (because they only differ in their `TracePacketDefaults`).
64   //
65   // ATTENTION: You should not create instances of these classes yourself but
66   // use the `PacketSequenceStateGeneration::GetCustomState<>' method instead.
67   class CustomState : public RefCounted {
68    public:
69     virtual ~CustomState();
70 
71    protected:
72     template <uint32_t FieldId, typename MessageType>
LookupInternedMessage(uint64_t iid)73     typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
74       return generation_->LookupInternedMessage<FieldId, MessageType>(iid);
75     }
76 
GetInternedMessageView(uint32_t field_id,uint64_t iid)77     InternedMessageView* GetInternedMessageView(uint32_t field_id,
78                                                 uint64_t iid) {
79       return generation_->GetInternedMessageView(field_id, iid);
80     }
81 
82     template <typename T>
GetCustomState()83     std::remove_cv_t<T>* GetCustomState() {
84       return generation_->GetCustomState<T>();
85     }
86 
pid_and_tid_valid()87     bool pid_and_tid_valid() const { return generation_->pid_and_tid_valid(); }
pid()88     int32_t pid() const { return generation_->pid(); }
tid()89     int32_t tid() const { return generation_->tid(); }
90 
91    private:
92     friend PacketSequenceStateGeneration;
93     // Called when the a new generation is created as a result of
94     // `TracePacketDefaults` being updated.
set_generation(PacketSequenceStateGeneration * generation)95     void set_generation(PacketSequenceStateGeneration* generation) {
96       generation_ = generation;
97     }
98 
99     // Note: A `InternedDataTracker` instance can be linked to multiple
100     // `PacketSequenceStateGeneration` instances (when there are multiple
101     // `TracePacketDefaults` in the same interning context). `generation_` will
102     // point to the latest one. We keep this member private to prevent misuse /
103     // confusion around this fact. Instead subclasses should access the public
104     // methods of this class to get any interned data.
105     // TODO(carlscab): Given that CustomState is ref counted this pointer might
106     // become invalid. CustomState should not be ref pointed and instead be
107     // owned by the `PacketSequenceStateGeneration` instance pointed at by
108     // `generation_`.
109     PacketSequenceStateGeneration* generation_ = nullptr;
110   };
111 
112   static RefPtr<PacketSequenceStateGeneration> CreateFirst(
113       TraceProcessorContext* context);
114 
115   RefPtr<PacketSequenceStateGeneration> OnPacketLoss();
116 
117   RefPtr<PacketSequenceStateGeneration> OnIncrementalStateCleared();
118 
119   RefPtr<PacketSequenceStateGeneration> OnNewTracePacketDefaults(
120       TraceBlobView trace_packet_defaults);
121 
pid_and_tid_valid()122   bool pid_and_tid_valid() const {
123     return track_event_sequence_state_.pid_and_tid_valid();
124   }
pid()125   int32_t pid() const { return track_event_sequence_state_.pid(); }
tid()126   int32_t tid() const { return track_event_sequence_state_.tid(); }
127 
128   // Returns |nullptr| if the message with the given |iid| was not found (also
129   // records a stat in this case).
130   template <uint32_t FieldId, typename MessageType>
LookupInternedMessage(uint64_t iid)131   typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
132     auto* interned_message_view = GetInternedMessageView(FieldId, iid);
133     if (!interned_message_view)
134       return nullptr;
135 
136     return interned_message_view->template GetOrCreateDecoder<MessageType>();
137   }
138 
139   InternedMessageView* GetInternedMessageView(uint32_t field_id, uint64_t iid);
140   // Returns |nullptr| if no defaults were set.
GetTracePacketDefaultsView()141   InternedMessageView* GetTracePacketDefaultsView() {
142     if (!trace_packet_defaults_.has_value()) {
143       return nullptr;
144     }
145 
146     return &*trace_packet_defaults_;
147   }
148 
149   // Returns |nullptr| if no defaults were set.
GetTracePacketDefaults()150   protos::pbzero::TracePacketDefaults::Decoder* GetTracePacketDefaults() {
151     if (!trace_packet_defaults_.has_value()) {
152       return nullptr;
153     }
154     return trace_packet_defaults_
155         ->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
156   }
157 
158   // Returns |nullptr| if no TrackEventDefaults were set.
GetTrackEventDefaults()159   protos::pbzero::TrackEventDefaults::Decoder* GetTrackEventDefaults() {
160     auto* packet_defaults_view = GetTracePacketDefaultsView();
161     if (packet_defaults_view) {
162       auto* track_event_defaults_view =
163           packet_defaults_view
164               ->GetOrCreateSubmessageView<protos::pbzero::TracePacketDefaults,
165                                           protos::pbzero::TracePacketDefaults::
166                                               kTrackEventDefaultsFieldNumber>();
167       if (track_event_defaults_view) {
168         return track_event_defaults_view
169             ->GetOrCreateDecoder<protos::pbzero::TrackEventDefaults>();
170       }
171     }
172     return nullptr;
173   }
174 
175   // Extension point for custom incremental state. Custom state classes need to
176   // inherit from `CustomState`.
177   //
178   // A common use case for this custom state is to store cache mappings between
179   // interning ids (iid) and TraceProcessor objects (e.g. table row). When we
180   // see an iid we need to access the InternedMessageView for that iid, and
181   // possibly do some computations, the result of all of this could then be
182   // cached so that next time we encounter the same iid we could reuse this
183   // cached value. This caching is only valid until incremental state is
184   // cleared, from then on subsequent iid values on the sequence will no longer
185   // refer to the same entities as the iid values before the clear. Custom state
186   // classes no not need to explicitly handle this: they are attached to an
187   // `IncrementalState` instance, and a new one is created when the state is
188   // cleared, so iid values after the clear will be processed by a new (empty)
189   // custom state instance.
190   template <typename T>
191   std::remove_cv_t<T>* GetCustomState();
192 
IncrementAndGetTrackEventTimeNs(int64_t delta_ns)193   int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
194     return track_event_sequence_state_.IncrementAndGetTrackEventTimeNs(
195         delta_ns);
196   }
197 
IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns)198   int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
199     return track_event_sequence_state_.IncrementAndGetTrackEventThreadTimeNs(
200         delta_ns);
201   }
202 
IncrementAndGetTrackEventThreadInstructionCount(int64_t delta)203   int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
204     return track_event_sequence_state_
205         .IncrementAndGetTrackEventThreadInstructionCount(delta);
206   }
207 
track_event_timestamps_valid()208   bool track_event_timestamps_valid() const {
209     return track_event_sequence_state_.timestamps_valid();
210   }
211 
SetThreadDescriptor(const protos::pbzero::ThreadDescriptor::Decoder & descriptor)212   void SetThreadDescriptor(
213       const protos::pbzero::ThreadDescriptor::Decoder& descriptor) {
214     track_event_sequence_state_.SetThreadDescriptor(descriptor);
215   }
216 
217   // TODO(carlscab): Nobody other than `ProtoTraceReader` should care about
218   // this. Remove.
IsIncrementalStateValid()219   bool IsIncrementalStateValid() const { return is_incremental_state_valid_; }
220 
221  private:
222   friend class PacketSequenceStateBuilder;
223 
224   using CustomStateArray =
225       std::array<RefPtr<CustomState>, std::tuple_size_v<CustomStateClasses>>;
226 
227   // Helper to find the index in a tuple of a given type. Lookups are done
228   // ignoring cv qualifiers. If no index is found size of the tuple is returned.
229   //
230   // ATTENTION: Duplicate types in the tuple will trigger a compiler error.
231   template <typename Tuple, typename Type, size_t index = 0>
FindUniqueType()232   static constexpr size_t FindUniqueType() {
233     constexpr size_t kSize = std::tuple_size_v<Tuple>;
234     if constexpr (index < kSize) {
235       using TypeAtIndex = typename std::tuple_element<index, Tuple>::type;
236       if constexpr (std::is_same_v<std::remove_cv_t<Type>,
237                                    std::remove_cv_t<TypeAtIndex>>) {
238         static_assert(FindUniqueType<Tuple, Type, index + 1>() == kSize,
239                       "Duplicate types.");
240         return index;
241       } else {
242         return FindUniqueType<Tuple, Type, index + 1>();
243       }
244     } else {
245       return kSize;
246     }
247   }
248 
PacketSequenceStateGeneration(TraceProcessorContext * context,TrackEventSequenceState track_state,bool is_incremental_state_valid)249   PacketSequenceStateGeneration(TraceProcessorContext* context,
250                                 TrackEventSequenceState track_state,
251                                 bool is_incremental_state_valid)
252       : context_(context),
253         track_event_sequence_state_(std::move(track_state)),
254         is_incremental_state_valid_(is_incremental_state_valid) {}
255 
256   PacketSequenceStateGeneration(
257       TraceProcessorContext* context,
258       InternedFieldMap interned_data,
259       TrackEventSequenceState track_event_sequence_state,
260       CustomStateArray custom_state,
261       TraceBlobView trace_packet_defaults,
262       bool is_incremental_state_valid);
263 
264   // Add an interned message to this incremental state view. This can only be
265   // called by `PacketSequenceStateBuilder' (which is a friend) as packet
266   // tokenizers and parsers should never deal directly with reading interned
267   // data out of trace packets.
268   void InternMessage(uint32_t field_id, TraceBlobView message);
269 
270   TraceProcessorContext* const context_;
271   InternedFieldMap interned_data_;
272   TrackEventSequenceState track_event_sequence_state_;
273   CustomStateArray custom_state_;
274   std::optional<InternedMessageView> trace_packet_defaults_;
275   // TODO(carlscab): Should not be needed as clients of this class should not
276   // care about validity.
277   bool is_incremental_state_valid_ = true;
278 };
279 
280 template <typename T>
GetCustomState()281 std::remove_cv_t<T>* PacketSequenceStateGeneration::GetCustomState() {
282   constexpr size_t index = FindUniqueType<CustomStateClasses, T>();
283   static_assert(index < std::tuple_size_v<CustomStateClasses>, "Not found");
284   auto& ptr = custom_state_[index];
285   if (PERFETTO_UNLIKELY(ptr.get() == nullptr)) {
286     ptr.reset(new T(context_));
287     ptr->set_generation(this);
288   }
289 
290   return static_cast<std::remove_cv_t<T>*>(ptr.get());
291 }
292 
293 }  // namespace trace_processor
294 }  // namespace perfetto
295 
296 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
297