blob: 3b4261388049bcb8da2a9eb55ef52a4617ab5faf [file] [log] [blame]
Primiano Tuccid933d912018-09-04 09:15:07 +01001/*
2 * Copyright (C) 2018 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/proto_trace_tokenizer.h"
18
19#include <string>
20
21#include "perfetto/base/logging.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010022#include "perfetto/ext/base/utils.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010023#include "perfetto/protozero/proto_decoder.h"
24#include "perfetto/protozero/proto_utils.h"
Isabelle Taylora97c5f52018-10-23 17:36:12 +010025#include "src/trace_processor/event_tracker.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010026#include "src/trace_processor/process_tracker.h"
Primiano Tucci0e38a142019-01-07 20:51:09 +000027#include "src/trace_processor/stats.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010028#include "src/trace_processor/trace_blob_view.h"
29#include "src/trace_processor/trace_sorter.h"
Primiano Tucci0e38a142019-01-07 20:51:09 +000030#include "src/trace_processor/trace_storage.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010031
Lalit Maganti295a8612019-05-21 13:57:42 +010032#include "perfetto/config/trace_config.pbzero.h"
Primiano Tuccic1678872019-03-20 11:30:54 +000033#include "perfetto/trace/ftrace/ftrace_event.pbzero.h"
34#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
Eric Seckler684a4f72019-04-26 14:34:07 +010035#include "perfetto/trace/interned_data/interned_data.pbzero.h"
Florian Mayer5716fc12019-06-24 11:50:51 -070036#include "perfetto/trace/profiling/profile_common.pbzero.h"
Primiano Tuccic1678872019-03-20 11:30:54 +000037#include "perfetto/trace/trace.pbzero.h"
Eric Seckler684a4f72019-04-26 14:34:07 +010038#include "perfetto/trace/track_event/task_execution.pbzero.h"
39#include "perfetto/trace/track_event/thread_descriptor.pbzero.h"
40#include "perfetto/trace/track_event/track_event.pbzero.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010041
42namespace perfetto {
43namespace trace_processor {
44
45using protozero::ProtoDecoder;
Primiano Tuccid933d912018-09-04 09:15:07 +010046using protozero::proto_utils::MakeTagLengthDelimited;
47using protozero::proto_utils::MakeTagVarInt;
48using protozero::proto_utils::ParseVarInt;
49
Eric Seckler684a4f72019-04-26 14:34:07 +010050namespace {
51
52template <typename MessageType>
53void InternMessage(TraceProcessorContext* context,
54 ProtoIncrementalState::PacketSequenceState* state,
55 TraceBlobView message) {
56 constexpr auto kIidFieldNumber = MessageType::kIidFieldNumber;
57
Florian Mayer5716fc12019-06-24 11:50:51 -070058 uint64_t iid = 0;
Eric Seckler684a4f72019-04-26 14:34:07 +010059 auto message_start = message.data();
60 auto message_size = message.length();
61 protozero::ProtoDecoder decoder(message_start, message_size);
62
63 auto field = decoder.FindField(kIidFieldNumber);
64 if (PERFETTO_UNLIKELY(!field)) {
65 PERFETTO_ELOG("Interned message without interning_id");
66 context->storage->IncrementStats(stats::interned_data_tokenizer_errors);
67 return;
68 }
Florian Mayer5716fc12019-06-24 11:50:51 -070069 iid = field.as_uint64();
Eric Seckler684a4f72019-04-26 14:34:07 +010070
71 auto res = state->GetInternedDataMap<MessageType>()->emplace(
72 iid,
Eric Seckler56a007d2019-05-02 16:25:14 +010073 ProtoIncrementalState::InternedDataView<MessageType>(std::move(message)));
Eric Seckler684a4f72019-04-26 14:34:07 +010074 // If a message with this ID is already interned, its data should not have
75 // changed (this is forbidden by the InternedData proto).
76 // TODO(eseckler): This DCHECK assumes that the message is encoded the
77 // same way whenever it is re-emitted.
78 PERFETTO_DCHECK(res.second ||
79 (res.first->second.message.length() == message_size &&
80 memcmp(res.first->second.message.data(), message_start,
81 message_size) == 0));
82}
83
84} // namespace
85
Primiano Tuccid933d912018-09-04 09:15:07 +010086ProtoTraceTokenizer::ProtoTraceTokenizer(TraceProcessorContext* ctx)
Deepanjan Roy01994ca2019-04-02 11:05:34 -070087 : context_(ctx) {}
Primiano Tuccid933d912018-09-04 09:15:07 +010088ProtoTraceTokenizer::~ProtoTraceTokenizer() = default;
89
Lalit Magantid71a9452019-05-09 15:13:24 +010090util::Status ProtoTraceTokenizer::Parse(std::unique_ptr<uint8_t[]> owned_buf,
91 size_t size) {
Primiano Tuccid933d912018-09-04 09:15:07 +010092 uint8_t* data = &owned_buf[0];
93 if (!partial_buf_.empty()) {
94 // It takes ~5 bytes for a proto preamble + the varint size.
95 const size_t kHeaderBytes = 5;
96 if (PERFETTO_UNLIKELY(partial_buf_.size() < kHeaderBytes)) {
97 size_t missing_len = std::min(kHeaderBytes - partial_buf_.size(), size);
98 partial_buf_.insert(partial_buf_.end(), &data[0], &data[missing_len]);
99 if (partial_buf_.size() < kHeaderBytes)
Lalit Magantid71a9452019-05-09 15:13:24 +0100100 return util::OkStatus();
Primiano Tuccid933d912018-09-04 09:15:07 +0100101 data += missing_len;
102 size -= missing_len;
103 }
104
Primiano Tuccic1678872019-03-20 11:30:54 +0000105 // At this point we have enough data in |partial_buf_| to read at least the
Primiano Tuccid933d912018-09-04 09:15:07 +0100106 // field header and know the size of the next TracePacket.
107 constexpr uint8_t kTracePacketTag =
Primiano Tuccic1678872019-03-20 11:30:54 +0000108 MakeTagLengthDelimited(protos::pbzero::Trace::kPacketFieldNumber);
Primiano Tuccid933d912018-09-04 09:15:07 +0100109 const uint8_t* pos = &partial_buf_[0];
110 uint8_t proto_field_tag = *pos;
111 uint64_t field_size = 0;
112 const uint8_t* next = ParseVarInt(++pos, &*partial_buf_.end(), &field_size);
113 bool parse_failed = next == pos;
114 pos = next;
115 if (proto_field_tag != kTracePacketTag || field_size == 0 || parse_failed) {
Lalit Magantid71a9452019-05-09 15:13:24 +0100116 return util::ErrStatus(
117 "Failed parsing a TracePacket from the partial buffer");
Primiano Tuccid933d912018-09-04 09:15:07 +0100118 }
119
120 // At this point we know how big the TracePacket is.
121 size_t hdr_size = static_cast<size_t>(pos - &partial_buf_[0]);
122 size_t size_incl_header = static_cast<size_t>(field_size + hdr_size);
123 PERFETTO_DCHECK(size_incl_header > partial_buf_.size());
124
125 // There is a good chance that between the |partial_buf_| and the new |data|
126 // of the current call we have enough bytes to parse a TracePacket.
127 if (partial_buf_.size() + size >= size_incl_header) {
128 // Create a new buffer for the whole TracePacket and copy into that:
129 // 1) The beginning of the TracePacket (including the proto header) from
130 // the partial buffer.
131 // 2) The rest of the TracePacket from the current |data| buffer (note
132 // that we might have consumed already a few bytes form |data| earlier
133 // in this function, hence we need to keep |off| into account).
134 std::unique_ptr<uint8_t[]> buf(new uint8_t[size_incl_header]);
135 memcpy(&buf[0], partial_buf_.data(), partial_buf_.size());
136 // |size_missing| is the number of bytes for the rest of the TracePacket
137 // in |data|.
138 size_t size_missing = size_incl_header - partial_buf_.size();
139 memcpy(&buf[partial_buf_.size()], &data[0], size_missing);
140 data += size_missing;
141 size -= size_missing;
142 partial_buf_.clear();
143 uint8_t* buf_start = &buf[0]; // Note that buf is std::moved below.
Lalit Magantid71a9452019-05-09 15:13:24 +0100144 util::Status status =
145 ParseInternal(std::move(buf), buf_start, size_incl_header);
146 if (PERFETTO_UNLIKELY(!status.ok()))
147 return status;
Primiano Tuccid933d912018-09-04 09:15:07 +0100148 } else {
149 partial_buf_.insert(partial_buf_.end(), data, &data[size]);
Lalit Magantid71a9452019-05-09 15:13:24 +0100150 return util::OkStatus();
Primiano Tuccid933d912018-09-04 09:15:07 +0100151 }
152 }
Lalit Magantid71a9452019-05-09 15:13:24 +0100153 return ParseInternal(std::move(owned_buf), data, size);
Primiano Tuccid933d912018-09-04 09:15:07 +0100154}
155
Lalit Magantid71a9452019-05-09 15:13:24 +0100156util::Status ProtoTraceTokenizer::ParseInternal(
157 std::unique_ptr<uint8_t[]> owned_buf,
158 uint8_t* data,
159 size_t size) {
Primiano Tuccid933d912018-09-04 09:15:07 +0100160 PERFETTO_DCHECK(data >= &owned_buf[0]);
161 const uint8_t* start = &owned_buf[0];
162 const size_t data_off = static_cast<size_t>(data - start);
163 TraceBlobView whole_buf(std::move(owned_buf), data_off, size);
Primiano Tuccic1678872019-03-20 11:30:54 +0000164
165 protos::pbzero::Trace::Decoder decoder(data, size);
166 for (auto it = decoder.packet(); it; ++it) {
167 size_t field_offset = whole_buf.offset_of(it->data());
Lalit Magantid71a9452019-05-09 15:13:24 +0100168 util::Status status =
169 ParsePacket(whole_buf.slice(field_offset, it->size()));
170 if (PERFETTO_UNLIKELY(!status.ok()))
171 return status;
Primiano Tuccid933d912018-09-04 09:15:07 +0100172 }
173
Primiano Tuccic1678872019-03-20 11:30:54 +0000174 const size_t bytes_left = decoder.bytes_left();
175 if (bytes_left > 0) {
Primiano Tuccid933d912018-09-04 09:15:07 +0100176 PERFETTO_DCHECK(partial_buf_.empty());
Primiano Tuccic1678872019-03-20 11:30:54 +0000177 partial_buf_.insert(partial_buf_.end(), &data[decoder.read_offset()],
178 &data[decoder.read_offset() + bytes_left]);
Primiano Tuccid933d912018-09-04 09:15:07 +0100179 }
Lalit Magantid71a9452019-05-09 15:13:24 +0100180 return util::OkStatus();
Primiano Tuccid933d912018-09-04 09:15:07 +0100181}
182
Lalit Magantid71a9452019-05-09 15:13:24 +0100183util::Status ProtoTraceTokenizer::ParsePacket(TraceBlobView packet) {
Primiano Tuccic1678872019-03-20 11:30:54 +0000184 protos::pbzero::TracePacket::Decoder decoder(packet.data(), packet.length());
Lalit Maganti4b2b2532019-05-09 11:03:23 +0100185 if (PERFETTO_UNLIKELY(decoder.bytes_left()))
Lalit Magantid71a9452019-05-09 15:13:24 +0100186 return util::ErrStatus(
187 "Failed to parse proto packet fully; the trace is probably corrupt.");
Primiano Tuccid933d912018-09-04 09:15:07 +0100188
Primiano Tuccic1678872019-03-20 11:30:54 +0000189 auto timestamp = decoder.has_timestamp()
190 ? static_cast<int64_t>(decoder.timestamp())
191 : latest_timestamp_;
Lalit Magantifa21a282019-01-17 19:03:04 +0000192 latest_timestamp_ = std::max(timestamp, latest_timestamp_);
Primiano Tuccid933d912018-09-04 09:15:07 +0100193
Eric Seckler684a4f72019-04-26 14:34:07 +0100194 if (decoder.incremental_state_cleared()) {
195 HandleIncrementalStateCleared(decoder);
196 } else if (decoder.previous_packet_dropped()) {
197 HandlePreviousPacketDropped(decoder);
198 }
199
200 if (decoder.has_interned_data()) {
201 auto field = decoder.interned_data();
202 const size_t offset = packet.offset_of(field.data);
203 ParseInternedData(decoder, packet.slice(offset, field.size));
204 }
205
Primiano Tuccic1678872019-03-20 11:30:54 +0000206 if (decoder.has_ftrace_events()) {
207 auto ftrace_field = decoder.ftrace_events();
208 const size_t fld_off = packet.offset_of(ftrace_field.data);
209 ParseFtraceBundle(packet.slice(fld_off, ftrace_field.size));
Lalit Magantid71a9452019-05-09 15:13:24 +0100210 return util::OkStatus();
Primiano Tuccid933d912018-09-04 09:15:07 +0100211 }
212
Eric Seckler684a4f72019-04-26 14:34:07 +0100213 if (decoder.has_track_event()) {
214 ParseTrackEventPacket(decoder, std::move(packet));
Lalit Magantid71a9452019-05-09 15:13:24 +0100215 return util::OkStatus();
Eric Seckler684a4f72019-04-26 14:34:07 +0100216 }
217
218 if (decoder.has_thread_descriptor()) {
219 ParseThreadDescriptorPacket(decoder);
Lalit Magantid71a9452019-05-09 15:13:24 +0100220 return util::OkStatus();
Eric Seckler684a4f72019-04-26 14:34:07 +0100221 }
222
Lalit Maganti295a8612019-05-21 13:57:42 +0100223 if (decoder.has_trace_config()) {
224 auto config = decoder.trace_config();
225 protos::pbzero::TraceConfig::Decoder trace_config(config.data, config.size);
226
227 if (trace_config.write_into_file()) {
228 int64_t window_size_ns;
229 if (trace_config.has_flush_period_ms() &&
230 trace_config.flush_period_ms() > 0) {
231 // We use 2x the flush period as a margin of error to allow for any
232 // late flush responses to still be sorted correctly.
Lalit Magantib2c2f562019-05-22 18:53:46 +0100233 window_size_ns = static_cast<int64_t>(trace_config.flush_period_ms()) *
234 2 * 1000 * 1000;
Lalit Maganti295a8612019-05-21 13:57:42 +0100235 } else {
236 constexpr uint64_t kDefaultWindowNs =
237 180 * 1000 * 1000 * 1000ULL; // 3 minutes.
238 PERFETTO_ELOG(
239 "It is strongly recommended to have flush_period_ms set when "
240 "write_into_file is turned on. You will likely have many dropped "
241 "events because of inability to sort the events correctly.");
242 window_size_ns = static_cast<int64_t>(kDefaultWindowNs);
243 }
244 context_->sorter->SetWindowSizeNs(window_size_ns);
245 }
246 }
247
Florian Mayer5716fc12019-06-24 11:50:51 -0700248 auto* state = GetIncrementalStateForPacketSequence(
249 decoder.trusted_packet_sequence_id());
250
Primiano Tuccid933d912018-09-04 09:15:07 +0100251 // Use parent data and length because we want to parse this again
252 // later to get the exact type of the packet.
Florian Mayer5716fc12019-06-24 11:50:51 -0700253 context_->sorter->PushTracePacket(timestamp, state, std::move(packet));
Lalit Maganti4b2b2532019-05-09 11:03:23 +0100254
Lalit Magantid71a9452019-05-09 15:13:24 +0100255 return util::OkStatus();
Eric Seckler684a4f72019-04-26 14:34:07 +0100256}
257
258void ProtoTraceTokenizer::HandleIncrementalStateCleared(
259 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
260 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
261 PERFETTO_ELOG(
262 "incremental_state_cleared without trusted_packet_sequence_id");
263 context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
264 return;
265 }
266 GetIncrementalStateForPacketSequence(
267 packet_decoder.trusted_packet_sequence_id())
268 ->OnIncrementalStateCleared();
269}
270
271void ProtoTraceTokenizer::HandlePreviousPacketDropped(
272 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
273 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
274 PERFETTO_ELOG("previous_packet_dropped without trusted_packet_sequence_id");
275 context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
276 return;
277 }
278 GetIncrementalStateForPacketSequence(
279 packet_decoder.trusted_packet_sequence_id())
280 ->OnPacketLoss();
281}
282
283void ProtoTraceTokenizer::ParseInternedData(
284 const protos::pbzero::TracePacket::Decoder& packet_decoder,
285 TraceBlobView interned_data) {
286 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
287 PERFETTO_ELOG("InternedData packet without trusted_packet_sequence_id");
288 context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
289 return;
290 }
291
292 auto* state = GetIncrementalStateForPacketSequence(
293 packet_decoder.trusted_packet_sequence_id());
294
295 protos::pbzero::InternedData::Decoder interned_data_decoder(
296 interned_data.data(), interned_data.length());
297
298 // Store references to interned data submessages into the sequence's state.
299 for (auto it = interned_data_decoder.event_categories(); it; ++it) {
300 size_t offset = interned_data.offset_of(it->data());
301 InternMessage<protos::pbzero::EventCategory>(
302 context_, state, interned_data.slice(offset, it->size()));
303 }
304
305 for (auto it = interned_data_decoder.legacy_event_names(); it; ++it) {
306 size_t offset = interned_data.offset_of(it->data());
307 InternMessage<protos::pbzero::LegacyEventName>(
308 context_, state, interned_data.slice(offset, it->size()));
309 }
310
311 for (auto it = interned_data_decoder.debug_annotation_names(); it; ++it) {
312 size_t offset = interned_data.offset_of(it->data());
313 InternMessage<protos::pbzero::DebugAnnotationName>(
314 context_, state, interned_data.slice(offset, it->size()));
315 }
316
317 for (auto it = interned_data_decoder.source_locations(); it; ++it) {
318 size_t offset = interned_data.offset_of(it->data());
319 InternMessage<protos::pbzero::SourceLocation>(
320 context_, state, interned_data.slice(offset, it->size()));
321 }
Florian Mayer5716fc12019-06-24 11:50:51 -0700322
323 for (auto it = interned_data_decoder.build_ids(); it; ++it) {
324 size_t offset = interned_data.offset_of(it->data());
325 InternMessage<protos::pbzero::InternedString>(
326 context_, state, interned_data.slice(offset, it->size()));
327 }
328 for (auto it = interned_data_decoder.mapping_paths(); it; ++it) {
329 size_t offset = interned_data.offset_of(it->data());
330 InternMessage<protos::pbzero::InternedString>(
331 context_, state, interned_data.slice(offset, it->size()));
332 }
333 for (auto it = interned_data_decoder.function_names(); it; ++it) {
334 size_t offset = interned_data.offset_of(it->data());
335 InternMessage<protos::pbzero::InternedString>(
336 context_, state, interned_data.slice(offset, it->size()));
337 }
338
339 for (auto it = interned_data_decoder.mappings(); it; ++it) {
340 size_t offset = interned_data.offset_of(it->data());
341 InternMessage<protos::pbzero::Mapping>(
342 context_, state, interned_data.slice(offset, it->size()));
343 }
344 for (auto it = interned_data_decoder.frames(); it; ++it) {
345 size_t offset = interned_data.offset_of(it->data());
346 InternMessage<protos::pbzero::Frame>(
347 context_, state, interned_data.slice(offset, it->size()));
348 }
349 for (auto it = interned_data_decoder.callstacks(); it; ++it) {
350 size_t offset = interned_data.offset_of(it->data());
351 InternMessage<protos::pbzero::Callstack>(
352 context_, state, interned_data.slice(offset, it->size()));
353 }
Eric Seckler684a4f72019-04-26 14:34:07 +0100354}
355
356void ProtoTraceTokenizer::ParseThreadDescriptorPacket(
357 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
358 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
359 PERFETTO_ELOG("ThreadDescriptor packet without trusted_packet_sequence_id");
360 context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
361 return;
362 }
363
364 auto* state = GetIncrementalStateForPacketSequence(
365 packet_decoder.trusted_packet_sequence_id());
366
367 // TrackEvents will be ignored while incremental state is invalid. As a
368 // consequence, we should also ignore any ThreadDescriptors received in this
369 // state. Otherwise, any delta-encoded timestamps would be calculated
370 // incorrectly once we move out of the packet loss state. Instead, wait until
371 // the first subsequent descriptor after incremental state is cleared.
372 if (!state->IsIncrementalStateValid()) {
373 context_->storage->IncrementStats(
374 stats::track_event_tokenizer_skipped_packets);
375 return;
376 }
377
378 auto thread_descriptor_field = packet_decoder.thread_descriptor();
379 protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
380 thread_descriptor_field.data, thread_descriptor_field.size);
381
382 state->SetThreadDescriptor(
383 thread_descriptor_decoder.pid(), thread_descriptor_decoder.tid(),
384 thread_descriptor_decoder.reference_timestamp_us() * 1000,
385 thread_descriptor_decoder.reference_thread_time_us() * 1000);
Siddhartha Sd37e5662019-06-13 18:27:42 -0700386
387 base::StringView name;
388 if (thread_descriptor_decoder.has_thread_name()) {
389 name = thread_descriptor_decoder.thread_name();
390 } else if (thread_descriptor_decoder.has_chrome_thread_type()) {
391 using protos::pbzero::ThreadDescriptor;
392 switch (thread_descriptor_decoder.chrome_thread_type()) {
393 case ThreadDescriptor::CHROME_THREAD_MAIN:
394 name = "CrProcessMain";
395 break;
396 case ThreadDescriptor::CHROME_THREAD_IO:
397 name = "ChromeIOThread";
398 break;
399 case ThreadDescriptor::CHROME_THREAD_POOL_FG_WORKER:
400 name = "ThreadPoolForegroundWorker&";
401 break;
402 case ThreadDescriptor::CHROME_THREAD_POOL_BG_WORKER:
403 name = "ThreadPoolBackgroundWorker&";
404 break;
405 case ThreadDescriptor::CHROME_THREAD_POOL_FB_BLOCKING:
406 name = "ThreadPoolSingleThreadForegroundBlocking&";
407 break;
408 case ThreadDescriptor::CHROME_THREAD_POOL_BG_BLOCKING:
409 name = "ThreadPoolSingleThreadBackgroundBlocking&";
410 break;
411 case ThreadDescriptor::CHROME_THREAD_POOL_SERVICE:
412 name = "ThreadPoolService";
413 break;
414 case ThreadDescriptor::CHROME_THREAD_COMPOSITOR_WORKER:
415 name = "CompositorTileWorker&";
416 break;
417 case ThreadDescriptor::CHROME_THREAD_COMPOSITOR:
418 name = "Compositor";
419 break;
420 case ThreadDescriptor::CHROME_THREAD_VIZ_COMPOSITOR:
421 name = "VizCompositorThread";
422 break;
423 case ThreadDescriptor::CHROME_THREAD_SERVICE_WORKER:
424 name = "ServiceWorkerThread&";
425 break;
426 case ThreadDescriptor::CHROME_THREAD_MEMORY_INFRA:
427 name = "MemoryInfra";
428 break;
429 case ThreadDescriptor::CHROME_THREAD_SAMPLING_PROFILER:
430 name = "StackSamplingProfiler";
431 break;
432 case ThreadDescriptor::CHROME_THREAD_UNSPECIFIED:
433 name = "ChromeUnspecified";
434 break;
435 }
436 }
437
438 if (!name.empty()) {
439 auto thread_name_id = context_->storage->InternString(name);
440 ProcessTracker* procs = context_->process_tracker.get();
441 procs->UpdateThreadName(
442 static_cast<uint32_t>(thread_descriptor_decoder.tid()), thread_name_id);
443 }
Eric Seckler684a4f72019-04-26 14:34:07 +0100444}
445
446void ProtoTraceTokenizer::ParseTrackEventPacket(
447 const protos::pbzero::TracePacket::Decoder& packet_decoder,
448 TraceBlobView packet) {
449 constexpr auto kTimestampDeltaUsFieldNumber =
450 protos::pbzero::TrackEvent::kTimestampDeltaUsFieldNumber;
451 constexpr auto kTimestampAbsoluteUsFieldNumber =
452 protos::pbzero::TrackEvent::kTimestampAbsoluteUsFieldNumber;
453 constexpr auto kThreadTimeDeltaUsFieldNumber =
454 protos::pbzero::TrackEvent::kThreadTimeDeltaUsFieldNumber;
455 constexpr auto kThreadTimeAbsoluteUsFieldNumber =
456 protos::pbzero::TrackEvent::kThreadTimeAbsoluteUsFieldNumber;
457
458 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
459 PERFETTO_ELOG("TrackEvent packet without trusted_packet_sequence_id");
460 context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
461 return;
462 }
463
464 auto* state = GetIncrementalStateForPacketSequence(
465 packet_decoder.trusted_packet_sequence_id());
466
467 // TrackEvents can only be parsed correctly while incremental state for their
468 // sequence is valid and after a ThreadDescriptor has been parsed.
469 if (!state->IsTrackEventStateValid()) {
470 context_->storage->IncrementStats(
471 stats::track_event_tokenizer_skipped_packets);
472 return;
473 }
474
475 auto field = packet_decoder.track_event();
476 ProtoDecoder event_decoder(field.data, field.size);
477
478 int64_t timestamp;
479 int64_t thread_timestamp = 0;
480
481 if (auto ts_delta_field =
482 event_decoder.FindField(kTimestampDeltaUsFieldNumber)) {
483 timestamp = state->IncrementAndGetTrackEventTimeNs(
484 ts_delta_field.as_int64() * 1000);
485 } else if (auto ts_absolute_field =
486 event_decoder.FindField(kTimestampAbsoluteUsFieldNumber)) {
487 // One-off absolute timestamps don't affect delta computation.
488 timestamp = ts_absolute_field.as_int64() * 1000;
489 } else {
490 PERFETTO_ELOG("TrackEvent without timestamp");
491 context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
492 return;
493 }
494
495 if (auto tt_delta_field =
496 event_decoder.FindField(kThreadTimeDeltaUsFieldNumber)) {
497 thread_timestamp = state->IncrementAndGetTrackEventThreadTimeNs(
498 tt_delta_field.as_int64() * 1000);
499 } else if (auto tt_absolute_field =
500 event_decoder.FindField(kThreadTimeAbsoluteUsFieldNumber)) {
501 // One-off absolute timestamps don't affect delta computation.
502 thread_timestamp = tt_absolute_field.as_int64() * 1000;
503 }
504
505 context_->sorter->PushTrackEventPacket(timestamp, thread_timestamp, state,
506 std::move(packet));
Primiano Tuccid933d912018-09-04 09:15:07 +0100507}
508
509PERFETTO_ALWAYS_INLINE
510void ProtoTraceTokenizer::ParseFtraceBundle(TraceBlobView bundle) {
Primiano Tuccic1678872019-03-20 11:30:54 +0000511 protos::pbzero::FtraceEventBundle::Decoder decoder(bundle.data(),
512 bundle.length());
Primiano Tuccid933d912018-09-04 09:15:07 +0100513
Primiano Tuccic1678872019-03-20 11:30:54 +0000514 if (PERFETTO_UNLIKELY(!decoder.has_cpu())) {
515 PERFETTO_ELOG("CPU field not found in FtraceEventBundle");
Deepanjan Roy01994ca2019-04-02 11:05:34 -0700516 context_->storage->IncrementStats(stats::ftrace_bundle_tokenizer_errors);
Hector Dearman52642ce2019-03-07 15:31:11 +0000517 return;
518 }
519
Primiano Tuccic1678872019-03-20 11:30:54 +0000520 uint32_t cpu = decoder.cpu();
521 if (PERFETTO_UNLIKELY(cpu > base::kMaxCpus)) {
522 PERFETTO_ELOG("CPU larger than kMaxCpus (%u > %zu)", cpu, base::kMaxCpus);
523 return;
Primiano Tuccid933d912018-09-04 09:15:07 +0100524 }
Primiano Tuccic1678872019-03-20 11:30:54 +0000525
526 for (auto it = decoder.event(); it; ++it) {
527 size_t off = bundle.offset_of(it->data());
528 ParseFtraceEvent(cpu, bundle.slice(off, it->size()));
529 }
Deepanjan Roy01994ca2019-04-02 11:05:34 -0700530 context_->sorter->FinalizeFtraceEventBatch(cpu);
Primiano Tuccid933d912018-09-04 09:15:07 +0100531}
532
533PERFETTO_ALWAYS_INLINE
534void ProtoTraceTokenizer::ParseFtraceEvent(uint32_t cpu, TraceBlobView event) {
535 constexpr auto kTimestampFieldNumber =
Primiano Tuccic1678872019-03-20 11:30:54 +0000536 protos::pbzero::FtraceEvent::kTimestampFieldNumber;
Primiano Tuccid933d912018-09-04 09:15:07 +0100537 const uint8_t* data = event.data();
538 const size_t length = event.length();
539 ProtoDecoder decoder(data, length);
Lalit Magantifa21a282019-01-17 19:03:04 +0000540 uint64_t raw_timestamp = 0;
Primiano Tuccid933d912018-09-04 09:15:07 +0100541 bool timestamp_found = false;
542
543 // Speculate on the fact that the timestamp is often the 1st field of the
544 // event.
545 constexpr auto timestampFieldTag = MakeTagVarInt(kTimestampFieldNumber);
546 if (PERFETTO_LIKELY(length > 10 && data[0] == timestampFieldTag)) {
547 // Fastpath.
Lalit Magantifa21a282019-01-17 19:03:04 +0000548 const uint8_t* next = ParseVarInt(data + 1, data + 11, &raw_timestamp);
Primiano Tuccid933d912018-09-04 09:15:07 +0100549 timestamp_found = next != data + 1;
550 decoder.Reset(next);
551 } else {
552 // Slowpath.
Primiano Tuccic1678872019-03-20 11:30:54 +0000553 if (auto ts_field = decoder.FindField(kTimestampFieldNumber)) {
554 timestamp_found = true;
555 raw_timestamp = ts_field.as_uint64();
556 }
Primiano Tuccid933d912018-09-04 09:15:07 +0100557 }
558
559 if (PERFETTO_UNLIKELY(!timestamp_found)) {
560 PERFETTO_ELOG("Timestamp field not found in FtraceEvent");
Deepanjan Roy01994ca2019-04-02 11:05:34 -0700561 context_->storage->IncrementStats(stats::ftrace_bundle_tokenizer_errors);
Primiano Tuccid933d912018-09-04 09:15:07 +0100562 return;
563 }
564
Lalit Magantifa21a282019-01-17 19:03:04 +0000565 int64_t timestamp = static_cast<int64_t>(raw_timestamp);
566 latest_timestamp_ = std::max(timestamp, latest_timestamp_);
Primiano Tuccid933d912018-09-04 09:15:07 +0100567
568 // We don't need to parse this packet, just push it to be sorted with
569 // the timestamp.
Deepanjan Roy01994ca2019-04-02 11:05:34 -0700570 context_->sorter->PushFtraceEvent(cpu, timestamp, std::move(event));
Primiano Tuccid933d912018-09-04 09:15:07 +0100571}
572
573} // namespace trace_processor
574} // namespace perfetto