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