• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #include "perfetto/tracing/track_event_state_tracker.h"
18 
19 #include "perfetto/ext/base/hash.h"
20 #include "perfetto/tracing/internal/track_event_internal.h"
21 
22 #include "protos/perfetto/common/interceptor_descriptor.gen.h"
23 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
24 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
25 #include "protos/perfetto/trace/trace_packet.pbzero.h"
26 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
27 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
28 #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
29 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
30 #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
31 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
32 
33 namespace perfetto {
34 
35 using internal::TrackEventIncrementalState;
36 
37 TrackEventStateTracker::~TrackEventStateTracker() = default;
38 TrackEventStateTracker::Delegate::~Delegate() = default;
39 
40 // static
ProcessTracePacket(Delegate & delegate,SequenceState & sequence_state,const protos::pbzero::TracePacket_Decoder & packet)41 void TrackEventStateTracker::ProcessTracePacket(
42     Delegate& delegate,
43     SequenceState& sequence_state,
44     const protos::pbzero::TracePacket_Decoder& packet) {
45   UpdateIncrementalState(delegate, sequence_state, packet);
46 
47   if (!packet.has_track_event())
48     return;
49   perfetto::protos::pbzero::TrackEvent::Decoder track_event(
50       packet.track_event());
51 
52   auto clock_id = packet.timestamp_clock_id();
53   if (!packet.has_timestamp_clock_id())
54     clock_id = sequence_state.default_clock_id;
55   uint64_t timestamp = packet.timestamp();
56   // TODO(mohitms): Incorporate unit multiplier as well.
57   if (clock_id == TrackEventIncrementalState::kClockIdIncremental) {
58     timestamp += sequence_state.most_recent_absolute_time_ns;
59     sequence_state.most_recent_absolute_time_ns = timestamp;
60   }
61 
62   Track* track = &sequence_state.track;
63   if (track_event.has_track_uuid()) {
64     auto* session_state = delegate.GetSessionState();
65     if (!session_state)
66       return;  // Tracing must have ended.
67     track = &session_state->tracks[track_event.track_uuid()];
68   }
69 
70   // We only log the first category of each event.
71   protozero::ConstChars category{};
72   uint64_t category_iid = 0;
73   if (auto iid_it = track_event.category_iids()) {
74     category_iid = *iid_it;
75     category.data = sequence_state.event_categories[category_iid].data();
76     category.size = sequence_state.event_categories[category_iid].size();
77   } else if (auto cat_it = track_event.categories()) {
78     category.data = reinterpret_cast<const char*>(cat_it->data());
79     category.size = cat_it->size();
80   }
81 
82   protozero::ConstChars name{};
83   uint64_t name_iid = track_event.name_iid();
84   uint64_t name_hash = 0;
85   uint64_t duration = 0;
86   if (name_iid) {
87     name.data = sequence_state.event_names[name_iid].data();
88     name.size = sequence_state.event_names[name_iid].size();
89   } else if (track_event.has_name()) {
90     name.data = track_event.name().data;
91     name.size = track_event.name().size;
92   }
93 
94   if (name.data) {
95     base::Hash hash;
96     hash.Update(name.data, name.size);
97     name_hash = hash.digest();
98   }
99 
100   size_t depth = track->stack.size();
101   switch (track_event.type()) {
102     case protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN: {
103       StackFrame frame;
104       frame.timestamp = timestamp;
105       frame.name_hash = name_hash;
106       if (track_event.has_track_uuid()) {
107         frame.name = name.ToStdString();
108         frame.category = category.ToStdString();
109       } else {
110         frame.name_iid = name_iid;
111         frame.category_iid = category_iid;
112       }
113       track->stack.push_back(std::move(frame));
114       break;
115     }
116     case protos::pbzero::TrackEvent::TYPE_SLICE_END:
117       if (!track->stack.empty()) {
118         const auto& prev_frame = track->stack.back();
119         if (prev_frame.name_iid) {
120           name.data = sequence_state.event_names[prev_frame.name_iid].data();
121           name.size = sequence_state.event_names[prev_frame.name_iid].size();
122         } else {
123           name.data = prev_frame.name.data();
124           name.size = prev_frame.name.size();
125         }
126         name_hash = prev_frame.name_hash;
127         if (prev_frame.category_iid) {
128           category.data =
129               sequence_state.event_categories[prev_frame.category_iid].data();
130           category.size =
131               sequence_state.event_categories[prev_frame.category_iid].size();
132         } else {
133           category.data = prev_frame.category.data();
134           category.size = prev_frame.category.size();
135         }
136         duration = timestamp - prev_frame.timestamp;
137         depth--;
138       }
139       break;
140     case protos::pbzero::TrackEvent::TYPE_INSTANT:
141       break;
142     case protos::pbzero::TrackEvent::TYPE_COUNTER:
143     case protos::pbzero::TrackEvent::TYPE_UNSPECIFIED:
144       // TODO(skyostil): Support counters.
145       return;
146   }
147 
148   ParsedTrackEvent parsed_event{track_event};
149   parsed_event.timestamp_ns = timestamp;
150   parsed_event.duration_ns = duration;
151   parsed_event.stack_depth = depth;
152   parsed_event.category = category;
153   parsed_event.name = name;
154   parsed_event.name_hash = name_hash;
155   delegate.OnTrackEvent(*track, parsed_event);
156 
157   if (track_event.type() == protos::pbzero::TrackEvent::TYPE_SLICE_END &&
158       !track->stack.empty()) {
159     track->stack.pop_back();
160   }
161 }
162 
163 // static
UpdateIncrementalState(Delegate & delegate,SequenceState & sequence_state,const protos::pbzero::TracePacket_Decoder & packet)164 void TrackEventStateTracker::UpdateIncrementalState(
165     Delegate& delegate,
166     SequenceState& sequence_state,
167     const protos::pbzero::TracePacket_Decoder& packet) {
168 #if PERFETTO_DCHECK_IS_ON()
169   if (!sequence_state.sequence_id) {
170     sequence_state.sequence_id = packet.trusted_packet_sequence_id();
171   } else {
172     PERFETTO_DCHECK(sequence_state.sequence_id ==
173                     packet.trusted_packet_sequence_id());
174   }
175 #endif
176 
177   perfetto::protos::pbzero::ClockSnapshot::Decoder snapshot(
178       packet.clock_snapshot());
179   for (auto it = snapshot.clocks(); it; ++it) {
180     perfetto::protos::pbzero::ClockSnapshot::Clock::Decoder clock(*it);
181     // TODO(mohitms) : Handle the incremental clock other than default one.
182     if (clock.is_incremental() &&
183         clock.clock_id() == TrackEventIncrementalState::kClockIdIncremental) {
184       sequence_state.most_recent_absolute_time_ns =
185           clock.timestamp() * clock.unit_multiplier_ns();
186       break;
187     }
188   }
189 
190   if (packet.sequence_flags() &
191       perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
192     // Convert any existing event names and categories on the stack to
193     // non-interned strings so we can look up their names even after the
194     // incremental state is gone.
195     for (auto& frame : sequence_state.track.stack) {
196       if (frame.name_iid) {
197         frame.name = sequence_state.event_names[frame.name_iid];
198         frame.name_iid = 0u;
199       }
200       if (frame.category_iid) {
201         frame.category = sequence_state.event_categories[frame.category_iid];
202         frame.category_iid = 0u;
203       }
204     }
205     sequence_state.event_names.clear();
206     sequence_state.event_categories.clear();
207     sequence_state.debug_annotation_names.clear();
208     sequence_state.track.uuid = 0u;
209     sequence_state.track.index = 0u;
210   }
211   if (packet.has_interned_data()) {
212     perfetto::protos::pbzero::InternedData::Decoder interned_data(
213         packet.interned_data());
214     for (auto it = interned_data.event_names(); it; it++) {
215       perfetto::protos::pbzero::EventName::Decoder entry(*it);
216       sequence_state.event_names[entry.iid()] = entry.name().ToStdString();
217     }
218     for (auto it = interned_data.event_categories(); it; it++) {
219       perfetto::protos::pbzero::EventCategory::Decoder entry(*it);
220       sequence_state.event_categories[entry.iid()] = entry.name().ToStdString();
221     }
222     for (auto it = interned_data.debug_annotation_names(); it; it++) {
223       perfetto::protos::pbzero::DebugAnnotationName::Decoder entry(*it);
224       sequence_state.debug_annotation_names[entry.iid()] =
225           entry.name().ToStdString();
226     }
227   }
228   if (packet.has_trace_packet_defaults()) {
229     perfetto::protos::pbzero::TracePacketDefaults::Decoder defaults(
230         packet.trace_packet_defaults());
231     if (defaults.has_track_event_defaults()) {
232       perfetto::protos::pbzero::TrackEventDefaults::Decoder
233           track_event_defaults(defaults.track_event_defaults());
234       sequence_state.track.uuid = track_event_defaults.track_uuid();
235       if (defaults.has_timestamp_clock_id())
236         sequence_state.default_clock_id = defaults.timestamp_clock_id();
237     }
238   }
239   if (packet.has_track_descriptor()) {
240     perfetto::protos::pbzero::TrackDescriptor::Decoder track_descriptor(
241         packet.track_descriptor());
242     auto* session_state = delegate.GetSessionState();
243     auto& track = session_state->tracks[track_descriptor.uuid()];
244     if (!track.index)
245       track.index = static_cast<uint32_t>(session_state->tracks.size() + 1);
246     track.uuid = track_descriptor.uuid();
247 
248     track.name = track_descriptor.name().ToStdString();
249     track.pid = 0;
250     track.tid = 0;
251     if (track_descriptor.has_process()) {
252       perfetto::protos::pbzero::ProcessDescriptor::Decoder process(
253           track_descriptor.process());
254       track.pid = process.pid();
255       if (track.name.empty())
256         track.name = process.process_name().ToStdString();
257     } else if (track_descriptor.has_thread()) {
258       perfetto::protos::pbzero::ThreadDescriptor::Decoder thread(
259           track_descriptor.thread());
260       track.pid = thread.pid();
261       track.tid = thread.tid();
262       if (track.name.empty())
263         track.name = thread.thread_name().ToStdString();
264     }
265     delegate.OnTrackUpdated(track);
266 
267     // Mirror properties to the default track of the sequence. Note that
268     // this does not catch updates to the default track written through other
269     // sequences.
270     if (track.uuid == sequence_state.track.uuid) {
271       sequence_state.track.index = track.index;
272       sequence_state.track.name = track.name;
273       sequence_state.track.pid = track.pid;
274       sequence_state.track.tid = track.tid;
275       sequence_state.track.user_data = track.user_data;
276     }
277   }
278 }
279 
ParsedTrackEvent(const perfetto::protos::pbzero::TrackEvent::Decoder & track_event_)280 TrackEventStateTracker::ParsedTrackEvent::ParsedTrackEvent(
281     const perfetto::protos::pbzero::TrackEvent::Decoder& track_event_)
282     : track_event(track_event_) {}
283 
284 }  // namespace perfetto
285