blob: b33379f655bc4fa88a033f442d672b4f2383c51c [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
Eric Seckler137a4672019-10-24 08:51:14 +010017#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010018
19#include <string>
20
Primiano Tucci1b5fdae2020-01-16 09:28:05 +000021#include "perfetto/base/build_config.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010022#include "perfetto/base/logging.h"
Hector Dearman33610d22019-08-07 13:00:20 +010023#include "perfetto/ext/base/optional.h"
ssid1ffe2252019-10-02 13:27:21 -070024#include "perfetto/ext/base/string_view.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010025#include "perfetto/ext/base/utils.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010026#include "perfetto/protozero/proto_decoder.h"
27#include "perfetto/protozero/proto_utils.h"
ssid1ffe2252019-10-02 13:27:21 -070028#include "perfetto/trace_processor/status.h"
Lalit Magantid5c45f42020-04-14 21:01:50 +010029#include "src/trace_processor/importers/common/clock_tracker.h"
30#include "src/trace_processor/importers/common/event_tracker.h"
Lalit Maganti617deae2020-04-14 21:00:49 +010031#include "src/trace_processor/importers/common/track_tracker.h"
Eric Seckleracfe35b2019-10-18 15:50:17 +010032#include "src/trace_processor/importers/ftrace/ftrace_module.h"
Lalit Maganti9d538bd2020-03-12 23:48:16 +000033#include "src/trace_processor/importers/gzip/gzip_utils.h"
Andrew Shulaev46b12a92020-07-09 00:45:37 +010034#include "src/trace_processor/importers/proto/args_table_utils.h"
Eric Seckler771960c2019-10-22 15:37:12 +010035#include "src/trace_processor/importers/proto/packet_sequence_state.h"
36#include "src/trace_processor/importers/proto/proto_incremental_state.h"
Lalit Maganti7010b332020-02-07 10:51:15 +000037#include "src/trace_processor/storage/stats.h"
38#include "src/trace_processor/storage/trace_storage.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010039#include "src/trace_processor/trace_sorter.h"
40
Eric Secklerdc454522020-05-20 19:40:23 +010041#include "protos/perfetto/common/builtin_clock.pbzero.h"
Primiano Tucci355b8c82019-08-29 08:37:51 +020042#include "protos/perfetto/config/trace_config.pbzero.h"
43#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
Andrew Shulaev46b12a92020-07-09 00:45:37 +010044#include "protos/perfetto/trace/extension_descriptor.pbzero.h"
Primiano Tucci355b8c82019-08-29 08:37:51 +020045#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
46#include "protos/perfetto/trace/trace.pbzero.h"
Eric Secklerd2af9892019-11-01 10:10:53 +000047#include "protos/perfetto/trace/trace_packet.pbzero.h"
Primiano Tuccid933d912018-09-04 09:15:07 +010048
49namespace perfetto {
50namespace trace_processor {
51
Primiano Tuccid933d912018-09-04 09:15:07 +010052using protozero::proto_utils::MakeTagLengthDelimited;
Primiano Tuccid933d912018-09-04 09:15:07 +010053using protozero::proto_utils::ParseVarInt;
54
Eric Seckler684a4f72019-04-26 14:34:07 +010055namespace {
56
Hector Dearman33610d22019-08-07 13:00:20 +010057constexpr uint8_t kTracePacketTag =
58 MakeTagLengthDelimited(protos::pbzero::Trace::kPacketFieldNumber);
59
Lalit Maganti9d538bd2020-03-12 23:48:16 +000060TraceBlobView Decompress(GzipDecompressor* decompressor, TraceBlobView input) {
Lalit Maganti0bfeb972020-03-14 03:57:30 +000061 PERFETTO_DCHECK(gzip::IsGzipSupported());
Lalit Maganti9d538bd2020-03-12 23:48:16 +000062
Hector Dearman33610d22019-08-07 13:00:20 +010063 uint8_t out[4096];
Hector Dearman33610d22019-08-07 13:00:20 +010064
Lalit Maganti9d538bd2020-03-12 23:48:16 +000065 std::vector<uint8_t> data;
66 data.reserve(input.length());
Hector Dearman33610d22019-08-07 13:00:20 +010067
Lalit Maganti9d538bd2020-03-12 23:48:16 +000068 // Ensure that the decompressor is able to cope with a new stream of data.
69 decompressor->Reset();
70 decompressor->SetInput(input.data(), input.length());
Hector Dearman33610d22019-08-07 13:00:20 +010071
Lalit Maganti9d538bd2020-03-12 23:48:16 +000072 using ResultCode = GzipDecompressor::ResultCode;
73 for (auto ret = ResultCode::kOk; ret != ResultCode::kEof;) {
74 auto res = decompressor->Decompress(out, base::ArraySize(out));
75 ret = res.ret;
76 if (ret == ResultCode::kError || ret == ResultCode::kNoProgress ||
77 ret == ResultCode::kNeedsMoreInput)
Hector Dearman33610d22019-08-07 13:00:20 +010078 return TraceBlobView(nullptr, 0, 0);
Hector Dearman33610d22019-08-07 13:00:20 +010079
Lalit Maganti9d538bd2020-03-12 23:48:16 +000080 data.insert(data.end(), out, out + res.bytes_written);
81 }
82
83 std::unique_ptr<uint8_t[]> output(new uint8_t[data.size()]);
84 memcpy(output.get(), data.data(), data.size());
85 return TraceBlobView(std::move(output), 0, data.size());
Hector Dearman33610d22019-08-07 13:00:20 +010086}
87
Eric Seckler684a4f72019-04-26 14:34:07 +010088} // namespace
89
Primiano Tuccid933d912018-09-04 09:15:07 +010090ProtoTraceTokenizer::ProtoTraceTokenizer(TraceProcessorContext* ctx)
Deepanjan Roy01994ca2019-04-02 11:05:34 -070091 : context_(ctx) {}
Primiano Tuccid933d912018-09-04 09:15:07 +010092ProtoTraceTokenizer::~ProtoTraceTokenizer() = default;
93
Lalit Magantid71a9452019-05-09 15:13:24 +010094util::Status ProtoTraceTokenizer::Parse(std::unique_ptr<uint8_t[]> owned_buf,
95 size_t size) {
Primiano Tuccid933d912018-09-04 09:15:07 +010096 uint8_t* data = &owned_buf[0];
97 if (!partial_buf_.empty()) {
98 // It takes ~5 bytes for a proto preamble + the varint size.
99 const size_t kHeaderBytes = 5;
100 if (PERFETTO_UNLIKELY(partial_buf_.size() < kHeaderBytes)) {
101 size_t missing_len = std::min(kHeaderBytes - partial_buf_.size(), size);
102 partial_buf_.insert(partial_buf_.end(), &data[0], &data[missing_len]);
103 if (partial_buf_.size() < kHeaderBytes)
Lalit Magantid71a9452019-05-09 15:13:24 +0100104 return util::OkStatus();
Primiano Tuccid933d912018-09-04 09:15:07 +0100105 data += missing_len;
106 size -= missing_len;
107 }
108
Primiano Tuccic1678872019-03-20 11:30:54 +0000109 // At this point we have enough data in |partial_buf_| to read at least the
Primiano Tuccid933d912018-09-04 09:15:07 +0100110 // field header and know the size of the next TracePacket.
Primiano Tuccid933d912018-09-04 09:15:07 +0100111 const uint8_t* pos = &partial_buf_[0];
112 uint8_t proto_field_tag = *pos;
113 uint64_t field_size = 0;
114 const uint8_t* next = ParseVarInt(++pos, &*partial_buf_.end(), &field_size);
115 bool parse_failed = next == pos;
116 pos = next;
117 if (proto_field_tag != kTracePacketTag || field_size == 0 || parse_failed) {
Lalit Magantid71a9452019-05-09 15:13:24 +0100118 return util::ErrStatus(
119 "Failed parsing a TracePacket from the partial buffer");
Primiano Tuccid933d912018-09-04 09:15:07 +0100120 }
121
122 // At this point we know how big the TracePacket is.
123 size_t hdr_size = static_cast<size_t>(pos - &partial_buf_[0]);
124 size_t size_incl_header = static_cast<size_t>(field_size + hdr_size);
125 PERFETTO_DCHECK(size_incl_header > partial_buf_.size());
126
127 // There is a good chance that between the |partial_buf_| and the new |data|
128 // of the current call we have enough bytes to parse a TracePacket.
129 if (partial_buf_.size() + size >= size_incl_header) {
130 // Create a new buffer for the whole TracePacket and copy into that:
131 // 1) The beginning of the TracePacket (including the proto header) from
132 // the partial buffer.
133 // 2) The rest of the TracePacket from the current |data| buffer (note
134 // that we might have consumed already a few bytes form |data| earlier
135 // in this function, hence we need to keep |off| into account).
136 std::unique_ptr<uint8_t[]> buf(new uint8_t[size_incl_header]);
137 memcpy(&buf[0], partial_buf_.data(), partial_buf_.size());
138 // |size_missing| is the number of bytes for the rest of the TracePacket
139 // in |data|.
140 size_t size_missing = size_incl_header - partial_buf_.size();
141 memcpy(&buf[partial_buf_.size()], &data[0], size_missing);
142 data += size_missing;
143 size -= size_missing;
144 partial_buf_.clear();
145 uint8_t* buf_start = &buf[0]; // Note that buf is std::moved below.
Lalit Magantid71a9452019-05-09 15:13:24 +0100146 util::Status status =
147 ParseInternal(std::move(buf), buf_start, size_incl_header);
148 if (PERFETTO_UNLIKELY(!status.ok()))
149 return status;
Primiano Tuccid933d912018-09-04 09:15:07 +0100150 } else {
151 partial_buf_.insert(partial_buf_.end(), data, &data[size]);
Lalit Magantid71a9452019-05-09 15:13:24 +0100152 return util::OkStatus();
Primiano Tuccid933d912018-09-04 09:15:07 +0100153 }
154 }
Lalit Magantid71a9452019-05-09 15:13:24 +0100155 return ParseInternal(std::move(owned_buf), data, size);
Primiano Tuccid933d912018-09-04 09:15:07 +0100156}
157
Lalit Magantid71a9452019-05-09 15:13:24 +0100158util::Status ProtoTraceTokenizer::ParseInternal(
159 std::unique_ptr<uint8_t[]> owned_buf,
160 uint8_t* data,
161 size_t size) {
Primiano Tuccid933d912018-09-04 09:15:07 +0100162 PERFETTO_DCHECK(data >= &owned_buf[0]);
163 const uint8_t* start = &owned_buf[0];
164 const size_t data_off = static_cast<size_t>(data - start);
165 TraceBlobView whole_buf(std::move(owned_buf), data_off, size);
Primiano Tuccic1678872019-03-20 11:30:54 +0000166
167 protos::pbzero::Trace::Decoder decoder(data, size);
168 for (auto it = decoder.packet(); it; ++it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100169 protozero::ConstBytes packet = *it;
170 size_t field_offset = whole_buf.offset_of(packet.data);
Lalit Magantid71a9452019-05-09 15:13:24 +0100171 util::Status status =
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100172 ParsePacket(whole_buf.slice(field_offset, packet.size));
Lalit Magantid71a9452019-05-09 15:13:24 +0100173 if (PERFETTO_UNLIKELY(!status.ok()))
174 return status;
Primiano Tuccid933d912018-09-04 09:15:07 +0100175 }
176
Primiano Tuccic1678872019-03-20 11:30:54 +0000177 const size_t bytes_left = decoder.bytes_left();
178 if (bytes_left > 0) {
Primiano Tuccid933d912018-09-04 09:15:07 +0100179 PERFETTO_DCHECK(partial_buf_.empty());
Primiano Tuccic1678872019-03-20 11:30:54 +0000180 partial_buf_.insert(partial_buf_.end(), &data[decoder.read_offset()],
181 &data[decoder.read_offset() + bytes_left]);
Primiano Tuccid933d912018-09-04 09:15:07 +0100182 }
Lalit Magantid71a9452019-05-09 15:13:24 +0100183 return util::OkStatus();
Primiano Tuccid933d912018-09-04 09:15:07 +0100184}
185
Andrew Shulaev46b12a92020-07-09 00:45:37 +0100186util::Status ProtoTraceTokenizer::ParseExtensionDescriptor(
187 ConstBytes descriptor) {
188 protos::pbzero::ExtensionDescriptor::Decoder decoder(descriptor.data,
189 descriptor.size);
190
191 for (auto extension = decoder.extension_file(); extension; extension++) {
192 context_->proto_to_args_table_->AddExtensionFileDescriptor(
193 extension->data(), extension->size());
194 }
195
196 return util::OkStatus();
197}
198
Lalit Magantid71a9452019-05-09 15:13:24 +0100199util::Status ProtoTraceTokenizer::ParsePacket(TraceBlobView packet) {
Primiano Tuccic1678872019-03-20 11:30:54 +0000200 protos::pbzero::TracePacket::Decoder decoder(packet.data(), packet.length());
Lalit Maganti4b2b2532019-05-09 11:03:23 +0100201 if (PERFETTO_UNLIKELY(decoder.bytes_left()))
Lalit Magantid71a9452019-05-09 15:13:24 +0100202 return util::ErrStatus(
203 "Failed to parse proto packet fully; the trace is probably corrupt.");
Primiano Tuccid933d912018-09-04 09:15:07 +0100204
Eric Secklerb32cacf2019-09-27 16:51:19 +0100205 const uint32_t seq_id = decoder.trusted_packet_sequence_id();
Eric Seckler1edbe002019-12-16 18:08:57 +0000206 auto* state = GetIncrementalStateForPacketSequence(seq_id);
Eric Secklerb32cacf2019-09-27 16:51:19 +0100207
208 uint32_t sequence_flags = decoder.sequence_flags();
209
210 if (decoder.incremental_state_cleared() ||
211 sequence_flags &
212 protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
Eric Seckler684a4f72019-04-26 14:34:07 +0100213 HandleIncrementalStateCleared(decoder);
214 } else if (decoder.previous_packet_dropped()) {
215 HandlePreviousPacketDropped(decoder);
216 }
217
Eric Seckler1edbe002019-12-16 18:08:57 +0000218 // It is important that we parse defaults before parsing other fields such as
219 // the timestamp, since the defaults could affect them.
220 if (decoder.has_trace_packet_defaults()) {
221 auto field = decoder.trace_packet_defaults();
222 const size_t offset = packet.offset_of(field.data);
223 ParseTracePacketDefaults(decoder, packet.slice(offset, field.size));
224 }
225
226 if (decoder.has_interned_data()) {
227 auto field = decoder.interned_data();
228 const size_t offset = packet.offset_of(field.data);
229 ParseInternedData(decoder, packet.slice(offset, field.size));
230 }
231
232 if (decoder.has_clock_snapshot()) {
233 return ParseClockSnapshot(decoder.clock_snapshot(),
234 decoder.trusted_packet_sequence_id());
235 }
236
Andrew Shulaev46b12a92020-07-09 00:45:37 +0100237 if (decoder.has_extension_descriptor()) {
238 return ParseExtensionDescriptor(decoder.extension_descriptor());
239 }
240
Eric Secklerb32cacf2019-09-27 16:51:19 +0100241 if (decoder.sequence_flags() &
242 protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE) {
243 if (!seq_id) {
244 return util::ErrStatus(
245 "TracePacket specified SEQ_NEEDS_INCREMENTAL_STATE but the "
246 "TraceWriter's sequence_id is zero (the service is "
247 "probably too old)");
248 }
249
250 if (!state->IsIncrementalStateValid()) {
251 context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
252 return util::OkStatus();
253 }
254 }
255
Eric Seckler1edbe002019-12-16 18:08:57 +0000256 protos::pbzero::TracePacketDefaults::Decoder* defaults =
Eric Seckler7e9dc312020-01-02 15:17:28 +0000257 state->current_generation()->GetTracePacketDefaults();
Primiano Tucci6756fb02019-08-14 15:49:18 +0200258
Eric Seckler1edbe002019-12-16 18:08:57 +0000259 int64_t timestamp;
260 if (decoder.has_timestamp()) {
261 timestamp = static_cast<int64_t>(decoder.timestamp());
Eric Secklerb32cacf2019-09-27 16:51:19 +0100262
Eric Seckler1edbe002019-12-16 18:08:57 +0000263 uint32_t timestamp_clock_id =
264 decoder.has_timestamp_clock_id()
265 ? decoder.timestamp_clock_id()
266 : (defaults ? defaults->timestamp_clock_id() : 0);
267
268 if ((decoder.has_chrome_events() || decoder.has_chrome_metadata()) &&
269 (!timestamp_clock_id ||
Eric Secklerdc454522020-05-20 19:40:23 +0100270 timestamp_clock_id == protos::pbzero::BUILTIN_CLOCK_MONOTONIC)) {
Eric Seckler1edbe002019-12-16 18:08:57 +0000271 // Chrome event timestamps are in MONOTONIC domain, but may occur in
272 // traces where (a) no clock snapshots exist or (b) no clock_id is
273 // specified for their timestamps. Adjust to trace time if we have a clock
274 // snapshot.
275 // TODO(eseckler): Set timestamp_clock_id and emit ClockSnapshots in
276 // chrome and then remove this.
277 auto trace_ts = context_->clock_tracker->ToTraceTime(
Eric Secklerdc454522020-05-20 19:40:23 +0100278 protos::pbzero::BUILTIN_CLOCK_MONOTONIC, timestamp);
Eric Seckler1edbe002019-12-16 18:08:57 +0000279 if (trace_ts.has_value())
280 timestamp = trace_ts.value();
281 } else if (timestamp_clock_id) {
282 // If the TracePacket specifies a non-zero clock-id, translate the
283 // timestamp into the trace-time clock domain.
284 ClockTracker::ClockId converted_clock_id = timestamp_clock_id;
285 bool is_seq_scoped =
286 ClockTracker::IsReservedSeqScopedClockId(converted_clock_id);
287 if (is_seq_scoped) {
288 if (!seq_id) {
289 return util::ErrStatus(
290 "TracePacket specified a sequence-local clock id (%" PRIu32
291 ") but the TraceWriter's sequence_id is zero (the service is "
292 "probably too old)",
293 timestamp_clock_id);
294 }
295 converted_clock_id =
296 ClockTracker::SeqScopedClockIdToGlobal(seq_id, timestamp_clock_id);
297 }
298 auto trace_ts =
299 context_->clock_tracker->ToTraceTime(converted_clock_id, timestamp);
300 if (!trace_ts.has_value()) {
301 // ToTraceTime() will increase the |clock_sync_failure| stat on failure.
302 static const char seq_extra_err[] =
303 " Because the clock id is sequence-scoped, the ClockSnapshot must "
304 "be emitted on the same TraceWriter sequence of the packet that "
305 "refers to that clock id.";
306 return util::ErrStatus(
307 "Failed to convert TracePacket's timestamp from clock_id=%" PRIu32
308 " seq_id=%" PRIu32
309 ". This is usually due to the lack of a prior ClockSnapshot "
310 "proto.%s",
311 timestamp_clock_id, seq_id, is_seq_scoped ? seq_extra_err : "");
312 }
313 timestamp = trace_ts.value();
314 }
315 } else {
316 timestamp = std::max(latest_timestamp_, context_->sorter->max_timestamp());
Eric Seckler684a4f72019-04-26 14:34:07 +0100317 }
Eric Seckler1edbe002019-12-16 18:08:57 +0000318 latest_timestamp_ = std::max(timestamp, latest_timestamp_);
Eric Seckler684a4f72019-04-26 14:34:07 +0100319
Mikhail Khokhlov785af542019-12-06 13:45:10 +0000320 auto& modules = context_->modules_by_field;
321 for (uint32_t field_id = 1; field_id < modules.size(); ++field_id) {
322 if (modules[field_id] && decoder.Get(field_id).valid()) {
Mikhail Khokhlovdd1db002019-12-09 16:34:07 +0000323 ModuleResult res = modules[field_id]->TokenizePacket(
324 decoder, &packet, timestamp, state, field_id);
Mikhail Khokhlov785af542019-12-06 13:45:10 +0000325 if (!res.ignored())
326 return res.ToStatus();
327 }
328 }
329
Hector Dearman33610d22019-08-07 13:00:20 +0100330 if (decoder.has_compressed_packets()) {
Lalit Maganti0bfeb972020-03-14 03:57:30 +0000331 if (!gzip::IsGzipSupported())
Lalit Maganti9d538bd2020-03-12 23:48:16 +0000332 return util::Status("Cannot decode compressed packets. Zlib not enabled");
333
Hector Dearman33610d22019-08-07 13:00:20 +0100334 protozero::ConstBytes field = decoder.compressed_packets();
335 const size_t field_off = packet.offset_of(field.data);
336 TraceBlobView compressed_packets = packet.slice(field_off, field.size);
Lalit Maganti9d538bd2020-03-12 23:48:16 +0000337 TraceBlobView packets =
338 Decompress(&decompressor_, std::move(compressed_packets));
Hector Dearman33610d22019-08-07 13:00:20 +0100339
340 const uint8_t* start = packets.data();
341 const uint8_t* end = packets.data() + packets.length();
342 const uint8_t* ptr = start;
343 while ((end - ptr) > 2) {
344 const uint8_t* packet_start = ptr;
345 if (PERFETTO_UNLIKELY(*ptr != kTracePacketTag))
346 return util::ErrStatus("Expected TracePacket tag");
347 uint64_t packet_size = 0;
348 ptr = ParseVarInt(++ptr, end, &packet_size);
349 size_t packet_offset = static_cast<size_t>(ptr - start);
350 ptr += packet_size;
351 if (PERFETTO_UNLIKELY((ptr - packet_start) < 2 || ptr > end))
352 return util::ErrStatus("Invalid packet size");
353 util::Status status = ParsePacket(
354 packets.slice(packet_offset, static_cast<size_t>(packet_size)));
355 if (PERFETTO_UNLIKELY(!status.ok()))
356 return status;
357 }
Hector Dearman33610d22019-08-07 13:00:20 +0100358 return util::OkStatus();
359 }
360
Lalit Maganti55d0bc72019-10-23 16:22:00 +0100361 // If we're not forcing a full sort and this is a write_into_file trace, then
362 // use flush_period_ms as an indiciator for how big the sliding window for the
363 // sorter should be.
364 if (!context_->config.force_full_sort && decoder.has_trace_config()) {
Lalit Maganti295a8612019-05-21 13:57:42 +0100365 auto config = decoder.trace_config();
366 protos::pbzero::TraceConfig::Decoder trace_config(config.data, config.size);
367
368 if (trace_config.write_into_file()) {
369 int64_t window_size_ns;
370 if (trace_config.has_flush_period_ms() &&
371 trace_config.flush_period_ms() > 0) {
372 // We use 2x the flush period as a margin of error to allow for any
373 // late flush responses to still be sorted correctly.
Lalit Magantib2c2f562019-05-22 18:53:46 +0100374 window_size_ns = static_cast<int64_t>(trace_config.flush_period_ms()) *
375 2 * 1000 * 1000;
Lalit Maganti295a8612019-05-21 13:57:42 +0100376 } else {
377 constexpr uint64_t kDefaultWindowNs =
378 180 * 1000 * 1000 * 1000ULL; // 3 minutes.
379 PERFETTO_ELOG(
380 "It is strongly recommended to have flush_period_ms set when "
381 "write_into_file is turned on. You will likely have many dropped "
382 "events because of inability to sort the events correctly.");
383 window_size_ns = static_cast<int64_t>(kDefaultWindowNs);
384 }
385 context_->sorter->SetWindowSizeNs(window_size_ns);
386 }
387 }
388
Primiano Tuccid933d912018-09-04 09:15:07 +0100389 // Use parent data and length because we want to parse this again
390 // later to get the exact type of the packet.
Florian Mayer5716fc12019-06-24 11:50:51 -0700391 context_->sorter->PushTracePacket(timestamp, state, std::move(packet));
Lalit Maganti4b2b2532019-05-09 11:03:23 +0100392
Lalit Magantid71a9452019-05-09 15:13:24 +0100393 return util::OkStatus();
Eric Seckler684a4f72019-04-26 14:34:07 +0100394}
395
396void ProtoTraceTokenizer::HandleIncrementalStateCleared(
397 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
398 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
399 PERFETTO_ELOG(
400 "incremental_state_cleared without trusted_packet_sequence_id");
401 context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
402 return;
403 }
404 GetIncrementalStateForPacketSequence(
405 packet_decoder.trusted_packet_sequence_id())
406 ->OnIncrementalStateCleared();
Eric Secklerfbd9aed2020-03-10 18:07:38 +0000407 context_->track_tracker->OnIncrementalStateCleared(
408 packet_decoder.trusted_packet_sequence_id());
Eric Seckler684a4f72019-04-26 14:34:07 +0100409}
410
411void ProtoTraceTokenizer::HandlePreviousPacketDropped(
412 const protos::pbzero::TracePacket::Decoder& packet_decoder) {
413 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
414 PERFETTO_ELOG("previous_packet_dropped without trusted_packet_sequence_id");
415 context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
416 return;
417 }
418 GetIncrementalStateForPacketSequence(
419 packet_decoder.trusted_packet_sequence_id())
420 ->OnPacketLoss();
421}
422
Eric Seckler1edbe002019-12-16 18:08:57 +0000423void ProtoTraceTokenizer::ParseTracePacketDefaults(
424 const protos::pbzero::TracePacket_Decoder& packet_decoder,
425 TraceBlobView trace_packet_defaults) {
426 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
427 PERFETTO_ELOG(
428 "TracePacketDefaults packet without trusted_packet_sequence_id");
429 context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
430 return;
431 }
432
433 auto* state = GetIncrementalStateForPacketSequence(
434 packet_decoder.trusted_packet_sequence_id());
435 state->UpdateTracePacketDefaults(std::move(trace_packet_defaults));
436}
437
Eric Seckler684a4f72019-04-26 14:34:07 +0100438void ProtoTraceTokenizer::ParseInternedData(
439 const protos::pbzero::TracePacket::Decoder& packet_decoder,
440 TraceBlobView interned_data) {
441 if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
442 PERFETTO_ELOG("InternedData packet without trusted_packet_sequence_id");
443 context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
444 return;
445 }
446
447 auto* state = GetIncrementalStateForPacketSequence(
448 packet_decoder.trusted_packet_sequence_id());
449
Eric Seckler02cdcef2019-10-14 08:56:28 +0100450 // Don't parse interned data entries until incremental state is valid, because
451 // they could otherwise be associated with the wrong generation in the state.
452 if (!state->IsIncrementalStateValid()) {
453 context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
454 return;
455 }
Eric Seckler684a4f72019-04-26 14:34:07 +0100456
457 // Store references to interned data submessages into the sequence's state.
Eric Seckler02cdcef2019-10-14 08:56:28 +0100458 protozero::ProtoDecoder decoder(interned_data.data(), interned_data.length());
459 for (protozero::Field f = decoder.ReadField(); f.valid();
460 f = decoder.ReadField()) {
461 auto bytes = f.as_bytes();
462 auto offset = interned_data.offset_of(bytes.data);
463 state->InternMessage(f.id(), interned_data.slice(offset, bytes.size));
Nicolò Mazzucato8f75ede2019-08-12 17:36:36 +0100464 }
Eric Seckler684a4f72019-04-26 14:34:07 +0100465}
466
Primiano Tucci6756fb02019-08-14 15:49:18 +0200467util::Status ProtoTraceTokenizer::ParseClockSnapshot(ConstBytes blob,
468 uint32_t seq_id) {
Eric Seckler9cadb3a2019-11-14 01:38:33 +0000469 std::vector<ClockTracker::ClockValue> clocks;
Primiano Tucci6756fb02019-08-14 15:49:18 +0200470 protos::pbzero::ClockSnapshot::Decoder evt(blob.data, blob.size);
Eric Secklerdc454522020-05-20 19:40:23 +0100471 if (evt.primary_trace_clock()) {
472 context_->clock_tracker->SetTraceTimeClock(
473 static_cast<ClockTracker::ClockId>(evt.primary_trace_clock()));
474 }
Primiano Tucci6756fb02019-08-14 15:49:18 +0200475 for (auto it = evt.clocks(); it; ++it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100476 protos::pbzero::ClockSnapshot::Clock::Decoder clk(*it);
Primiano Tucci6756fb02019-08-14 15:49:18 +0200477 ClockTracker::ClockId clock_id = clk.clock_id();
478 if (ClockTracker::IsReservedSeqScopedClockId(clk.clock_id())) {
479 if (!seq_id) {
480 return util::ErrStatus(
481 "ClockSnapshot packet is specifying a sequence-scoped clock id "
482 "(%" PRIu64 ") but the TracePacket sequence_id is zero",
483 clock_id);
484 }
485 clock_id = ClockTracker::SeqScopedClockIdToGlobal(seq_id, clk.clock_id());
486 }
Eric Seckler9cadb3a2019-11-14 01:38:33 +0000487 int64_t unit_multiplier_ns =
488 clk.unit_multiplier_ns()
489 ? static_cast<int64_t>(clk.unit_multiplier_ns())
490 : 1;
491 clocks.emplace_back(clock_id, clk.timestamp(), unit_multiplier_ns,
492 clk.is_incremental());
Primiano Tucci6756fb02019-08-14 15:49:18 +0200493 }
Eric Seckler9cadb3a2019-11-14 01:38:33 +0000494 context_->clock_tracker->AddSnapshot(clocks);
Primiano Tucci6756fb02019-08-14 15:49:18 +0200495 return util::OkStatus();
496}
497
Primiano Tucci40da82f2020-02-13 18:04:35 +0000498void ProtoTraceTokenizer::NotifyEndOfFile() {}
499
Primiano Tuccid933d912018-09-04 09:15:07 +0100500} // namespace trace_processor
501} // namespace perfetto