blob: 9d17b7794bc17f0a1f8801599d1f9587789f8285 [file] [log] [blame]
Eric Seckler771960c2019-10-22 15:37:12 +01001/*
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#include "src/trace_processor/importers/proto/track_event_tokenizer.h"
18
19#include "perfetto/base/logging.h"
20#include "perfetto/protozero/proto_decoder.h"
21#include "src/trace_processor/clock_tracker.h"
22#include "src/trace_processor/importers/proto/packet_sequence_state.h"
Eric Seckler137a4672019-10-24 08:51:14 +010023#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
Eric Seckler771960c2019-10-22 15:37:12 +010024#include "src/trace_processor/process_tracker.h"
Eric Seckler771960c2019-10-22 15:37:12 +010025#include "src/trace_processor/stats.h"
26#include "src/trace_processor/trace_blob_view.h"
27#include "src/trace_processor/trace_sorter.h"
28#include "src/trace_processor/trace_storage.h"
29#include "src/trace_processor/track_tracker.h"
30
31#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
Eric Secklerd2af9892019-11-01 10:10:53 +000032#include "protos/perfetto/trace/trace_packet.pbzero.h"
Eric Seckler771960c2019-10-22 15:37:12 +010033#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
34#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
35#include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
36#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
37
38namespace perfetto {
39namespace trace_processor {
40
Eric Seckler053ebaa2019-10-31 10:30:58 +000041TrackEventTokenizer::TrackEventTokenizer(TraceProcessorContext* context)
42 : context_(context),
43 process_name_ids_{{context_->storage->InternString("Unknown"),
44 context_->storage->InternString("Browser"),
45 context_->storage->InternString("Renderer"),
46 context_->storage->InternString("Utility"),
47 context_->storage->InternString("Zygote"),
48 context_->storage->InternString("SandboxHelper"),
49 context_->storage->InternString("Gpu"),
50 context_->storage->InternString("PpapiPlugin"),
51 context_->storage->InternString("PpapiBroker")}} {}
52
Eric Seckler771960c2019-10-22 15:37:12 +010053void TrackEventTokenizer::TokenizeTrackDescriptorPacket(
54 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
55 auto track_descriptor_field = packet_decoder.track_descriptor();
56 protos::pbzero::TrackDescriptor::Decoder track_descriptor_decoder(
57 track_descriptor_field.data, track_descriptor_field.size);
58
59 if (!track_descriptor_decoder.has_uuid()) {
60 PERFETTO_ELOG("TrackDescriptor packet without trusted_packet_sequence_id");
61 context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
62 return;
63 }
64
65 base::Optional<UniquePid> upid;
66 base::Optional<UniqueTid> utid;
67
68 if (track_descriptor_decoder.has_process()) {
69 auto process_descriptor_field = track_descriptor_decoder.process();
70 protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
71 process_descriptor_field.data, process_descriptor_field.size);
72
73 // TODO(eseckler): Also parse process name / type here.
74
75 upid = context_->process_tracker->GetOrCreateProcess(
76 static_cast<uint32_t>(process_descriptor_decoder.pid()));
77 }
78
79 if (track_descriptor_decoder.has_thread()) {
80 auto thread_descriptor_field = track_descriptor_decoder.thread();
81 protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
82 thread_descriptor_field.data, thread_descriptor_field.size);
83
84 TokenizeThreadDescriptor(thread_descriptor_decoder);
85 utid = context_->process_tracker->UpdateThread(
86 static_cast<uint32_t>(thread_descriptor_decoder.tid()),
87 static_cast<uint32_t>(thread_descriptor_decoder.pid()));
88 upid = *context_->storage->GetThread(*utid).upid;
89 }
90
91 StringId name_id =
92 context_->storage->InternString(track_descriptor_decoder.name());
93
94 context_->track_tracker->UpdateDescriptorTrack(
95 track_descriptor_decoder.uuid(), name_id, upid, utid);
96}
97
98void TrackEventTokenizer::TokenizeProcessDescriptorPacket(
99 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
100 protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
101 packet_decoder.process_descriptor());
102 if (!process_descriptor_decoder.has_chrome_process_type())
103 return;
Eric Seckler053ebaa2019-10-31 10:30:58 +0000104
105 auto process_type = process_descriptor_decoder.chrome_process_type();
106 size_t name_index =
107 static_cast<size_t>(process_type) < process_name_ids_.size()
108 ? static_cast<size_t>(process_type)
109 : 0u;
110 StringId name = process_name_ids_[name_index];
111
112 // Don't override system-provided names.
113 context_->process_tracker->SetProcessNameIfUnset(
114 context_->process_tracker->GetOrCreateProcess(
115 static_cast<uint32_t>(process_descriptor_decoder.pid())),
Eric Seckler771960c2019-10-22 15:37:12 +0100116 name);
117}
118
119void TrackEventTokenizer::TokenizeThreadDescriptorPacket(
120 PacketSequenceState* state,
121 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
122 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
123 PERFETTO_ELOG("ThreadDescriptor packet without trusted_packet_sequence_id");
124 context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
125 return;
126 }
127
128 // TrackEvents will be ignored while incremental state is invalid. As a
129 // consequence, we should also ignore any ThreadDescriptors received in this
130 // state. Otherwise, any delta-encoded timestamps would be calculated
131 // incorrectly once we move out of the packet loss state. Instead, wait until
132 // the first subsequent descriptor after incremental state is cleared.
133 if (!state->IsIncrementalStateValid()) {
134 context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
135 return;
136 }
137
138 auto thread_descriptor_field = packet_decoder.thread_descriptor();
139 protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
140 thread_descriptor_field.data, thread_descriptor_field.size);
141
142 state->SetThreadDescriptor(
143 thread_descriptor_decoder.pid(), thread_descriptor_decoder.tid(),
144 thread_descriptor_decoder.reference_timestamp_us() * 1000,
145 thread_descriptor_decoder.reference_thread_time_us() * 1000,
146 thread_descriptor_decoder.reference_thread_instruction_count());
147
148 TokenizeThreadDescriptor(thread_descriptor_decoder);
149}
150
151void TrackEventTokenizer::TokenizeThreadDescriptor(
152 const protos::pbzero::ThreadDescriptor::Decoder&
153 thread_descriptor_decoder) {
154 base::StringView name;
155 if (thread_descriptor_decoder.has_thread_name()) {
156 name = thread_descriptor_decoder.thread_name();
157 } else if (thread_descriptor_decoder.has_chrome_thread_type()) {
158 using protos::pbzero::ThreadDescriptor;
159 switch (thread_descriptor_decoder.chrome_thread_type()) {
160 case ThreadDescriptor::CHROME_THREAD_MAIN:
161 name = "CrProcessMain";
162 break;
163 case ThreadDescriptor::CHROME_THREAD_IO:
164 name = "ChromeIOThread";
165 break;
166 case ThreadDescriptor::CHROME_THREAD_POOL_FG_WORKER:
167 name = "ThreadPoolForegroundWorker&";
168 break;
169 case ThreadDescriptor::CHROME_THREAD_POOL_BG_WORKER:
170 name = "ThreadPoolBackgroundWorker&";
171 break;
172 case ThreadDescriptor::CHROME_THREAD_POOL_FB_BLOCKING:
173 name = "ThreadPoolSingleThreadForegroundBlocking&";
174 break;
175 case ThreadDescriptor::CHROME_THREAD_POOL_BG_BLOCKING:
176 name = "ThreadPoolSingleThreadBackgroundBlocking&";
177 break;
178 case ThreadDescriptor::CHROME_THREAD_POOL_SERVICE:
179 name = "ThreadPoolService";
180 break;
181 case ThreadDescriptor::CHROME_THREAD_COMPOSITOR_WORKER:
182 name = "CompositorTileWorker&";
183 break;
184 case ThreadDescriptor::CHROME_THREAD_COMPOSITOR:
185 name = "Compositor";
186 break;
187 case ThreadDescriptor::CHROME_THREAD_VIZ_COMPOSITOR:
188 name = "VizCompositorThread";
189 break;
190 case ThreadDescriptor::CHROME_THREAD_SERVICE_WORKER:
191 name = "ServiceWorkerThread&";
192 break;
193 case ThreadDescriptor::CHROME_THREAD_MEMORY_INFRA:
194 name = "MemoryInfra";
195 break;
196 case ThreadDescriptor::CHROME_THREAD_SAMPLING_PROFILER:
197 name = "StackSamplingProfiler";
198 break;
199 case ThreadDescriptor::CHROME_THREAD_UNSPECIFIED:
200 name = "ChromeUnspecified";
201 break;
202 }
203 }
204
205 if (!name.empty()) {
206 auto thread_name_id = context_->storage->InternString(name);
207 ProcessTracker* procs = context_->process_tracker.get();
Eric Seckler053ebaa2019-10-31 10:30:58 +0000208 // Don't override system-provided names.
209 procs->SetThreadNameIfUnset(
Eric Seckler9d48adc2019-10-24 16:57:15 +0100210 procs->UpdateThread(
211 static_cast<uint32_t>(thread_descriptor_decoder.tid()),
212 static_cast<uint32_t>(thread_descriptor_decoder.pid())),
213 thread_name_id);
Eric Seckler771960c2019-10-22 15:37:12 +0100214 }
215}
216
217void TrackEventTokenizer::TokenizeTrackEventPacket(
218 PacketSequenceState* state,
219 const protos::pbzero::TracePacket::Decoder& packet_decoder,
220 TraceBlobView* packet,
221 int64_t packet_timestamp) {
222 constexpr auto kTimestampDeltaUsFieldNumber =
223 protos::pbzero::TrackEvent::kTimestampDeltaUsFieldNumber;
224 constexpr auto kTimestampAbsoluteUsFieldNumber =
225 protos::pbzero::TrackEvent::kTimestampAbsoluteUsFieldNumber;
226 constexpr auto kThreadTimeDeltaUsFieldNumber =
227 protos::pbzero::TrackEvent::kThreadTimeDeltaUsFieldNumber;
228 constexpr auto kThreadTimeAbsoluteUsFieldNumber =
229 protos::pbzero::TrackEvent::kThreadTimeAbsoluteUsFieldNumber;
230 constexpr auto kThreadInstructionCountDeltaFieldNumber =
231 protos::pbzero::TrackEvent::kThreadInstructionCountDeltaFieldNumber;
232 constexpr auto kThreadInstructionCountAbsoluteFieldNumber =
233 protos::pbzero::TrackEvent::kThreadInstructionCountAbsoluteFieldNumber;
234
235 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
236 PERFETTO_ELOG("TrackEvent packet without trusted_packet_sequence_id");
237 context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
238 return;
239 }
240
241 // TODO(eseckler): For now, TrackEvents can only be parsed correctly while
242 // incremental state for their sequence is valid, because chromium doesn't set
243 // SEQ_NEEDS_INCREMENTAL_STATE yet. Remove this once it does.
244 if (!state->IsIncrementalStateValid()) {
245 context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
246 return;
247 }
248
249 auto field = packet_decoder.track_event();
250 protozero::ProtoDecoder event_decoder(field.data, field.size);
251
252 int64_t timestamp;
253 int64_t thread_timestamp = 0;
254 int64_t thread_instructions = 0;
255
256 // TODO(eseckler): Remove handling of timestamps relative to ThreadDescriptors
257 // once all producers have switched to clock-domain timestamps (e.g.
258 // TracePacket's timestamp).
259
260 if (auto ts_delta_field =
261 event_decoder.FindField(kTimestampDeltaUsFieldNumber)) {
262 // Delta timestamps require a valid ThreadDescriptor packet since the last
263 // packet loss.
264 if (!state->track_event_timestamps_valid()) {
265 context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
266 return;
267 }
268 timestamp = state->IncrementAndGetTrackEventTimeNs(
269 ts_delta_field.as_int64() * 1000);
270
271 // Legacy TrackEvent timestamp fields are in MONOTONIC domain. Adjust to
272 // trace time if we have a clock snapshot.
273 auto trace_ts = context_->clock_tracker->ToTraceTime(
274 protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
275 if (trace_ts.has_value())
276 timestamp = trace_ts.value();
Eric Seckler866054c2019-11-13 19:08:22 +0000277 } else if (int64_t ts_absolute_us =
278 event_decoder.FindField(kTimestampAbsoluteUsFieldNumber)
279 .as_int64()) {
Eric Seckler771960c2019-10-22 15:37:12 +0100280 // One-off absolute timestamps don't affect delta computation.
Eric Seckler866054c2019-11-13 19:08:22 +0000281 timestamp = ts_absolute_us * 1000;
Eric Seckler771960c2019-10-22 15:37:12 +0100282
283 // Legacy TrackEvent timestamp fields are in MONOTONIC domain. Adjust to
284 // trace time if we have a clock snapshot.
285 auto trace_ts = context_->clock_tracker->ToTraceTime(
286 protos::pbzero::ClockSnapshot::Clock::MONOTONIC, timestamp);
287 if (trace_ts.has_value())
288 timestamp = trace_ts.value();
Eric Seckler866054c2019-11-13 19:08:22 +0000289 } else if (packet_decoder.timestamp()) {
Eric Seckler771960c2019-10-22 15:37:12 +0100290 timestamp = packet_timestamp;
291 } else {
Eric Seckler866054c2019-11-13 19:08:22 +0000292 PERFETTO_ELOG("TrackEvent without valid timestamp");
Eric Seckler771960c2019-10-22 15:37:12 +0100293 context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
294 return;
295 }
296
297 if (auto tt_delta_field =
298 event_decoder.FindField(kThreadTimeDeltaUsFieldNumber)) {
299 // Delta timestamps require a valid ThreadDescriptor packet since the last
300 // packet loss.
301 if (!state->track_event_timestamps_valid()) {
302 context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
303 return;
304 }
305 thread_timestamp = state->IncrementAndGetTrackEventThreadTimeNs(
306 tt_delta_field.as_int64() * 1000);
307 } else if (auto tt_absolute_field =
308 event_decoder.FindField(kThreadTimeAbsoluteUsFieldNumber)) {
309 // One-off absolute timestamps don't affect delta computation.
310 thread_timestamp = tt_absolute_field.as_int64() * 1000;
311 }
312
313 if (auto ti_delta_field =
314 event_decoder.FindField(kThreadInstructionCountDeltaFieldNumber)) {
315 // Delta timestamps require a valid ThreadDescriptor packet since the last
316 // packet loss.
317 if (!state->track_event_timestamps_valid()) {
318 context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
319 return;
320 }
321 thread_instructions =
322 state->IncrementAndGetTrackEventThreadInstructionCount(
323 ti_delta_field.as_int64());
324 } else if (auto ti_absolute_field = event_decoder.FindField(
325 kThreadInstructionCountAbsoluteFieldNumber)) {
326 // One-off absolute timestamps don't affect delta computation.
327 thread_instructions = ti_absolute_field.as_int64();
328 }
329
330 context_->sorter->PushTrackEventPacket(timestamp, thread_timestamp,
331 thread_instructions, state,
332 std::move(*packet));
333}
334
335} // namespace trace_processor
336} // namespace perfetto