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