1 /*
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_parser.h"
18
19 #include <iostream>
20 #include <optional>
21 #include <string>
22
23 #include "perfetto/base/logging.h"
24 #include "perfetto/ext/base/string_writer.h"
25 #include "perfetto/trace_processor/status.h"
26 #include "src/trace_processor/importers/common/args_tracker.h"
27 #include "src/trace_processor/importers/common/args_translation_table.h"
28 #include "src/trace_processor/importers/common/event_tracker.h"
29 #include "src/trace_processor/importers/common/flow_tracker.h"
30 #include "src/trace_processor/importers/common/process_tracker.h"
31 #include "src/trace_processor/importers/common/track_tracker.h"
32 #include "src/trace_processor/importers/json/json_utils.h"
33 #include "src/trace_processor/importers/proto/packet_analyzer.h"
34 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
35 #include "src/trace_processor/importers/proto/profile_packet_utils.h"
36 #include "src/trace_processor/importers/proto/track_event_tracker.h"
37 #include "src/trace_processor/util/debug_annotation_parser.h"
38 #include "src/trace_processor/util/proto_to_args_parser.h"
39 #include "src/trace_processor/util/status_macros.h"
40
41 #include "protos/perfetto/trace/extension_descriptor.pbzero.h"
42 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
43 #include "protos/perfetto/trace/track_event/chrome_active_processes.pbzero.h"
44 #include "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h"
45 #include "protos/perfetto/trace/track_event/chrome_histogram_sample.pbzero.h"
46 #include "protos/perfetto/trace/track_event/chrome_legacy_ipc.pbzero.h"
47 #include "protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h"
48 #include "protos/perfetto/trace/track_event/chrome_thread_descriptor.pbzero.h"
49 #include "protos/perfetto/trace/track_event/counter_descriptor.pbzero.h"
50 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
51 #include "protos/perfetto/trace/track_event/log_message.pbzero.h"
52 #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
53 #include "protos/perfetto/trace/track_event/source_location.pbzero.h"
54 #include "protos/perfetto/trace/track_event/task_execution.pbzero.h"
55 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
56 #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
57 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
58
59 namespace perfetto {
60 namespace trace_processor {
61
62 namespace {
63 using BoundInserter = ArgsTracker::BoundInserter;
64 using protos::pbzero::TrackEvent;
65 using LegacyEvent = TrackEvent::LegacyEvent;
66 using protozero::ConstBytes;
67
68 // Slices which have been opened but haven't been closed yet will be marked
69 // with these placeholder values.
70 constexpr int64_t kPendingThreadDuration = -1;
71 constexpr int64_t kPendingThreadInstructionDelta = -1;
72
73 class TrackEventArgsParser : public util::ProtoToArgsParser::Delegate {
74 public:
TrackEventArgsParser(int64_t packet_timestamp,BoundInserter & inserter,TraceStorage & storage,PacketSequenceStateGeneration & sequence_state)75 TrackEventArgsParser(int64_t packet_timestamp,
76 BoundInserter& inserter,
77 TraceStorage& storage,
78 PacketSequenceStateGeneration& sequence_state)
79 : packet_timestamp_(packet_timestamp),
80 inserter_(inserter),
81 storage_(storage),
82 sequence_state_(sequence_state) {}
83
84 ~TrackEventArgsParser() override;
85
86 using Key = util::ProtoToArgsParser::Key;
87
AddInteger(const Key & key,int64_t value)88 void AddInteger(const Key& key, int64_t value) final {
89 inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
90 storage_.InternString(base::StringView(key.key)),
91 Variadic::Integer(value));
92 }
AddUnsignedInteger(const Key & key,uint64_t value)93 void AddUnsignedInteger(const Key& key, uint64_t value) final {
94 inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
95 storage_.InternString(base::StringView(key.key)),
96 Variadic::UnsignedInteger(value));
97 }
AddString(const Key & key,const protozero::ConstChars & value)98 void AddString(const Key& key, const protozero::ConstChars& value) final {
99 inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
100 storage_.InternString(base::StringView(key.key)),
101 Variadic::String(storage_.InternString(value)));
102 }
AddString(const Key & key,const std::string & value)103 void AddString(const Key& key, const std::string& value) final {
104 inserter_.AddArg(
105 storage_.InternString(base::StringView(key.flat_key)),
106 storage_.InternString(base::StringView(key.key)),
107 Variadic::String(storage_.InternString(base::StringView(value))));
108 }
AddDouble(const Key & key,double value)109 void AddDouble(const Key& key, double value) final {
110 inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
111 storage_.InternString(base::StringView(key.key)),
112 Variadic::Real(value));
113 }
AddPointer(const Key & key,const void * value)114 void AddPointer(const Key& key, const void* value) final {
115 inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
116 storage_.InternString(base::StringView(key.key)),
117 Variadic::Pointer(reinterpret_cast<uintptr_t>(value)));
118 }
AddBoolean(const Key & key,bool value)119 void AddBoolean(const Key& key, bool value) final {
120 inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
121 storage_.InternString(base::StringView(key.key)),
122 Variadic::Boolean(value));
123 }
AddJson(const Key & key,const protozero::ConstChars & value)124 bool AddJson(const Key& key, const protozero::ConstChars& value) final {
125 auto json_value = json::ParseJsonString(value);
126 if (!json_value)
127 return false;
128 return json::AddJsonValueToArgs(*json_value, base::StringView(key.flat_key),
129 base::StringView(key.key), &storage_,
130 &inserter_);
131 }
AddNull(const Key & key)132 void AddNull(const Key& key) final {
133 inserter_.AddArg(storage_.InternString(base::StringView(key.flat_key)),
134 storage_.InternString(base::StringView(key.key)),
135 Variadic::Null());
136 }
137
GetArrayEntryIndex(const std::string & array_key)138 size_t GetArrayEntryIndex(const std::string& array_key) final {
139 return inserter_.GetNextArrayEntryIndex(
140 storage_.InternString(base::StringView(array_key)));
141 }
142
IncrementArrayEntryIndex(const std::string & array_key)143 size_t IncrementArrayEntryIndex(const std::string& array_key) final {
144 return inserter_.IncrementArrayEntryIndex(
145 storage_.InternString(base::StringView(array_key)));
146 }
147
GetInternedMessageView(uint32_t field_id,uint64_t iid)148 InternedMessageView* GetInternedMessageView(uint32_t field_id,
149 uint64_t iid) final {
150 return sequence_state_.GetInternedMessageView(field_id, iid);
151 }
152
packet_timestamp()153 int64_t packet_timestamp() final { return packet_timestamp_; }
154
seq_state()155 PacketSequenceStateGeneration* seq_state() final { return &sequence_state_; }
156
157 private:
158 int64_t packet_timestamp_;
159 BoundInserter& inserter_;
160 TraceStorage& storage_;
161 PacketSequenceStateGeneration& sequence_state_;
162 };
163
164 TrackEventArgsParser::~TrackEventArgsParser() = default;
165
166 // Paths on Windows use backslash rather than slash as a separator.
167 // Normalise the paths by replacing backslashes with slashes to make it
168 // easier to write cross-platform scripts.
NormalizePathSeparators(const protozero::ConstChars & path)169 std::string NormalizePathSeparators(const protozero::ConstChars& path) {
170 std::string result(path.data, path.size);
171 for (char& c : result) {
172 if (c == '\\')
173 c = '/';
174 }
175 return result;
176 }
177
MaybeParseUnsymbolizedSourceLocation(std::string prefix,const protozero::Field & field,util::ProtoToArgsParser::Delegate & delegate)178 std::optional<base::Status> MaybeParseUnsymbolizedSourceLocation(
179 std::string prefix,
180 const protozero::Field& field,
181 util::ProtoToArgsParser::Delegate& delegate) {
182 auto* decoder = delegate.GetInternedMessage(
183 protos::pbzero::InternedData::kUnsymbolizedSourceLocations,
184 field.as_uint64());
185 if (!decoder) {
186 // Lookup failed fall back on default behaviour which will just put
187 // the iid into the args table.
188 return std::nullopt;
189 }
190 // Interned mapping_id loses it's meaning when the sequence ends. So we need
191 // to get an id from stack_profile_mapping table.
192 ProfilePacketInternLookup intern_lookup(delegate.seq_state());
193 auto mapping_id =
194 delegate.seq_state()
195 ->state()
196 ->sequence_stack_profile_tracker()
197 .FindOrInsertMapping(decoder->mapping_id(), &intern_lookup);
198 if (!mapping_id) {
199 return std::nullopt;
200 }
201 delegate.AddUnsignedInteger(
202 util::ProtoToArgsParser::Key(prefix + ".mapping_id"), mapping_id->value);
203 delegate.AddUnsignedInteger(util::ProtoToArgsParser::Key(prefix + ".rel_pc"),
204 decoder->rel_pc());
205 return base::OkStatus();
206 }
207
MaybeParseSourceLocation(std::string prefix,const protozero::Field & field,util::ProtoToArgsParser::Delegate & delegate)208 std::optional<base::Status> MaybeParseSourceLocation(
209 std::string prefix,
210 const protozero::Field& field,
211 util::ProtoToArgsParser::Delegate& delegate) {
212 auto* decoder = delegate.GetInternedMessage(
213 protos::pbzero::InternedData::kSourceLocations, field.as_uint64());
214 if (!decoder) {
215 // Lookup failed fall back on default behaviour which will just put
216 // the source_location_iid into the args table.
217 return std::nullopt;
218 }
219
220 delegate.AddString(util::ProtoToArgsParser::Key(prefix + ".file_name"),
221 NormalizePathSeparators(decoder->file_name()));
222 delegate.AddString(util::ProtoToArgsParser::Key(prefix + ".function_name"),
223 decoder->function_name());
224 if (decoder->has_line_number()) {
225 delegate.AddInteger(util::ProtoToArgsParser::Key(prefix + ".line_number"),
226 decoder->line_number());
227 }
228
229 return base::OkStatus();
230 }
231
232 } // namespace
233
234 class TrackEventParser::EventImporter {
235 public:
EventImporter(TrackEventParser * parser,int64_t ts,const TrackEventData * event_data,ConstBytes blob,uint32_t packet_sequence_id)236 EventImporter(TrackEventParser* parser,
237 int64_t ts,
238 const TrackEventData* event_data,
239 ConstBytes blob,
240 uint32_t packet_sequence_id)
241 : context_(parser->context_),
242 track_event_tracker_(parser->track_event_tracker_),
243 storage_(context_->storage.get()),
244 parser_(parser),
245 args_translation_table_(context_->args_translation_table.get()),
246 ts_(ts),
247 event_data_(event_data),
248 sequence_state_(event_data->trace_packet_data.sequence_state.get()),
249 blob_(std::move(blob)),
250 event_(blob_),
251 legacy_event_(event_.legacy_event()),
252 defaults_(event_data->trace_packet_data.sequence_state
253 ->GetTrackEventDefaults()),
254 thread_timestamp_(event_data->thread_timestamp),
255 thread_instruction_count_(event_data->thread_instruction_count),
256 packet_sequence_id_(packet_sequence_id) {}
257
Import()258 util::Status Import() {
259 // TODO(eseckler): This legacy event field will eventually be replaced by
260 // fields in TrackEvent itself.
261 if (PERFETTO_UNLIKELY(!event_.type() && !legacy_event_.has_phase()))
262 return util::ErrStatus("TrackEvent without type or phase");
263
264 category_id_ = ParseTrackEventCategory();
265 name_id_ = ParseTrackEventName();
266
267 if (context_->content_analyzer) {
268 PacketAnalyzer::SampleAnnotation annotation;
269 annotation.push_back({parser_->event_category_key_id_, category_id_});
270 annotation.push_back({parser_->event_name_key_id_, name_id_});
271 PacketAnalyzer::Get(context_)->ProcessPacket(
272 event_data_->trace_packet_data.packet, annotation);
273 }
274
275 RETURN_IF_ERROR(ParseTrackAssociation());
276
277 // Counter-type events don't support arguments (those are on the
278 // CounterDescriptor instead). All they have is a |{double_,}counter_value|.
279 if (event_.type() == TrackEvent::TYPE_COUNTER) {
280 ParseCounterEvent();
281 return util::OkStatus();
282 }
283
284 // If we have legacy thread time / instruction count fields, also parse them
285 // into the counters tables.
286 ParseLegacyThreadTimeAndInstructionsAsCounters();
287
288 // Parse extra counter values before parsing the actual event. This way, we
289 // can update the slice's thread time / instruction count fields based on
290 // these counter values and also parse them as slice attributes / arguments.
291 ParseExtraCounterValues();
292
293 // TODO(eseckler): Replace phase with type and remove handling of
294 // legacy_event_.phase() once it is no longer used by producers.
295 char phase = static_cast<char>(ParsePhaseOrType());
296
297 switch (phase) {
298 case 'B': // TRACE_EVENT_PHASE_BEGIN.
299 return ParseThreadBeginEvent();
300 case 'E': // TRACE_EVENT_PHASE_END.
301 return ParseThreadEndEvent();
302 case 'X': // TRACE_EVENT_PHASE_COMPLETE.
303 return ParseThreadCompleteEvent();
304 case 's': // TRACE_EVENT_PHASE_FLOW_BEGIN.
305 case 't': // TRACE_EVENT_PHASE_FLOW_STEP.
306 case 'f': // TRACE_EVENT_PHASE_FLOW_END.
307 return ParseFlowEventV1(phase);
308 case 'i':
309 case 'I': // TRACE_EVENT_PHASE_INSTANT.
310 case 'R': // TRACE_EVENT_PHASE_MARK.
311 return ParseThreadInstantEvent(phase);
312 case 'b': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN
313 case 'S':
314 return ParseAsyncBeginEvent(phase);
315 case 'e': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_END
316 case 'F':
317 return ParseAsyncEndEvent();
318 case 'n': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT
319 return ParseAsyncInstantEvent();
320 case 'T':
321 case 'p':
322 return ParseAsyncStepEvent(phase);
323 case 'M': // TRACE_EVENT_PHASE_METADATA (process and thread names).
324 return ParseMetadataEvent();
325 default:
326 // Other events are proxied via the raw table for JSON export.
327 return ParseLegacyEventAsRawEvent();
328 }
329 }
330
331 private:
ParseTrackEventCategory()332 StringId ParseTrackEventCategory() {
333 StringId category_id = kNullStringId;
334
335 std::vector<uint64_t> category_iids;
336 for (auto it = event_.category_iids(); it; ++it) {
337 category_iids.push_back(*it);
338 }
339 std::vector<protozero::ConstChars> category_strings;
340 for (auto it = event_.categories(); it; ++it) {
341 category_strings.push_back(*it);
342 }
343
344 // If there's a single category, we can avoid building a concatenated
345 // string.
346 if (PERFETTO_LIKELY(category_iids.size() == 1 &&
347 category_strings.empty())) {
348 auto* decoder = sequence_state_->LookupInternedMessage<
349 protos::pbzero::InternedData::kEventCategoriesFieldNumber,
350 protos::pbzero::EventCategory>(category_iids[0]);
351 if (decoder) {
352 category_id = storage_->InternString(decoder->name());
353 } else {
354 char buffer[32];
355 base::StringWriter writer(buffer, sizeof(buffer));
356 writer.AppendLiteral("unknown(");
357 writer.AppendUnsignedInt(category_iids[0]);
358 writer.AppendChar(')');
359 category_id = storage_->InternString(writer.GetStringView());
360 }
361 } else if (category_iids.empty() && category_strings.size() == 1) {
362 category_id = storage_->InternString(category_strings[0]);
363 } else if (category_iids.size() + category_strings.size() > 1) {
364 // We concatenate the category strings together since we currently only
365 // support a single "cat" column.
366 // TODO(eseckler): Support multi-category events in the table schema.
367 std::string categories;
368 for (uint64_t iid : category_iids) {
369 auto* decoder = sequence_state_->LookupInternedMessage<
370 protos::pbzero::InternedData::kEventCategoriesFieldNumber,
371 protos::pbzero::EventCategory>(iid);
372 if (!decoder)
373 continue;
374 base::StringView name = decoder->name();
375 if (!categories.empty())
376 categories.append(",");
377 categories.append(name.data(), name.size());
378 }
379 for (const protozero::ConstChars& cat : category_strings) {
380 if (!categories.empty())
381 categories.append(",");
382 categories.append(cat.data, cat.size);
383 }
384 if (!categories.empty())
385 category_id = storage_->InternString(base::StringView(categories));
386 }
387
388 return category_id;
389 }
390
ParseTrackEventName()391 StringId ParseTrackEventName() {
392 uint64_t name_iid = event_.name_iid();
393 if (!name_iid)
394 name_iid = legacy_event_.name_iid();
395
396 if (PERFETTO_LIKELY(name_iid)) {
397 auto* decoder = sequence_state_->LookupInternedMessage<
398 protos::pbzero::InternedData::kEventNamesFieldNumber,
399 protos::pbzero::EventName>(name_iid);
400 if (decoder)
401 return storage_->InternString(decoder->name());
402 } else if (event_.has_name()) {
403 return storage_->InternString(event_.name());
404 }
405
406 return kNullStringId;
407 }
408
ParseTrackAssociation()409 util::Status ParseTrackAssociation() {
410 TrackTracker* track_tracker = context_->track_tracker.get();
411 ProcessTracker* procs = context_->process_tracker.get();
412
413 // Consider track_uuid from the packet and TrackEventDefaults, fall back to
414 // the default descriptor track (uuid 0).
415 track_uuid_ = event_.has_track_uuid()
416 ? event_.track_uuid()
417 : (defaults_ && defaults_->has_track_uuid()
418 ? defaults_->track_uuid()
419 : 0u);
420
421 // Determine track from track_uuid specified in either TrackEvent or
422 // TrackEventDefaults. If a non-default track is not set, we either:
423 // a) fall back to the track specified by the sequence's (or event's) pid
424 // + tid (only in case of legacy tracks/events, i.e. events that don't
425 // specify an explicit track uuid or use legacy event phases instead of
426 // TrackEvent types), or
427 // b) a default track.
428 if (track_uuid_) {
429 std::optional<TrackId> opt_track_id =
430 track_event_tracker_->GetDescriptorTrack(track_uuid_, name_id_,
431 packet_sequence_id_);
432 if (!opt_track_id) {
433 track_event_tracker_->ReserveDescriptorChildTrack(track_uuid_,
434 /*parent_uuid=*/0,
435 name_id_);
436 opt_track_id = track_event_tracker_->GetDescriptorTrack(
437 track_uuid_, name_id_, packet_sequence_id_);
438 }
439 track_id_ = *opt_track_id;
440
441 auto thread_track_row =
442 storage_->thread_track_table().id().IndexOf(track_id_);
443 if (thread_track_row) {
444 utid_ = storage_->thread_track_table().utid()[*thread_track_row];
445 upid_ = storage_->thread_table().upid()[*utid_];
446 } else {
447 auto process_track_row =
448 storage_->process_track_table().id().IndexOf(track_id_);
449 if (process_track_row) {
450 upid_ = storage_->process_track_table().upid()[*process_track_row];
451 if (sequence_state_->state()->pid_and_tid_valid()) {
452 uint32_t pid =
453 static_cast<uint32_t>(sequence_state_->state()->pid());
454 uint32_t tid =
455 static_cast<uint32_t>(sequence_state_->state()->tid());
456 UniqueTid utid_candidate = procs->UpdateThread(tid, pid);
457 if (storage_->thread_table().upid()[utid_candidate] == upid_)
458 legacy_passthrough_utid_ = utid_candidate;
459 }
460 } else {
461 auto* tracks = context_->storage->mutable_track_table();
462 auto track_index = tracks->id().IndexOf(track_id_);
463 if (track_index) {
464 const StringPool::Id& id = tracks->name()[*track_index];
465 if (id.is_null())
466 tracks->mutable_name()->Set(*track_index, name_id_);
467 }
468
469 if (sequence_state_->state()->pid_and_tid_valid()) {
470 uint32_t pid =
471 static_cast<uint32_t>(sequence_state_->state()->pid());
472 uint32_t tid =
473 static_cast<uint32_t>(sequence_state_->state()->tid());
474 legacy_passthrough_utid_ = procs->UpdateThread(tid, pid);
475 }
476 }
477 }
478 } else {
479 bool pid_tid_state_valid = sequence_state_->state()->pid_and_tid_valid();
480
481 // We have a 0-value |track_uuid|. Nevertheless, we should only fall back
482 // if we have either no |track_uuid| specified at all or |track_uuid| was
483 // set explicitly to 0 (e.g. to override a default track_uuid) and we have
484 // a legacy phase. Events with real phases should use |track_uuid| to
485 // specify a different track (or use the pid/tid_override fields).
486 bool fallback_to_legacy_pid_tid_tracks =
487 (!event_.has_track_uuid() || !event_.has_type()) &&
488 pid_tid_state_valid;
489
490 // Always allow fallback if we have a process override.
491 fallback_to_legacy_pid_tid_tracks |= legacy_event_.has_pid_override();
492
493 // A thread override requires a valid pid.
494 fallback_to_legacy_pid_tid_tracks |=
495 legacy_event_.has_tid_override() && pid_tid_state_valid;
496
497 if (fallback_to_legacy_pid_tid_tracks) {
498 uint32_t pid = static_cast<uint32_t>(sequence_state_->state()->pid());
499 uint32_t tid = static_cast<uint32_t>(sequence_state_->state()->tid());
500 if (legacy_event_.has_pid_override()) {
501 pid = static_cast<uint32_t>(legacy_event_.pid_override());
502 tid = static_cast<uint32_t>(-1);
503 }
504 if (legacy_event_.has_tid_override())
505 tid = static_cast<uint32_t>(legacy_event_.tid_override());
506
507 utid_ = procs->UpdateThread(tid, pid);
508 upid_ = storage_->thread_table().upid()[*utid_];
509 track_id_ = track_tracker->InternThreadTrack(*utid_);
510 } else {
511 track_id_ = track_event_tracker_->GetOrCreateDefaultDescriptorTrack();
512 }
513 }
514
515 if (!legacy_event_.has_phase())
516 return util::OkStatus();
517
518 // Legacy phases may imply a different track than the one specified by
519 // the fallback (or default track uuid) above.
520 switch (legacy_event_.phase()) {
521 case 'b':
522 case 'e':
523 case 'n':
524 case 'S':
525 case 'T':
526 case 'p':
527 case 'F': {
528 // Intern tracks for legacy async events based on legacy event ids.
529 int64_t source_id = 0;
530 bool source_id_is_process_scoped = false;
531 if (legacy_event_.has_unscoped_id()) {
532 source_id = static_cast<int64_t>(legacy_event_.unscoped_id());
533 } else if (legacy_event_.has_global_id()) {
534 source_id = static_cast<int64_t>(legacy_event_.global_id());
535 } else if (legacy_event_.has_local_id()) {
536 if (!upid_) {
537 return util::ErrStatus(
538 "TrackEvent with local_id without process association");
539 }
540
541 source_id = static_cast<int64_t>(legacy_event_.local_id());
542 source_id_is_process_scoped = true;
543 } else {
544 return util::ErrStatus("Async LegacyEvent without ID");
545 }
546
547 // Catapult treats nestable async events of different categories with
548 // the same ID as separate tracks. We replicate the same behavior
549 // here. For legacy async events, it uses different tracks based on
550 // event names.
551 const bool legacy_async =
552 legacy_event_.phase() == 'S' || legacy_event_.phase() == 'T' ||
553 legacy_event_.phase() == 'p' || legacy_event_.phase() == 'F';
554 StringId id_scope = legacy_async ? name_id_ : category_id_;
555 if (legacy_event_.has_id_scope()) {
556 std::string concat = storage_->GetString(category_id_).ToStdString() +
557 ":" + legacy_event_.id_scope().ToStdString();
558 id_scope = storage_->InternString(base::StringView(concat));
559 }
560
561 track_id_ = context_->track_tracker->InternLegacyChromeAsyncTrack(
562 name_id_, upid_.value_or(0), source_id, source_id_is_process_scoped,
563 id_scope);
564 legacy_passthrough_utid_ = utid_;
565 break;
566 }
567 case 'i':
568 case 'I': {
569 // Intern tracks for global or process-scoped legacy instant events.
570 switch (legacy_event_.instant_event_scope()) {
571 case LegacyEvent::SCOPE_UNSPECIFIED:
572 case LegacyEvent::SCOPE_THREAD:
573 // Thread-scoped legacy instant events already have the right
574 // track based on the tid/pid of the sequence.
575 if (!utid_) {
576 return util::ErrStatus(
577 "Thread-scoped instant event without thread association");
578 }
579 break;
580 case LegacyEvent::SCOPE_GLOBAL:
581 track_id_ = context_->track_tracker
582 ->GetOrCreateLegacyChromeGlobalInstantTrack();
583 legacy_passthrough_utid_ = utid_;
584 utid_ = std::nullopt;
585 break;
586 case LegacyEvent::SCOPE_PROCESS:
587 if (!upid_) {
588 return util::ErrStatus(
589 "Process-scoped instant event without process association");
590 }
591
592 track_id_ =
593 context_->track_tracker->InternLegacyChromeProcessInstantTrack(
594 *upid_);
595 legacy_passthrough_utid_ = utid_;
596 utid_ = std::nullopt;
597 break;
598 }
599 break;
600 }
601 default:
602 break;
603 }
604
605 return util::OkStatus();
606 }
607
ParsePhaseOrType()608 int32_t ParsePhaseOrType() {
609 if (legacy_event_.has_phase())
610 return legacy_event_.phase();
611
612 switch (event_.type()) {
613 case TrackEvent::TYPE_SLICE_BEGIN:
614 return utid_ ? 'B' : 'b';
615 case TrackEvent::TYPE_SLICE_END:
616 return utid_ ? 'E' : 'e';
617 case TrackEvent::TYPE_INSTANT:
618 return utid_ ? 'i' : 'n';
619 default:
620 PERFETTO_ELOG("unexpected event type %d", event_.type());
621 return 0;
622 }
623 }
624
ParseCounterEvent()625 void ParseCounterEvent() {
626 // Tokenizer ensures that TYPE_COUNTER events are associated with counter
627 // tracks and have values.
628 PERFETTO_DCHECK(storage_->counter_track_table().id().IndexOf(track_id_));
629 PERFETTO_DCHECK(event_.has_counter_value() ||
630 event_.has_double_counter_value());
631
632 context_->event_tracker->PushCounter(
633 ts_, static_cast<double>(event_data_->counter_value), track_id_);
634 }
635
ParseLegacyThreadTimeAndInstructionsAsCounters()636 void ParseLegacyThreadTimeAndInstructionsAsCounters() {
637 if (!utid_)
638 return;
639 // When these fields are set, we don't expect TrackDescriptor-based counters
640 // for thread time or instruction count for this thread in the trace, so we
641 // intern separate counter tracks based on name + utid. Note that we cannot
642 // import the counter values from the end of a complete event, because the
643 // EventTracker expects counters to be pushed in order of their timestamps.
644 // One more reason to switch to split begin/end events.
645 if (thread_timestamp_) {
646 TrackId track_id = context_->track_tracker->InternThreadCounterTrack(
647 parser_->counter_name_thread_time_id_, *utid_);
648 context_->event_tracker->PushCounter(
649 ts_, static_cast<double>(*thread_timestamp_), track_id);
650 }
651 if (thread_instruction_count_) {
652 TrackId track_id = context_->track_tracker->InternThreadCounterTrack(
653 parser_->counter_name_thread_instruction_count_id_, *utid_);
654 context_->event_tracker->PushCounter(
655 ts_, static_cast<double>(*thread_instruction_count_), track_id);
656 }
657 }
658
ParseExtraCounterValues()659 void ParseExtraCounterValues() {
660 if (!event_.has_extra_counter_values() &&
661 !event_.has_extra_double_counter_values()) {
662 return;
663 }
664
665 // Add integer extra counter values.
666 size_t index = 0;
667 protozero::RepeatedFieldIterator<uint64_t> track_uuid_it;
668 if (event_.has_extra_counter_track_uuids()) {
669 track_uuid_it = event_.extra_counter_track_uuids();
670 } else if (defaults_ && defaults_->has_extra_counter_track_uuids()) {
671 track_uuid_it = defaults_->extra_counter_track_uuids();
672 }
673 for (auto value_it = event_.extra_counter_values(); value_it;
674 ++value_it, ++track_uuid_it, ++index) {
675 AddExtraCounterValue(track_uuid_it, index);
676 }
677
678 // Add double extra counter values.
679 track_uuid_it = protozero::RepeatedFieldIterator<uint64_t>();
680 if (event_.has_extra_double_counter_track_uuids()) {
681 track_uuid_it = event_.extra_double_counter_track_uuids();
682 } else if (defaults_ && defaults_->has_extra_double_counter_track_uuids()) {
683 track_uuid_it = defaults_->extra_double_counter_track_uuids();
684 }
685 for (auto value_it = event_.extra_double_counter_values(); value_it;
686 ++value_it, ++track_uuid_it, ++index) {
687 AddExtraCounterValue(track_uuid_it, index);
688 }
689 }
690
AddExtraCounterValue(protozero::RepeatedFieldIterator<uint64_t> track_uuid_it,size_t index)691 void AddExtraCounterValue(
692 protozero::RepeatedFieldIterator<uint64_t> track_uuid_it,
693 size_t index) {
694 // Tokenizer ensures that there aren't more values than uuids, that we
695 // don't have more values than kMaxNumExtraCounters and that the
696 // track_uuids are for valid counter tracks.
697 PERFETTO_DCHECK(track_uuid_it);
698 PERFETTO_DCHECK(index < TrackEventData::kMaxNumExtraCounters);
699
700 std::optional<TrackId> track_id = track_event_tracker_->GetDescriptorTrack(
701 *track_uuid_it, kNullStringId, packet_sequence_id_);
702 std::optional<uint32_t> counter_row =
703 storage_->counter_track_table().id().IndexOf(*track_id);
704
705 double value = event_data_->extra_counter_values[index];
706 context_->event_tracker->PushCounter(ts_, value, *track_id);
707
708 // Also import thread_time and thread_instruction_count counters into
709 // slice columns to simplify JSON export.
710 StringId counter_name =
711 storage_->counter_track_table().name()[*counter_row];
712 if (counter_name == parser_->counter_name_thread_time_id_) {
713 thread_timestamp_ = static_cast<int64_t>(value);
714 } else if (counter_name ==
715 parser_->counter_name_thread_instruction_count_id_) {
716 thread_instruction_count_ = static_cast<int64_t>(value);
717 }
718 }
719
ParseThreadBeginEvent()720 util::Status ParseThreadBeginEvent() {
721 if (!utid_) {
722 return util::ErrStatus(
723 "TrackEvent with phase B without thread association");
724 }
725
726 auto* thread_slices = storage_->mutable_slice_table();
727 auto opt_slice_id = context_->slice_tracker->BeginTyped(
728 thread_slices, MakeThreadSliceRow(),
729 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
730
731 if (opt_slice_id.has_value()) {
732 MaybeParseFlowEvents(opt_slice_id.value());
733 }
734 return util::OkStatus();
735 }
736
ParseThreadEndEvent()737 util::Status ParseThreadEndEvent() {
738 if (!utid_) {
739 return util::ErrStatus(
740 "TrackEvent with phase E without thread association");
741 }
742 auto opt_slice_id = context_->slice_tracker->End(
743 ts_, track_id_, category_id_, name_id_,
744 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
745 if (!opt_slice_id)
746 return base::OkStatus();
747
748 MaybeParseFlowEvents(*opt_slice_id);
749 auto* thread_slices = storage_->mutable_slice_table();
750 auto opt_thread_slice_ref = thread_slices->FindById(*opt_slice_id);
751 if (!opt_thread_slice_ref) {
752 // This means that the end event did not match a corresponding track event
753 // begin packet so we likely closed the wrong slice. There's not much we
754 // can do about this beyond flag it as a stat.
755 context_->storage->IncrementStats(stats::track_event_thread_invalid_end);
756 return base::OkStatus();
757 }
758
759 tables::SliceTable::RowReference slice_ref = *opt_thread_slice_ref;
760 std::optional<int64_t> tts = slice_ref.thread_ts();
761 if (tts) {
762 PERFETTO_DCHECK(thread_timestamp_);
763 slice_ref.set_thread_dur(*thread_timestamp_ - *tts);
764 }
765 std::optional<int64_t> tic = slice_ref.thread_instruction_count();
766 if (tic) {
767 PERFETTO_DCHECK(event_data_->thread_instruction_count);
768 slice_ref.set_thread_instruction_delta(
769 *event_data_->thread_instruction_count - *tic);
770 }
771 return util::OkStatus();
772 }
773
ParseThreadCompleteEvent()774 util::Status ParseThreadCompleteEvent() {
775 if (!utid_) {
776 return util::ErrStatus(
777 "TrackEvent with phase X without thread association");
778 }
779
780 auto duration_ns = legacy_event_.duration_us() * 1000;
781 if (duration_ns < 0)
782 return util::ErrStatus("TrackEvent with phase X with negative duration");
783
784 auto* thread_slices = storage_->mutable_slice_table();
785 tables::SliceTable::Row row = MakeThreadSliceRow();
786 row.dur = duration_ns;
787 if (legacy_event_.has_thread_duration_us()) {
788 row.thread_dur = legacy_event_.thread_duration_us() * 1000;
789 }
790 if (legacy_event_.has_thread_instruction_delta()) {
791 row.thread_instruction_delta = legacy_event_.thread_instruction_delta();
792 }
793 auto opt_slice_id = context_->slice_tracker->ScopedTyped(
794 thread_slices, std::move(row),
795 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
796
797 if (opt_slice_id.has_value()) {
798 MaybeParseFlowEvents(opt_slice_id.value());
799 }
800 return util::OkStatus();
801 }
802
GetLegacyEventId()803 std::optional<uint64_t> GetLegacyEventId() {
804 if (legacy_event_.has_unscoped_id())
805 return legacy_event_.unscoped_id();
806 // TODO(andrewbb): Catapult doesn't support global_id and local_id on flow
807 // events. We could add support in trace processor (e.g. because there seem
808 // to be some callsites supplying local_id in chromium), but we would have
809 // to consider the process ID for local IDs and use a separate ID scope for
810 // global_id and unscoped_id.
811 return std::nullopt;
812 }
813
ParseFlowEventV1(char phase)814 util::Status ParseFlowEventV1(char phase) {
815 auto opt_source_id = GetLegacyEventId();
816 if (!opt_source_id) {
817 storage_->IncrementStats(stats::flow_invalid_id);
818 return util::ErrStatus("Invalid id for flow event v1");
819 }
820 FlowId flow_id = context_->flow_tracker->GetFlowIdForV1Event(
821 opt_source_id.value(), category_id_, name_id_);
822 switch (phase) {
823 case 's':
824 context_->flow_tracker->Begin(track_id_, flow_id);
825 break;
826 case 't':
827 context_->flow_tracker->Step(track_id_, flow_id);
828 break;
829 case 'f':
830 context_->flow_tracker->End(track_id_, flow_id,
831 legacy_event_.bind_to_enclosing(),
832 /* close_flow = */ false);
833 break;
834 }
835 return util::OkStatus();
836 }
837
MaybeParseTrackEventFlows(SliceId slice_id)838 void MaybeParseTrackEventFlows(SliceId slice_id) {
839 if (event_.has_flow_ids_old() || event_.has_flow_ids()) {
840 auto it =
841 event_.has_flow_ids() ? event_.flow_ids() : event_.flow_ids_old();
842 for (; it; ++it) {
843 FlowId flow_id = *it;
844 if (!context_->flow_tracker->IsActive(flow_id)) {
845 context_->flow_tracker->Begin(slice_id, flow_id);
846 continue;
847 }
848 context_->flow_tracker->Step(slice_id, flow_id);
849 }
850 }
851 if (event_.has_terminating_flow_ids_old() ||
852 event_.has_terminating_flow_ids()) {
853 auto it = event_.has_terminating_flow_ids()
854 ? event_.terminating_flow_ids()
855 : event_.terminating_flow_ids_old();
856 for (; it; ++it) {
857 FlowId flow_id = *it;
858 if (!context_->flow_tracker->IsActive(flow_id)) {
859 // If we should terminate a flow, do not begin a new one if it's not
860 // active already.
861 continue;
862 }
863 context_->flow_tracker->End(slice_id, flow_id,
864 /* close_flow = */ true);
865 }
866 }
867 }
868
MaybeParseFlowEventV2(SliceId slice_id)869 void MaybeParseFlowEventV2(SliceId slice_id) {
870 if (!legacy_event_.has_bind_id()) {
871 return;
872 }
873 if (!legacy_event_.has_flow_direction()) {
874 storage_->IncrementStats(stats::flow_without_direction);
875 return;
876 }
877
878 auto bind_id = legacy_event_.bind_id();
879 switch (legacy_event_.flow_direction()) {
880 case LegacyEvent::FLOW_OUT:
881 context_->flow_tracker->Begin(slice_id, bind_id);
882 break;
883 case LegacyEvent::FLOW_INOUT:
884 context_->flow_tracker->Step(slice_id, bind_id);
885 break;
886 case LegacyEvent::FLOW_IN:
887 context_->flow_tracker->End(slice_id, bind_id,
888 /* close_flow = */ false);
889 break;
890 default:
891 storage_->IncrementStats(stats::flow_without_direction);
892 }
893 }
894
MaybeParseFlowEvents(SliceId slice_id)895 void MaybeParseFlowEvents(SliceId slice_id) {
896 MaybeParseFlowEventV2(slice_id);
897 MaybeParseTrackEventFlows(slice_id);
898 }
899
ParseThreadInstantEvent(char phase)900 util::Status ParseThreadInstantEvent(char phase) {
901 // Handle instant events as slices with zero duration, so that they end
902 // up nested underneath their parent slices.
903 int64_t duration_ns = 0;
904 int64_t tidelta = 0;
905 std::optional<tables::SliceTable::Id> opt_slice_id;
906 auto args_inserter = [this, phase](BoundInserter* inserter) {
907 ParseTrackEventArgs(inserter);
908 // For legacy MARK event, add phase for JSON exporter.
909 if (phase == 'R') {
910 std::string phase_string(1, static_cast<char>(phase));
911 StringId phase_id = storage_->InternString(phase_string.c_str());
912 inserter->AddArg(parser_->legacy_event_phase_key_id_,
913 Variadic::String(phase_id));
914 }
915 };
916 if (utid_) {
917 auto* thread_slices = storage_->mutable_slice_table();
918 tables::SliceTable::Row row = MakeThreadSliceRow();
919 row.dur = duration_ns;
920 if (thread_timestamp_) {
921 row.thread_dur = duration_ns;
922 }
923 if (thread_instruction_count_) {
924 row.thread_instruction_delta = tidelta;
925 }
926 opt_slice_id = context_->slice_tracker->ScopedTyped(
927 thread_slices, row, std::move(args_inserter));
928 } else {
929 opt_slice_id = context_->slice_tracker->Scoped(
930 ts_, track_id_, category_id_, name_id_, duration_ns,
931 std::move(args_inserter));
932 }
933 if (!opt_slice_id.has_value()) {
934 return util::OkStatus();
935 }
936 MaybeParseFlowEvents(opt_slice_id.value());
937 return util::OkStatus();
938 }
939
ParseAsyncBeginEvent(char phase)940 util::Status ParseAsyncBeginEvent(char phase) {
941 auto args_inserter = [this, phase](BoundInserter* inserter) {
942 ParseTrackEventArgs(inserter);
943
944 if (phase == 'b')
945 return;
946 PERFETTO_DCHECK(phase == 'S');
947 // For legacy ASYNC_BEGIN, add phase for JSON exporter.
948 std::string phase_string(1, static_cast<char>(phase));
949 StringId phase_id = storage_->InternString(phase_string.c_str());
950 inserter->AddArg(parser_->legacy_event_phase_key_id_,
951 Variadic::String(phase_id));
952 };
953 auto opt_slice_id = context_->slice_tracker->Begin(
954 ts_, track_id_, category_id_, name_id_, args_inserter);
955 if (!opt_slice_id.has_value()) {
956 return util::OkStatus();
957 }
958 MaybeParseFlowEvents(opt_slice_id.value());
959 // For the time being, we only create vtrack slice rows if we need to
960 // store thread timestamps/counters.
961 if (legacy_event_.use_async_tts()) {
962 auto* vtrack_slices = storage_->mutable_virtual_track_slices();
963 PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
964 vtrack_slices->slice_ids().back() < opt_slice_id.value());
965 int64_t tts = thread_timestamp_.value_or(0);
966 int64_t tic = thread_instruction_count_.value_or(0);
967 vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
968 kPendingThreadDuration, tic,
969 kPendingThreadInstructionDelta);
970 }
971 return util::OkStatus();
972 }
973
ParseAsyncEndEvent()974 util::Status ParseAsyncEndEvent() {
975 auto opt_slice_id = context_->slice_tracker->End(
976 ts_, track_id_, category_id_, name_id_,
977 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
978 if (!opt_slice_id)
979 return base::OkStatus();
980
981 MaybeParseFlowEvents(*opt_slice_id);
982 if (legacy_event_.use_async_tts()) {
983 auto* vtrack_slices = storage_->mutable_virtual_track_slices();
984 int64_t tts = event_data_->thread_timestamp.value_or(0);
985 int64_t tic = event_data_->thread_instruction_count.value_or(0);
986 vtrack_slices->UpdateThreadDeltasForSliceId(*opt_slice_id, tts, tic);
987 }
988 return util::OkStatus();
989 }
990
ParseAsyncStepEvent(char phase)991 util::Status ParseAsyncStepEvent(char phase) {
992 // Parse step events as instant events. Reconstructing the begin/end times
993 // of the child slice would be too complicated, see b/178540838. For JSON
994 // export, we still record the original step's phase in an arg.
995 int64_t duration_ns = 0;
996 context_->slice_tracker->Scoped(
997 ts_, track_id_, category_id_, name_id_, duration_ns,
998 [this, phase](BoundInserter* inserter) {
999 ParseTrackEventArgs(inserter);
1000
1001 PERFETTO_DCHECK(phase == 'T' || phase == 'p');
1002 std::string phase_string(1, static_cast<char>(phase));
1003 StringId phase_id = storage_->InternString(phase_string.c_str());
1004 inserter->AddArg(parser_->legacy_event_phase_key_id_,
1005 Variadic::String(phase_id));
1006 });
1007 // Step events don't support thread timestamps, so no need to add a row to
1008 // virtual_track_slices.
1009 return util::OkStatus();
1010 }
1011
ParseAsyncInstantEvent()1012 util::Status ParseAsyncInstantEvent() {
1013 // Handle instant events as slices with zero duration, so that they end
1014 // up nested underneath their parent slices.
1015 int64_t duration_ns = 0;
1016 int64_t tidelta = 0;
1017 auto opt_slice_id = context_->slice_tracker->Scoped(
1018 ts_, track_id_, category_id_, name_id_, duration_ns,
1019 [this](BoundInserter* inserter) { ParseTrackEventArgs(inserter); });
1020 if (!opt_slice_id.has_value()) {
1021 return util::OkStatus();
1022 }
1023 MaybeParseFlowEvents(opt_slice_id.value());
1024 if (legacy_event_.use_async_tts()) {
1025 auto* vtrack_slices = storage_->mutable_virtual_track_slices();
1026 PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
1027 vtrack_slices->slice_ids().back() < opt_slice_id.value());
1028 int64_t tts = thread_timestamp_.value_or(0);
1029 int64_t tic = thread_instruction_count_.value_or(0);
1030 vtrack_slices->AddVirtualTrackSlice(opt_slice_id.value(), tts,
1031 duration_ns, tic, tidelta);
1032 }
1033 return util::OkStatus();
1034 }
1035
ParseMetadataEvent()1036 util::Status ParseMetadataEvent() {
1037 ProcessTracker* procs = context_->process_tracker.get();
1038
1039 if (name_id_ == kNullStringId)
1040 return util::ErrStatus("Metadata event without name");
1041
1042 // Parse process and thread names from correspondingly named events.
1043 NullTermStringView event_name = storage_->GetString(name_id_);
1044 PERFETTO_DCHECK(event_name.data());
1045 if (strcmp(event_name.c_str(), "thread_name") == 0) {
1046 if (!utid_) {
1047 return util::ErrStatus(
1048 "thread_name metadata event without thread association");
1049 }
1050
1051 auto it = event_.debug_annotations();
1052 if (!it) {
1053 return util::ErrStatus(
1054 "thread_name metadata event without debug annotations");
1055 }
1056 protos::pbzero::DebugAnnotation::Decoder annotation(*it);
1057 auto thread_name = annotation.string_value();
1058 if (!thread_name.size)
1059 return util::OkStatus();
1060 auto thread_name_id = storage_->InternString(thread_name);
1061 procs->UpdateThreadNameByUtid(
1062 *utid_, thread_name_id,
1063 ThreadNamePriority::kTrackDescriptorThreadType);
1064 return util::OkStatus();
1065 }
1066 if (strcmp(event_name.c_str(), "process_name") == 0) {
1067 if (!upid_) {
1068 return util::ErrStatus(
1069 "process_name metadata event without process association");
1070 }
1071
1072 auto it = event_.debug_annotations();
1073 if (!it) {
1074 return util::ErrStatus(
1075 "process_name metadata event without debug annotations");
1076 }
1077 protos::pbzero::DebugAnnotation::Decoder annotation(*it);
1078 auto process_name = annotation.string_value();
1079 if (!process_name.size)
1080 return util::OkStatus();
1081 auto process_name_id =
1082 storage_->InternString(base::StringView(process_name));
1083 // Don't override system-provided names.
1084 procs->SetProcessNameIfUnset(*upid_, process_name_id);
1085 return util::OkStatus();
1086 }
1087 // Other metadata events are proxied via the raw table for JSON export.
1088 ParseLegacyEventAsRawEvent();
1089 return util::OkStatus();
1090 }
1091
ParseLegacyEventAsRawEvent()1092 util::Status ParseLegacyEventAsRawEvent() {
1093 if (!utid_)
1094 return util::ErrStatus("raw legacy event without thread association");
1095
1096 RawId id = storage_->mutable_raw_table()
1097 ->Insert({ts_, parser_->raw_legacy_event_id_, 0, *utid_})
1098 .id;
1099
1100 auto inserter = context_->args_tracker->AddArgsTo(id);
1101 inserter
1102 .AddArg(parser_->legacy_event_category_key_id_,
1103 Variadic::String(category_id_))
1104 .AddArg(parser_->legacy_event_name_key_id_, Variadic::String(name_id_));
1105
1106 std::string phase_string(1, static_cast<char>(legacy_event_.phase()));
1107 StringId phase_id = storage_->InternString(phase_string.c_str());
1108 inserter.AddArg(parser_->legacy_event_phase_key_id_,
1109 Variadic::String(phase_id));
1110
1111 if (legacy_event_.has_duration_us()) {
1112 inserter.AddArg(parser_->legacy_event_duration_ns_key_id_,
1113 Variadic::Integer(legacy_event_.duration_us() * 1000));
1114 }
1115
1116 if (thread_timestamp_) {
1117 inserter.AddArg(parser_->legacy_event_thread_timestamp_ns_key_id_,
1118 Variadic::Integer(*thread_timestamp_));
1119 if (legacy_event_.has_thread_duration_us()) {
1120 inserter.AddArg(
1121 parser_->legacy_event_thread_duration_ns_key_id_,
1122 Variadic::Integer(legacy_event_.thread_duration_us() * 1000));
1123 }
1124 }
1125
1126 if (thread_instruction_count_) {
1127 inserter.AddArg(parser_->legacy_event_thread_instruction_count_key_id_,
1128 Variadic::Integer(*thread_instruction_count_));
1129 if (legacy_event_.has_thread_instruction_delta()) {
1130 inserter.AddArg(
1131 parser_->legacy_event_thread_instruction_delta_key_id_,
1132 Variadic::Integer(legacy_event_.thread_instruction_delta()));
1133 }
1134 }
1135
1136 if (legacy_event_.use_async_tts()) {
1137 inserter.AddArg(parser_->legacy_event_use_async_tts_key_id_,
1138 Variadic::Boolean(true));
1139 }
1140
1141 bool has_id = false;
1142 if (legacy_event_.has_unscoped_id()) {
1143 // Unscoped ids are either global or local depending on the phase. Pass
1144 // them through as unscoped IDs to JSON export to preserve this behavior.
1145 inserter.AddArg(parser_->legacy_event_unscoped_id_key_id_,
1146 Variadic::UnsignedInteger(legacy_event_.unscoped_id()));
1147 has_id = true;
1148 } else if (legacy_event_.has_global_id()) {
1149 inserter.AddArg(parser_->legacy_event_global_id_key_id_,
1150 Variadic::UnsignedInteger(legacy_event_.global_id()));
1151 has_id = true;
1152 } else if (legacy_event_.has_local_id()) {
1153 inserter.AddArg(parser_->legacy_event_local_id_key_id_,
1154 Variadic::UnsignedInteger(legacy_event_.local_id()));
1155 has_id = true;
1156 }
1157
1158 if (has_id && legacy_event_.has_id_scope() &&
1159 legacy_event_.id_scope().size) {
1160 inserter.AddArg(
1161 parser_->legacy_event_id_scope_key_id_,
1162 Variadic::String(storage_->InternString(legacy_event_.id_scope())));
1163 }
1164
1165 // No need to parse legacy_event.instant_event_scope() because we import
1166 // instant events into the slice table.
1167
1168 ParseTrackEventArgs(&inserter);
1169 return util::OkStatus();
1170 }
1171
ParseTrackEventArgs(BoundInserter * inserter)1172 void ParseTrackEventArgs(BoundInserter* inserter) {
1173 auto log_errors = [this](util::Status status) {
1174 if (status.ok())
1175 return;
1176 // Log error but continue parsing the other args.
1177 storage_->IncrementStats(stats::track_event_parser_errors);
1178 PERFETTO_DLOG("ParseTrackEventArgs error: %s", status.c_message());
1179 };
1180
1181 if (event_.has_source_location_iid()) {
1182 log_errors(AddSourceLocationArgs(event_.source_location_iid(), inserter));
1183 }
1184
1185 if (event_.has_task_execution()) {
1186 log_errors(ParseTaskExecutionArgs(event_.task_execution(), inserter));
1187 }
1188 if (event_.has_log_message()) {
1189 log_errors(ParseLogMessage(event_.log_message(), inserter));
1190 }
1191 if (event_.has_chrome_histogram_sample()) {
1192 log_errors(
1193 ParseHistogramName(event_.chrome_histogram_sample(), inserter));
1194 }
1195 if (event_.has_chrome_active_processes()) {
1196 protos::pbzero::ChromeActiveProcesses::Decoder message(
1197 event_.chrome_active_processes());
1198 for (auto it = message.pid(); it; ++it) {
1199 parser_->AddActiveProcess(ts_, *it);
1200 }
1201 }
1202
1203 TrackEventArgsParser args_writer(ts_, *inserter, *storage_,
1204 *sequence_state_);
1205 int unknown_extensions = 0;
1206 log_errors(parser_->args_parser_.ParseMessage(
1207 blob_, ".perfetto.protos.TrackEvent", &parser_->reflect_fields_,
1208 args_writer, &unknown_extensions));
1209 if (unknown_extensions > 0) {
1210 context_->storage->IncrementStats(stats::unknown_extension_fields,
1211 unknown_extensions);
1212 }
1213
1214 {
1215 auto key = parser_->args_parser_.EnterDictionary("debug");
1216 util::DebugAnnotationParser parser(parser_->args_parser_);
1217 for (auto it = event_.debug_annotations(); it; ++it) {
1218 log_errors(parser.Parse(*it, args_writer));
1219 }
1220 }
1221
1222 if (legacy_passthrough_utid_) {
1223 inserter->AddArg(parser_->legacy_event_passthrough_utid_id_,
1224 Variadic::UnsignedInteger(*legacy_passthrough_utid_),
1225 ArgsTracker::UpdatePolicy::kSkipIfExists);
1226 }
1227 }
1228
ParseTaskExecutionArgs(ConstBytes task_execution,BoundInserter * inserter)1229 util::Status ParseTaskExecutionArgs(ConstBytes task_execution,
1230 BoundInserter* inserter) {
1231 protos::pbzero::TaskExecution::Decoder task(task_execution);
1232 uint64_t iid = task.posted_from_iid();
1233 if (!iid)
1234 return util::ErrStatus("TaskExecution with invalid posted_from_iid");
1235
1236 auto* decoder = sequence_state_->LookupInternedMessage<
1237 protos::pbzero::InternedData::kSourceLocationsFieldNumber,
1238 protos::pbzero::SourceLocation>(iid);
1239 if (!decoder)
1240 return util::ErrStatus("TaskExecution with invalid posted_from_iid");
1241
1242 StringId file_name_id = kNullStringId;
1243 StringId function_name_id = kNullStringId;
1244 uint32_t line_number = 0;
1245
1246 std::string file_name = NormalizePathSeparators(decoder->file_name());
1247 file_name_id = storage_->InternString(base::StringView(file_name));
1248 function_name_id = storage_->InternString(decoder->function_name());
1249 line_number = decoder->line_number();
1250
1251 inserter->AddArg(parser_->task_file_name_args_key_id_,
1252 Variadic::String(file_name_id));
1253 inserter->AddArg(parser_->task_function_name_args_key_id_,
1254 Variadic::String(function_name_id));
1255 inserter->AddArg(parser_->task_line_number_args_key_id_,
1256 Variadic::UnsignedInteger(line_number));
1257 return util::OkStatus();
1258 }
1259
AddSourceLocationArgs(uint64_t iid,BoundInserter * inserter)1260 util::Status AddSourceLocationArgs(uint64_t iid, BoundInserter* inserter) {
1261 if (!iid)
1262 return util::ErrStatus("SourceLocation with invalid iid");
1263
1264 auto* decoder = sequence_state_->LookupInternedMessage<
1265 protos::pbzero::InternedData::kSourceLocationsFieldNumber,
1266 protos::pbzero::SourceLocation>(iid);
1267 if (!decoder)
1268 return util::ErrStatus("SourceLocation with invalid iid");
1269
1270 StringId file_name_id = kNullStringId;
1271 StringId function_name_id = kNullStringId;
1272 uint32_t line_number = 0;
1273
1274 std::string file_name = NormalizePathSeparators(decoder->file_name());
1275 file_name_id = storage_->InternString(base::StringView(file_name));
1276 function_name_id = storage_->InternString(decoder->function_name());
1277 line_number = decoder->line_number();
1278
1279 inserter->AddArg(parser_->source_location_file_name_key_id_,
1280 Variadic::String(file_name_id));
1281 inserter->AddArg(parser_->source_location_function_name_key_id_,
1282 Variadic::String(function_name_id));
1283 inserter->AddArg(parser_->source_location_line_number_key_id_,
1284 Variadic::UnsignedInteger(line_number));
1285 return util::OkStatus();
1286 }
1287
ParseLogMessage(ConstBytes blob,BoundInserter * inserter)1288 util::Status ParseLogMessage(ConstBytes blob, BoundInserter* inserter) {
1289 if (!utid_)
1290 return util::ErrStatus("LogMessage without thread association");
1291
1292 protos::pbzero::LogMessage::Decoder message(blob);
1293
1294 auto* body_decoder = sequence_state_->LookupInternedMessage<
1295 protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
1296 protos::pbzero::LogMessageBody>(message.body_iid());
1297 if (!body_decoder)
1298 return util::ErrStatus("LogMessage with invalid body_iid");
1299
1300 const StringId log_message_id =
1301 storage_->InternString(body_decoder->body());
1302 inserter->AddArg(parser_->log_message_body_key_id_,
1303 Variadic::String(log_message_id));
1304
1305 StringId source_location_id = kNullStringId;
1306 if (message.has_source_location_iid()) {
1307 auto* source_location_decoder = sequence_state_->LookupInternedMessage<
1308 protos::pbzero::InternedData::kSourceLocationsFieldNumber,
1309 protos::pbzero::SourceLocation>(message.source_location_iid());
1310 if (!source_location_decoder)
1311 return util::ErrStatus("LogMessage with invalid source_location_iid");
1312 const std::string source_location =
1313 source_location_decoder->file_name().ToStdString() + ":" +
1314 std::to_string(source_location_decoder->line_number());
1315 source_location_id =
1316 storage_->InternString(base::StringView(source_location));
1317
1318 inserter->AddArg(parser_->log_message_source_location_file_name_key_id_,
1319 Variadic::String(storage_->InternString(
1320 source_location_decoder->file_name())));
1321 inserter->AddArg(
1322 parser_->log_message_source_location_function_name_key_id_,
1323 Variadic::String(storage_->InternString(
1324 source_location_decoder->function_name())));
1325 inserter->AddArg(
1326 parser_->log_message_source_location_line_number_key_id_,
1327 Variadic::Integer(source_location_decoder->line_number()));
1328 }
1329
1330 storage_->mutable_android_log_table()->Insert(
1331 {ts_, *utid_,
1332 /*priority*/ 0,
1333 /*tag_id*/ source_location_id, log_message_id});
1334
1335 return util::OkStatus();
1336 }
1337
ParseHistogramName(ConstBytes blob,BoundInserter * inserter)1338 util::Status ParseHistogramName(ConstBytes blob, BoundInserter* inserter) {
1339 protos::pbzero::ChromeHistogramSample::Decoder sample(blob);
1340 if (!sample.has_name_iid())
1341 return util::OkStatus();
1342
1343 if (sample.has_name()) {
1344 return util::ErrStatus(
1345 "name is already set for ChromeHistogramSample: only one of name and "
1346 "name_iid can be set.");
1347 }
1348
1349 auto* decoder = sequence_state_->LookupInternedMessage<
1350 protos::pbzero::InternedData::kHistogramNamesFieldNumber,
1351 protos::pbzero::HistogramName>(sample.name_iid());
1352 if (!decoder)
1353 return util::ErrStatus("HistogramName with invalid name_iid");
1354
1355 inserter->AddArg(parser_->histogram_name_key_id_,
1356 Variadic::String(storage_->InternString(decoder->name())));
1357 return util::OkStatus();
1358 }
1359
MakeThreadSliceRow()1360 tables::SliceTable::Row MakeThreadSliceRow() {
1361 tables::SliceTable::Row row;
1362 row.ts = ts_;
1363 row.track_id = track_id_;
1364 row.category = category_id_;
1365 row.name = name_id_;
1366 row.thread_ts = thread_timestamp_;
1367 row.thread_dur = std::nullopt;
1368 row.thread_instruction_count = thread_instruction_count_;
1369 row.thread_instruction_delta = std::nullopt;
1370 return row;
1371 }
1372
1373 TraceProcessorContext* context_;
1374 TrackEventTracker* track_event_tracker_;
1375 TraceStorage* storage_;
1376 TrackEventParser* parser_;
1377 ArgsTranslationTable* args_translation_table_;
1378 int64_t ts_;
1379 const TrackEventData* event_data_;
1380 PacketSequenceStateGeneration* sequence_state_;
1381 ConstBytes blob_;
1382 TrackEvent::Decoder event_;
1383 LegacyEvent::Decoder legacy_event_;
1384 protos::pbzero::TrackEventDefaults::Decoder* defaults_;
1385
1386 // Importing state.
1387 StringId category_id_;
1388 StringId name_id_;
1389 uint64_t track_uuid_;
1390 TrackId track_id_;
1391 std::optional<UniqueTid> utid_;
1392 std::optional<UniqueTid> upid_;
1393 std::optional<int64_t> thread_timestamp_;
1394 std::optional<int64_t> thread_instruction_count_;
1395 // All events in legacy JSON require a thread ID, but for some types of
1396 // events (e.g. async events or process/global-scoped instants), we don't
1397 // store it in the slice/track model. To pass the utid through to the json
1398 // export, we store it in an arg.
1399 std::optional<UniqueTid> legacy_passthrough_utid_;
1400
1401 uint32_t packet_sequence_id_;
1402 };
1403
TrackEventParser(TraceProcessorContext * context,TrackEventTracker * track_event_tracker)1404 TrackEventParser::TrackEventParser(TraceProcessorContext* context,
1405 TrackEventTracker* track_event_tracker)
1406 : args_parser_(*context->descriptor_pool_.get()),
1407 context_(context),
1408 track_event_tracker_(track_event_tracker),
1409 counter_name_thread_time_id_(
1410 context->storage->InternString("thread_time")),
1411 counter_name_thread_instruction_count_id_(
1412 context->storage->InternString("thread_instruction_count")),
1413 task_file_name_args_key_id_(
1414 context->storage->InternString("task.posted_from.file_name")),
1415 task_function_name_args_key_id_(
1416 context->storage->InternString("task.posted_from.function_name")),
1417 task_line_number_args_key_id_(
1418 context->storage->InternString("task.posted_from.line_number")),
1419 log_message_body_key_id_(
1420 context->storage->InternString("track_event.log_message")),
1421 log_message_source_location_function_name_key_id_(
1422 context->storage->InternString(
1423 "track_event.log_message.function_name")),
1424 log_message_source_location_file_name_key_id_(
1425 context->storage->InternString("track_event.log_message.file_name")),
1426 log_message_source_location_line_number_key_id_(
1427 context->storage->InternString(
1428 "track_event.log_message.line_number")),
1429 source_location_function_name_key_id_(
1430 context->storage->InternString("source.function_name")),
1431 source_location_file_name_key_id_(
1432 context->storage->InternString("source.file_name")),
1433 source_location_line_number_key_id_(
1434 context->storage->InternString("source.line_number")),
1435 raw_legacy_event_id_(
1436 context->storage->InternString("track_event.legacy_event")),
1437 legacy_event_passthrough_utid_id_(
1438 context->storage->InternString("legacy_event.passthrough_utid")),
1439 legacy_event_category_key_id_(
1440 context->storage->InternString("legacy_event.category")),
1441 legacy_event_name_key_id_(
1442 context->storage->InternString("legacy_event.name")),
1443 legacy_event_phase_key_id_(
1444 context->storage->InternString("legacy_event.phase")),
1445 legacy_event_duration_ns_key_id_(
1446 context->storage->InternString("legacy_event.duration_ns")),
1447 legacy_event_thread_timestamp_ns_key_id_(
1448 context->storage->InternString("legacy_event.thread_timestamp_ns")),
1449 legacy_event_thread_duration_ns_key_id_(
1450 context->storage->InternString("legacy_event.thread_duration_ns")),
1451 legacy_event_thread_instruction_count_key_id_(
1452 context->storage->InternString(
1453 "legacy_event.thread_instruction_count")),
1454 legacy_event_thread_instruction_delta_key_id_(
1455 context->storage->InternString(
1456 "legacy_event.thread_instruction_delta")),
1457 legacy_event_use_async_tts_key_id_(
1458 context->storage->InternString("legacy_event.use_async_tts")),
1459 legacy_event_unscoped_id_key_id_(
1460 context->storage->InternString("legacy_event.unscoped_id")),
1461 legacy_event_global_id_key_id_(
1462 context->storage->InternString("legacy_event.global_id")),
1463 legacy_event_local_id_key_id_(
1464 context->storage->InternString("legacy_event.local_id")),
1465 legacy_event_id_scope_key_id_(
1466 context->storage->InternString("legacy_event.id_scope")),
1467 legacy_event_bind_id_key_id_(
1468 context->storage->InternString("legacy_event.bind_id")),
1469 legacy_event_bind_to_enclosing_key_id_(
1470 context->storage->InternString("legacy_event.bind_to_enclosing")),
1471 legacy_event_flow_direction_key_id_(
1472 context->storage->InternString("legacy_event.flow_direction")),
1473 histogram_name_key_id_(
1474 context->storage->InternString("chrome_histogram_sample.name")),
1475 flow_direction_value_in_id_(context->storage->InternString("in")),
1476 flow_direction_value_out_id_(context->storage->InternString("out")),
1477 flow_direction_value_inout_id_(context->storage->InternString("inout")),
1478 chrome_legacy_ipc_class_args_key_id_(
1479 context->storage->InternString("legacy_ipc.class")),
1480 chrome_legacy_ipc_line_args_key_id_(
1481 context->storage->InternString("legacy_ipc.line")),
1482 chrome_host_app_package_name_id_(
1483 context->storage->InternString("chrome.host_app_package_name")),
1484 chrome_crash_trace_id_name_id_(
1485 context->storage->InternString("chrome.crash_trace_id")),
1486 chrome_process_label_flat_key_id_(
1487 context->storage->InternString("chrome.process_label")),
1488 chrome_process_type_id_(
1489 context_->storage->InternString("chrome.process_type")),
1490 event_category_key_id_(context_->storage->InternString("event.category")),
1491 event_name_key_id_(context_->storage->InternString("event.name")),
1492 chrome_string_lookup_(context->storage.get()),
1493 counter_unit_ids_{{kNullStringId, context_->storage->InternString("ns"),
1494 context_->storage->InternString("count"),
1495 context_->storage->InternString("bytes")}},
1496 active_chrome_processes_tracker_(context) {
1497 args_parser_.AddParsingOverrideForField(
1498 "chrome_mojo_event_info.mojo_interface_method_iid",
1499 [](const protozero::Field& field,
__anon79793c0f0b02(const protozero::Field& field, util::ProtoToArgsParser::Delegate& delegate) 1500 util::ProtoToArgsParser::Delegate& delegate) {
1501 return MaybeParseUnsymbolizedSourceLocation(
1502 "chrome_mojo_event_info.mojo_interface_method.native_symbol", field,
1503 delegate);
1504 });
1505 // Switch |source_location_iid| into its interned data variant.
1506 args_parser_.AddParsingOverrideForField(
1507 "begin_impl_frame_args.current_args.source_location_iid",
1508 [](const protozero::Field& field,
__anon79793c0f0c02(const protozero::Field& field, util::ProtoToArgsParser::Delegate& delegate) 1509 util::ProtoToArgsParser::Delegate& delegate) {
1510 return MaybeParseSourceLocation("begin_impl_frame_args.current_args",
1511 field, delegate);
1512 });
1513 args_parser_.AddParsingOverrideForField(
1514 "begin_impl_frame_args.last_args.source_location_iid",
1515 [](const protozero::Field& field,
__anon79793c0f0d02(const protozero::Field& field, util::ProtoToArgsParser::Delegate& delegate) 1516 util::ProtoToArgsParser::Delegate& delegate) {
1517 return MaybeParseSourceLocation("begin_impl_frame_args.last_args",
1518 field, delegate);
1519 });
1520 args_parser_.AddParsingOverrideForField(
1521 "begin_frame_observer_state.last_begin_frame_args.source_location_iid",
1522 [](const protozero::Field& field,
__anon79793c0f0e02(const protozero::Field& field, util::ProtoToArgsParser::Delegate& delegate) 1523 util::ProtoToArgsParser::Delegate& delegate) {
1524 return MaybeParseSourceLocation(
1525 "begin_frame_observer_state.last_begin_frame_args", field,
1526 delegate);
1527 });
1528 args_parser_.AddParsingOverrideForField(
1529 "chrome_memory_pressure_notification.creation_location_iid",
1530 [](const protozero::Field& field,
__anon79793c0f0f02(const protozero::Field& field, util::ProtoToArgsParser::Delegate& delegate) 1531 util::ProtoToArgsParser::Delegate& delegate) {
1532 return MaybeParseSourceLocation("chrome_memory_pressure_notification",
1533 field, delegate);
1534 });
1535
1536 // Parse DebugAnnotations.
1537 args_parser_.AddParsingOverrideForType(
1538 ".perfetto.protos.DebugAnnotation",
1539 [&](util::ProtoToArgsParser::ScopedNestedKeyContext& key,
1540 const protozero::ConstBytes& data,
__anon79793c0f1002(util::ProtoToArgsParser::ScopedNestedKeyContext& key, const protozero::ConstBytes& data, util::ProtoToArgsParser::Delegate& delegate) 1541 util::ProtoToArgsParser::Delegate& delegate) {
1542 // Do not add "debug_annotations" to the final key.
1543 key.RemoveFieldSuffix();
1544 util::DebugAnnotationParser annotation_parser(args_parser_);
1545 return annotation_parser.Parse(data, delegate);
1546 });
1547
1548 args_parser_.AddParsingOverrideForField(
1549 "active_processes.pid", [&](const protozero::Field& field,
__anon79793c0f1102(const protozero::Field& field, util::ProtoToArgsParser::Delegate& delegate) 1550 util::ProtoToArgsParser::Delegate& delegate) {
1551 AddActiveProcess(delegate.packet_timestamp(), field.as_int32());
1552 // Fallthrough so that the parser adds pid as a regular arg.
1553 return std::nullopt;
1554 });
1555
1556 for (uint16_t index : kReflectFields) {
1557 reflect_fields_.push_back(index);
1558 }
1559 }
1560
ParseTrackDescriptor(int64_t packet_timestamp,protozero::ConstBytes track_descriptor,uint32_t packet_sequence_id)1561 void TrackEventParser::ParseTrackDescriptor(
1562 int64_t packet_timestamp,
1563 protozero::ConstBytes track_descriptor,
1564 uint32_t packet_sequence_id) {
1565 protos::pbzero::TrackDescriptor::Decoder decoder(track_descriptor);
1566
1567 // Ensure that the track and its parents are resolved. This may start a new
1568 // process and/or thread (i.e. new upid/utid).
1569 TrackId track_id = *track_event_tracker_->GetDescriptorTrack(
1570 decoder.uuid(), kNullStringId, packet_sequence_id);
1571
1572 if (decoder.has_thread()) {
1573 UniqueTid utid = ParseThreadDescriptor(decoder.thread());
1574 if (decoder.has_chrome_thread())
1575 ParseChromeThreadDescriptor(utid, decoder.chrome_thread());
1576 } else if (decoder.has_process()) {
1577 UniquePid upid =
1578 ParseProcessDescriptor(packet_timestamp, decoder.process());
1579 if (decoder.has_chrome_process())
1580 ParseChromeProcessDescriptor(upid, decoder.chrome_process());
1581 } else if (decoder.has_counter()) {
1582 ParseCounterDescriptor(track_id, decoder.counter());
1583 }
1584
1585 // Override the name with the most recent name seen (after sorting by ts).
1586 if (decoder.has_name()) {
1587 auto* tracks = context_->storage->mutable_track_table();
1588 StringId name_id = context_->storage->InternString(decoder.name());
1589 tracks->mutable_name()->Set(*tracks->id().IndexOf(track_id), name_id);
1590 }
1591 }
1592
ParseProcessDescriptor(int64_t packet_timestamp,protozero::ConstBytes process_descriptor)1593 UniquePid TrackEventParser::ParseProcessDescriptor(
1594 int64_t packet_timestamp,
1595 protozero::ConstBytes process_descriptor) {
1596 protos::pbzero::ProcessDescriptor::Decoder decoder(process_descriptor);
1597 UniquePid upid = context_->process_tracker->GetOrCreateProcess(
1598 static_cast<uint32_t>(decoder.pid()));
1599 active_chrome_processes_tracker_.AddProcessDescriptor(packet_timestamp, upid);
1600 if (decoder.has_process_name() && decoder.process_name().size) {
1601 // Don't override system-provided names.
1602 context_->process_tracker->SetProcessNameIfUnset(
1603 upid, context_->storage->InternString(decoder.process_name()));
1604 }
1605 if (decoder.has_start_timestamp_ns() && decoder.start_timestamp_ns() > 0) {
1606 context_->process_tracker->SetStartTsIfUnset(upid,
1607 decoder.start_timestamp_ns());
1608 }
1609 // TODO(skyostil): Remove parsing for legacy chrome_process_type field.
1610 if (decoder.has_chrome_process_type()) {
1611 StringId name_id =
1612 chrome_string_lookup_.GetProcessName(decoder.chrome_process_type());
1613 // Don't override system-provided names.
1614 context_->process_tracker->SetProcessNameIfUnset(upid, name_id);
1615 }
1616 int label_index = 0;
1617 for (auto it = decoder.process_labels(); it; it++) {
1618 StringId label_id = context_->storage->InternString(*it);
1619 std::string key = "chrome.process_label[";
1620 key.append(std::to_string(label_index++));
1621 key.append("]");
1622 context_->process_tracker->AddArgsTo(upid).AddArg(
1623 chrome_process_label_flat_key_id_,
1624 context_->storage->InternString(base::StringView(key)),
1625 Variadic::String(label_id));
1626 }
1627 return upid;
1628 }
1629
ParseChromeProcessDescriptor(UniquePid upid,protozero::ConstBytes chrome_process_descriptor)1630 void TrackEventParser::ParseChromeProcessDescriptor(
1631 UniquePid upid,
1632 protozero::ConstBytes chrome_process_descriptor) {
1633 protos::pbzero::ChromeProcessDescriptor::Decoder decoder(
1634 chrome_process_descriptor);
1635
1636 StringId name_id =
1637 chrome_string_lookup_.GetProcessName(decoder.process_type());
1638 // Don't override system-provided names.
1639 context_->process_tracker->SetProcessNameIfUnset(upid, name_id);
1640
1641 ArgsTracker::BoundInserter process_args =
1642 context_->process_tracker->AddArgsTo(upid);
1643 // For identifying Chrome processes in system traces.
1644 process_args.AddArg(chrome_process_type_id_, Variadic::String(name_id));
1645 if (decoder.has_host_app_package_name()) {
1646 process_args.AddArg(chrome_host_app_package_name_id_,
1647 Variadic::String(context_->storage->InternString(
1648 decoder.host_app_package_name())));
1649 }
1650 if (decoder.has_crash_trace_id()) {
1651 process_args.AddArg(chrome_crash_trace_id_name_id_,
1652 Variadic::UnsignedInteger(decoder.crash_trace_id()));
1653 }
1654 }
1655
ParseThreadDescriptor(protozero::ConstBytes thread_descriptor)1656 UniqueTid TrackEventParser::ParseThreadDescriptor(
1657 protozero::ConstBytes thread_descriptor) {
1658 protos::pbzero::ThreadDescriptor::Decoder decoder(thread_descriptor);
1659 UniqueTid utid = context_->process_tracker->UpdateThread(
1660 static_cast<uint32_t>(decoder.tid()),
1661 static_cast<uint32_t>(decoder.pid()));
1662 StringId name_id = kNullStringId;
1663 if (decoder.has_thread_name() && decoder.thread_name().size) {
1664 name_id = context_->storage->InternString(decoder.thread_name());
1665 } else if (decoder.has_chrome_thread_type()) {
1666 // TODO(skyostil): Remove parsing for legacy chrome_thread_type field.
1667 name_id = chrome_string_lookup_.GetThreadName(decoder.chrome_thread_type());
1668 }
1669 context_->process_tracker->UpdateThreadNameByUtid(
1670 utid, name_id, ThreadNamePriority::kTrackDescriptor);
1671 return utid;
1672 }
1673
ParseChromeThreadDescriptor(UniqueTid utid,protozero::ConstBytes chrome_thread_descriptor)1674 void TrackEventParser::ParseChromeThreadDescriptor(
1675 UniqueTid utid,
1676 protozero::ConstBytes chrome_thread_descriptor) {
1677 protos::pbzero::ChromeThreadDescriptor::Decoder decoder(
1678 chrome_thread_descriptor);
1679 if (!decoder.has_thread_type())
1680 return;
1681
1682 StringId name_id = chrome_string_lookup_.GetThreadName(decoder.thread_type());
1683 context_->process_tracker->UpdateThreadNameByUtid(
1684 utid, name_id, ThreadNamePriority::kTrackDescriptorThreadType);
1685 }
1686
ParseCounterDescriptor(TrackId track_id,protozero::ConstBytes counter_descriptor)1687 void TrackEventParser::ParseCounterDescriptor(
1688 TrackId track_id,
1689 protozero::ConstBytes counter_descriptor) {
1690 using protos::pbzero::CounterDescriptor;
1691
1692 CounterDescriptor::Decoder decoder(counter_descriptor);
1693 auto* counter_tracks = context_->storage->mutable_counter_track_table();
1694
1695 size_t unit_index = static_cast<size_t>(decoder.unit());
1696 if (unit_index >= counter_unit_ids_.size())
1697 unit_index = CounterDescriptor::UNIT_UNSPECIFIED;
1698
1699 auto opt_track_idx = counter_tracks->id().IndexOf(track_id);
1700 if (!opt_track_idx) {
1701 context_->storage->IncrementStats(stats::track_event_parser_errors);
1702 return;
1703 }
1704
1705 auto track_idx = *opt_track_idx;
1706
1707 switch (decoder.type()) {
1708 case CounterDescriptor::COUNTER_UNSPECIFIED:
1709 break;
1710 case CounterDescriptor::COUNTER_THREAD_TIME_NS:
1711 unit_index = CounterDescriptor::UNIT_TIME_NS;
1712 counter_tracks->mutable_name()->Set(track_idx,
1713 counter_name_thread_time_id_);
1714 break;
1715 case CounterDescriptor::COUNTER_THREAD_INSTRUCTION_COUNT:
1716 unit_index = CounterDescriptor::UNIT_COUNT;
1717 counter_tracks->mutable_name()->Set(
1718 track_idx, counter_name_thread_instruction_count_id_);
1719 break;
1720 }
1721
1722 counter_tracks->mutable_unit()->Set(track_idx, counter_unit_ids_[unit_index]);
1723 }
1724
ParseTrackEvent(int64_t ts,const TrackEventData * event_data,ConstBytes blob,uint32_t packet_sequence_id)1725 void TrackEventParser::ParseTrackEvent(int64_t ts,
1726 const TrackEventData* event_data,
1727 ConstBytes blob,
1728 uint32_t packet_sequence_id) {
1729 const auto range_of_interest_start_us =
1730 track_event_tracker_->range_of_interest_start_us();
1731 if (context_->config.drop_track_event_data_before ==
1732 DropTrackEventDataBefore::kTrackEventRangeOfInterest &&
1733 range_of_interest_start_us && ts < *range_of_interest_start_us * 1000) {
1734 // The event is outside of the range of interest, and dropping is enabled.
1735 // So we drop the event.
1736 context_->storage->IncrementStats(
1737 stats::track_event_dropped_packets_outside_of_range_of_interest);
1738 return;
1739 }
1740 util::Status status =
1741 EventImporter(this, ts, event_data, std::move(blob), packet_sequence_id)
1742 .Import();
1743 if (!status.ok()) {
1744 context_->storage->IncrementStats(stats::track_event_parser_errors);
1745 PERFETTO_DLOG("ParseTrackEvent error: %s", status.c_message());
1746 }
1747 }
1748
AddActiveProcess(int64_t packet_timestamp,int32_t pid)1749 void TrackEventParser::AddActiveProcess(int64_t packet_timestamp, int32_t pid) {
1750 UniquePid upid =
1751 context_->process_tracker->GetOrCreateProcess(static_cast<uint32_t>(pid));
1752 active_chrome_processes_tracker_.AddActiveProcessMetadata(packet_timestamp,
1753 upid);
1754 }
1755
NotifyEndOfFile()1756 void TrackEventParser::NotifyEndOfFile() {
1757 active_chrome_processes_tracker_.NotifyEndOfFile();
1758 }
1759
1760 } // namespace trace_processor
1761 } // namespace perfetto
1762