| /* | 
 |  * Copyright (C) 2020 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include "perfetto/tracing/track_event_state_tracker.h" | 
 |  | 
 | #include "perfetto/ext/base/hash.h" | 
 | #include "perfetto/tracing/internal/track_event_internal.h" | 
 |  | 
 | #include "protos/perfetto/common/interceptor_descriptor.gen.h" | 
 | #include "protos/perfetto/trace/clock_snapshot.pbzero.h" | 
 | #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h" | 
 | #include "protos/perfetto/trace/trace_packet.pbzero.h" | 
 | #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h" | 
 | #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h" | 
 | #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h" | 
 | #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h" | 
 | #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h" | 
 | #include "protos/perfetto/trace/track_event/track_event.pbzero.h" | 
 |  | 
 | namespace perfetto { | 
 |  | 
 | using internal::TrackEventIncrementalState; | 
 |  | 
 | TrackEventStateTracker::~TrackEventStateTracker() = default; | 
 | TrackEventStateTracker::Delegate::~Delegate() = default; | 
 |  | 
 | // static | 
 | void TrackEventStateTracker::ProcessTracePacket( | 
 |     Delegate& delegate, | 
 |     SequenceState& sequence_state, | 
 |     const protos::pbzero::TracePacket_Decoder& packet) { | 
 |   UpdateIncrementalState(delegate, sequence_state, packet); | 
 |  | 
 |   if (!packet.has_track_event()) | 
 |     return; | 
 |   perfetto::protos::pbzero::TrackEvent::Decoder track_event( | 
 |       packet.track_event()); | 
 |  | 
 |   auto clock_id = packet.timestamp_clock_id(); | 
 |   if (!packet.has_timestamp_clock_id()) | 
 |     clock_id = sequence_state.default_clock_id; | 
 |   uint64_t timestamp = packet.timestamp(); | 
 |   // TODO(mohitms): Incorporate unit multiplier as well. | 
 |   if (clock_id == internal::TrackEventIncrementalState::kClockIdIncremental) { | 
 |     timestamp += sequence_state.most_recent_absolute_time_ns; | 
 |     sequence_state.most_recent_absolute_time_ns = timestamp; | 
 |   } | 
 |  | 
 |   Track* track = &sequence_state.track; | 
 |   if (track_event.has_track_uuid()) { | 
 |     auto* session_state = delegate.GetSessionState(); | 
 |     if (!session_state) | 
 |       return;  // Tracing must have ended. | 
 |     track = &session_state->tracks[track_event.track_uuid()]; | 
 |   } | 
 |  | 
 |   // We only log the first category of each event. | 
 |   protozero::ConstChars category{}; | 
 |   uint64_t category_iid = 0; | 
 |   if (auto iid_it = track_event.category_iids()) { | 
 |     category_iid = *iid_it; | 
 |     category.data = sequence_state.event_categories[category_iid].data(); | 
 |     category.size = sequence_state.event_categories[category_iid].size(); | 
 |   } else if (auto cat_it = track_event.categories()) { | 
 |     category.data = reinterpret_cast<const char*>(cat_it->data()); | 
 |     category.size = cat_it->size(); | 
 |   } | 
 |  | 
 |   protozero::ConstChars name{}; | 
 |   uint64_t name_iid = track_event.name_iid(); | 
 |   uint64_t name_hash = 0; | 
 |   uint64_t duration = 0; | 
 |   if (name_iid) { | 
 |     name.data = sequence_state.event_names[name_iid].data(); | 
 |     name.size = sequence_state.event_names[name_iid].size(); | 
 |   } else if (track_event.has_name()) { | 
 |     name.data = track_event.name().data; | 
 |     name.size = track_event.name().size; | 
 |   } | 
 |  | 
 |   if (name.data) { | 
 |     base::Hasher hash; | 
 |     hash.Update(name.data, name.size); | 
 |     name_hash = hash.digest(); | 
 |   } | 
 |  | 
 |   size_t depth = track->stack.size(); | 
 |   switch (track_event.type()) { | 
 |     case protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN: { | 
 |       StackFrame frame; | 
 |       frame.timestamp = timestamp; | 
 |       frame.name_hash = name_hash; | 
 |       if (track_event.has_track_uuid()) { | 
 |         frame.name = name.ToStdString(); | 
 |         frame.category = category.ToStdString(); | 
 |       } else { | 
 |         frame.name_iid = name_iid; | 
 |         frame.category_iid = category_iid; | 
 |       } | 
 |       track->stack.push_back(std::move(frame)); | 
 |       break; | 
 |     } | 
 |     case protos::pbzero::TrackEvent::TYPE_SLICE_END: | 
 |       if (!track->stack.empty()) { | 
 |         const auto& prev_frame = track->stack.back(); | 
 |         if (prev_frame.name_iid) { | 
 |           name.data = sequence_state.event_names[prev_frame.name_iid].data(); | 
 |           name.size = sequence_state.event_names[prev_frame.name_iid].size(); | 
 |         } else { | 
 |           name.data = prev_frame.name.data(); | 
 |           name.size = prev_frame.name.size(); | 
 |         } | 
 |         name_hash = prev_frame.name_hash; | 
 |         if (prev_frame.category_iid) { | 
 |           category.data = | 
 |               sequence_state.event_categories[prev_frame.category_iid].data(); | 
 |           category.size = | 
 |               sequence_state.event_categories[prev_frame.category_iid].size(); | 
 |         } else { | 
 |           category.data = prev_frame.category.data(); | 
 |           category.size = prev_frame.category.size(); | 
 |         } | 
 |         duration = timestamp - prev_frame.timestamp; | 
 |         depth--; | 
 |       } | 
 |       break; | 
 |     case protos::pbzero::TrackEvent::TYPE_INSTANT: | 
 |       break; | 
 |     case protos::pbzero::TrackEvent::TYPE_COUNTER: | 
 |     case protos::pbzero::TrackEvent::TYPE_UNSPECIFIED: | 
 |       // TODO(skyostil): Support counters. | 
 |       return; | 
 |   } | 
 |  | 
 |   ParsedTrackEvent parsed_event{track_event}; | 
 |   parsed_event.timestamp_ns = timestamp; | 
 |   parsed_event.duration_ns = duration; | 
 |   parsed_event.stack_depth = depth; | 
 |   parsed_event.category = category; | 
 |   parsed_event.name = name; | 
 |   parsed_event.name_hash = name_hash; | 
 |   delegate.OnTrackEvent(*track, parsed_event); | 
 |  | 
 |   if (track_event.type() == protos::pbzero::TrackEvent::TYPE_SLICE_END && | 
 |       !track->stack.empty()) { | 
 |     track->stack.pop_back(); | 
 |   } | 
 | } | 
 |  | 
 | // static | 
 | void TrackEventStateTracker::UpdateIncrementalState( | 
 |     Delegate& delegate, | 
 |     SequenceState& sequence_state, | 
 |     const protos::pbzero::TracePacket_Decoder& packet) { | 
 | #if PERFETTO_DCHECK_IS_ON() | 
 |   if (!sequence_state.sequence_id) { | 
 |     sequence_state.sequence_id = packet.trusted_packet_sequence_id(); | 
 |   } else { | 
 |     PERFETTO_DCHECK(sequence_state.sequence_id == | 
 |                     packet.trusted_packet_sequence_id()); | 
 |   } | 
 | #endif | 
 |  | 
 |   perfetto::protos::pbzero::ClockSnapshot::Decoder snapshot( | 
 |       packet.clock_snapshot()); | 
 |   for (auto it = snapshot.clocks(); it; ++it) { | 
 |     perfetto::protos::pbzero::ClockSnapshot::Clock::Decoder clock(*it); | 
 |     // TODO(mohitms) : Handle the incremental clock other than default one. | 
 |     if (clock.is_incremental() && | 
 |         clock.clock_id() == | 
 |             internal::TrackEventIncrementalState::kClockIdIncremental) { | 
 |       sequence_state.most_recent_absolute_time_ns = | 
 |           clock.timestamp() * clock.unit_multiplier_ns(); | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   if (packet.sequence_flags() & | 
 |       perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) { | 
 |     // Convert any existing event names and categories on the stack to | 
 |     // non-interned strings so we can look up their names even after the | 
 |     // incremental state is gone. | 
 |     for (auto& frame : sequence_state.track.stack) { | 
 |       if (frame.name_iid) { | 
 |         frame.name = sequence_state.event_names[frame.name_iid]; | 
 |         frame.name_iid = 0u; | 
 |       } | 
 |       if (frame.category_iid) { | 
 |         frame.category = sequence_state.event_categories[frame.category_iid]; | 
 |         frame.category_iid = 0u; | 
 |       } | 
 |     } | 
 |     sequence_state.event_names.clear(); | 
 |     sequence_state.event_categories.clear(); | 
 |     sequence_state.debug_annotation_names.clear(); | 
 |     sequence_state.track.uuid = 0u; | 
 |     sequence_state.track.index = 0u; | 
 |   } | 
 |   if (packet.has_interned_data()) { | 
 |     perfetto::protos::pbzero::InternedData::Decoder interned_data( | 
 |         packet.interned_data()); | 
 |     for (auto it = interned_data.event_names(); it; it++) { | 
 |       perfetto::protos::pbzero::EventName::Decoder entry(*it); | 
 |       sequence_state.event_names[entry.iid()] = entry.name().ToStdString(); | 
 |     } | 
 |     for (auto it = interned_data.event_categories(); it; it++) { | 
 |       perfetto::protos::pbzero::EventCategory::Decoder entry(*it); | 
 |       sequence_state.event_categories[entry.iid()] = entry.name().ToStdString(); | 
 |     } | 
 |     for (auto it = interned_data.debug_annotation_names(); it; it++) { | 
 |       perfetto::protos::pbzero::DebugAnnotationName::Decoder entry(*it); | 
 |       sequence_state.debug_annotation_names[entry.iid()] = | 
 |           entry.name().ToStdString(); | 
 |     } | 
 |   } | 
 |   if (packet.has_trace_packet_defaults()) { | 
 |     perfetto::protos::pbzero::TracePacketDefaults::Decoder defaults( | 
 |         packet.trace_packet_defaults()); | 
 |     if (defaults.has_track_event_defaults()) { | 
 |       perfetto::protos::pbzero::TrackEventDefaults::Decoder | 
 |           track_event_defaults(defaults.track_event_defaults()); | 
 |       sequence_state.track.uuid = track_event_defaults.track_uuid(); | 
 |       if (defaults.has_timestamp_clock_id()) | 
 |         sequence_state.default_clock_id = defaults.timestamp_clock_id(); | 
 |     } | 
 |   } | 
 |   if (packet.has_track_descriptor()) { | 
 |     perfetto::protos::pbzero::TrackDescriptor::Decoder track_descriptor( | 
 |         packet.track_descriptor()); | 
 |     auto* session_state = delegate.GetSessionState(); | 
 |     auto& track = session_state->tracks[track_descriptor.uuid()]; | 
 |     if (!track.index) | 
 |       track.index = static_cast<uint32_t>(session_state->tracks.size() + 1); | 
 |     track.uuid = track_descriptor.uuid(); | 
 |  | 
 |     track.name = track_descriptor.name().ToStdString(); | 
 |     track.pid = 0; | 
 |     track.tid = 0; | 
 |     if (track_descriptor.has_process()) { | 
 |       perfetto::protos::pbzero::ProcessDescriptor::Decoder process( | 
 |           track_descriptor.process()); | 
 |       track.pid = process.pid(); | 
 |       if (track.name.empty()) | 
 |         track.name = process.process_name().ToStdString(); | 
 |     } else if (track_descriptor.has_thread()) { | 
 |       perfetto::protos::pbzero::ThreadDescriptor::Decoder thread( | 
 |           track_descriptor.thread()); | 
 |       track.pid = thread.pid(); | 
 |       track.tid = thread.tid(); | 
 |       if (track.name.empty()) | 
 |         track.name = thread.thread_name().ToStdString(); | 
 |     } | 
 |     delegate.OnTrackUpdated(track); | 
 |  | 
 |     // Mirror properties to the default track of the sequence. Note that | 
 |     // this does not catch updates to the default track written through other | 
 |     // sequences. | 
 |     if (track.uuid == sequence_state.track.uuid) { | 
 |       sequence_state.track.index = track.index; | 
 |       sequence_state.track.name = track.name; | 
 |       sequence_state.track.pid = track.pid; | 
 |       sequence_state.track.tid = track.tid; | 
 |       sequence_state.track.user_data = track.user_data; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | TrackEventStateTracker::ParsedTrackEvent::ParsedTrackEvent( | 
 |     const perfetto::protos::pbzero::TrackEvent::Decoder& track_event_) | 
 |     : track_event(track_event_) {} | 
 |  | 
 | }  // namespace perfetto |