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 == internal::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::Hasher 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() ==
184 internal::TrackEventIncrementalState::kClockIdIncremental) {
185 sequence_state.most_recent_absolute_time_ns =
186 clock.timestamp() * clock.unit_multiplier_ns();
187 break;
188 }
189 }
190
191 if (packet.sequence_flags() &
192 perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
193 // Convert any existing event names and categories on the stack to
194 // non-interned strings so we can look up their names even after the
195 // incremental state is gone.
196 for (auto& frame : sequence_state.track.stack) {
197 if (frame.name_iid) {
198 frame.name = sequence_state.event_names[frame.name_iid];
199 frame.name_iid = 0u;
200 }
201 if (frame.category_iid) {
202 frame.category = sequence_state.event_categories[frame.category_iid];
203 frame.category_iid = 0u;
204 }
205 }
206 sequence_state.event_names.clear();
207 sequence_state.event_categories.clear();
208 sequence_state.debug_annotation_names.clear();
209 sequence_state.track.uuid = 0u;
210 sequence_state.track.index = 0u;
211 }
212 if (packet.has_interned_data()) {
213 perfetto::protos::pbzero::InternedData::Decoder interned_data(
214 packet.interned_data());
215 for (auto it = interned_data.event_names(); it; it++) {
216 perfetto::protos::pbzero::EventName::Decoder entry(*it);
217 sequence_state.event_names[entry.iid()] = entry.name().ToStdString();
218 }
219 for (auto it = interned_data.event_categories(); it; it++) {
220 perfetto::protos::pbzero::EventCategory::Decoder entry(*it);
221 sequence_state.event_categories[entry.iid()] = entry.name().ToStdString();
222 }
223 for (auto it = interned_data.debug_annotation_names(); it; it++) {
224 perfetto::protos::pbzero::DebugAnnotationName::Decoder entry(*it);
225 sequence_state.debug_annotation_names[entry.iid()] =
226 entry.name().ToStdString();
227 }
228 }
229 if (packet.has_trace_packet_defaults()) {
230 perfetto::protos::pbzero::TracePacketDefaults::Decoder defaults(
231 packet.trace_packet_defaults());
232 if (defaults.has_track_event_defaults()) {
233 perfetto::protos::pbzero::TrackEventDefaults::Decoder
234 track_event_defaults(defaults.track_event_defaults());
235 sequence_state.track.uuid = track_event_defaults.track_uuid();
236 if (defaults.has_timestamp_clock_id())
237 sequence_state.default_clock_id = defaults.timestamp_clock_id();
238 }
239 }
240 if (packet.has_track_descriptor()) {
241 perfetto::protos::pbzero::TrackDescriptor::Decoder track_descriptor(
242 packet.track_descriptor());
243 auto* session_state = delegate.GetSessionState();
244 auto& track = session_state->tracks[track_descriptor.uuid()];
245 if (!track.index)
246 track.index = static_cast<uint32_t>(session_state->tracks.size() + 1);
247 track.uuid = track_descriptor.uuid();
248
249 if (track_descriptor.has_name()) {
250 track.name = track_descriptor.name().ToStdString();
251 } else if (track_descriptor.has_static_name()) {
252 track.name = track_descriptor.static_name().ToStdString();
253 }
254 track.pid = 0;
255 track.tid = 0;
256 if (track_descriptor.has_process()) {
257 perfetto::protos::pbzero::ProcessDescriptor::Decoder process(
258 track_descriptor.process());
259 track.pid = process.pid();
260 if (track.name.empty())
261 track.name = process.process_name().ToStdString();
262 } else if (track_descriptor.has_thread()) {
263 perfetto::protos::pbzero::ThreadDescriptor::Decoder thread(
264 track_descriptor.thread());
265 track.pid = thread.pid();
266 track.tid = thread.tid();
267 if (track.name.empty())
268 track.name = thread.thread_name().ToStdString();
269 }
270 delegate.OnTrackUpdated(track);
271
272 // Mirror properties to the default track of the sequence. Note that
273 // this does not catch updates to the default track written through other
274 // sequences.
275 if (track.uuid == sequence_state.track.uuid) {
276 sequence_state.track.index = track.index;
277 sequence_state.track.name = track.name;
278 sequence_state.track.pid = track.pid;
279 sequence_state.track.tid = track.tid;
280 sequence_state.track.user_data = track.user_data;
281 }
282 }
283 }
284
ParsedTrackEvent(const perfetto::protos::pbzero::TrackEvent::Decoder & track_event_)285 TrackEventStateTracker::ParsedTrackEvent::ParsedTrackEvent(
286 const perfetto::protos::pbzero::TrackEvent::Decoder& track_event_)
287 : track_event(track_event_) {}
288
289 } // namespace perfetto
290