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