Home | History | Annotate | Download | only in trace_processor
      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