1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/proto/proto_trace_parser.h"
18 
19 #include <inttypes.h>
20 #include <string.h>
21 
22 #include <string>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/ext/base/metatrace_events.h"
26 #include "perfetto/ext/base/string_utils.h"
27 #include "perfetto/ext/base/string_view.h"
28 #include "perfetto/ext/base/string_writer.h"
29 #include "perfetto/ext/base/utils.h"
30 #include "perfetto/ext/base/uuid.h"
31 #include "perfetto/trace_processor/status.h"
32 #include "src/trace_processor/args_tracker.h"
33 #include "src/trace_processor/clock_tracker.h"
34 #include "src/trace_processor/event_tracker.h"
35 #include "src/trace_processor/heap_profile_tracker.h"
36 #include "src/trace_processor/importers/ftrace/ftrace_module.h"
37 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
38 #include "src/trace_processor/importers/proto/profile_packet_utils.h"
39 #include "src/trace_processor/metadata_tracker.h"
40 #include "src/trace_processor/perf_sample_tracker.h"
41 #include "src/trace_processor/process_tracker.h"
42 #include "src/trace_processor/slice_tracker.h"
43 #include "src/trace_processor/stack_profile_tracker.h"
44 #include "src/trace_processor/storage/metadata.h"
45 #include "src/trace_processor/timestamped_trace_piece.h"
46 #include "src/trace_processor/trace_processor_context.h"
47 #include "src/trace_processor/track_tracker.h"
48 #include "src/trace_processor/types/variadic.h"
49 
50 #include "protos/perfetto/common/trace_stats.pbzero.h"
51 #include "protos/perfetto/config/trace_config.pbzero.h"
52 #include "protos/perfetto/trace/chrome/chrome_benchmark_metadata.pbzero.h"
53 #include "protos/perfetto/trace/chrome/chrome_trace_event.pbzero.h"
54 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
55 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
56 #include "protos/perfetto/trace/perfetto/perfetto_metatrace.pbzero.h"
57 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
58 #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
59 #include "protos/perfetto/trace/trace.pbzero.h"
60 #include "protos/perfetto/trace/trace_packet.pbzero.h"
61 #include "protos/perfetto/trace/trigger.pbzero.h"
62 
63 namespace perfetto {
64 namespace trace_processor {
65 
ProtoTraceParser(TraceProcessorContext * context)66 ProtoTraceParser::ProtoTraceParser(TraceProcessorContext* context)
67     : context_(context),
68       metatrace_id_(context->storage->InternString("metatrace")),
69       data_name_id_(context->storage->InternString("data")),
70       raw_chrome_metadata_event_id_(
71           context->storage->InternString("chrome_event.metadata")),
72       raw_chrome_legacy_system_trace_event_id_(
73           context->storage->InternString("chrome_event.legacy_system_trace")),
74       raw_chrome_legacy_user_trace_event_id_(
75           context->storage->InternString("chrome_event.legacy_user_trace")) {
76   // TODO(140860736): Once we support null values for
77   // stack_profile_frame.symbol_set_id remove this hack
78   context_->storage->mutable_symbol_table()->Insert(
79       {0, kNullStringId, kNullStringId, 0});
80 }
81 
82 ProtoTraceParser::~ProtoTraceParser() = default;
83 
ParseTracePacket(int64_t ts,TimestampedTracePiece ttp)84 void ProtoTraceParser::ParseTracePacket(int64_t ts, TimestampedTracePiece ttp) {
85   const TracePacketData* data = nullptr;
86   if (ttp.type == TimestampedTracePiece::Type::kTracePacket) {
87     data = &ttp.packet_data;
88   } else {
89     PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTrackEvent);
90     data = ttp.track_event_data.get();
91   }
92 
93   const TraceBlobView& blob = data->packet;
94   protos::pbzero::TracePacket::Decoder packet(blob.data(), blob.length());
95 
96   ParseTracePacketImpl(ts, std::move(ttp), data, packet);
97 
98   // TODO(lalitm): maybe move this to the flush method in the trace processor
99   // once we have it. This may reduce performance in the ArgsTracker though so
100   // needs to be handled carefully.
101   context_->args_tracker->Flush();
102   PERFETTO_DCHECK(!packet.bytes_left());
103 }
104 
ParseTracePacketImpl(int64_t ts,TimestampedTracePiece ttp,const TracePacketData * data,const protos::pbzero::TracePacket::Decoder & packet)105 void ProtoTraceParser::ParseTracePacketImpl(
106     int64_t ts,
107     TimestampedTracePiece ttp,
108     const TracePacketData* data,
109     const protos::pbzero::TracePacket::Decoder& packet) {
110   // TODO(eseckler): Propagate statuses from modules.
111   auto& modules = context_->modules_by_field;
112   for (uint32_t field_id = 1; field_id < modules.size(); ++field_id) {
113     if (modules[field_id] && packet.Get(field_id).valid()) {
114       modules[field_id]->ParsePacket(packet, ttp, field_id);
115       return;
116     }
117   }
118 
119   if (packet.has_trace_stats())
120     ParseTraceStats(packet.trace_stats());
121 
122   if (packet.has_profile_packet()) {
123     ParseProfilePacket(ts, data->sequence_state,
124                        packet.trusted_packet_sequence_id(),
125                        packet.profile_packet());
126   }
127 
128   if (packet.has_perf_sample()) {
129     ParsePerfSample(ts, data->sequence_state, packet.perf_sample());
130   }
131 
132   if (packet.has_chrome_benchmark_metadata()) {
133     ParseChromeBenchmarkMetadata(packet.chrome_benchmark_metadata());
134   }
135 
136   if (packet.has_chrome_events()) {
137     ParseChromeEvents(ts, packet.chrome_events());
138   }
139 
140   if (packet.has_perfetto_metatrace()) {
141     ParseMetatraceEvent(ts, packet.perfetto_metatrace());
142   }
143 
144   if (packet.has_trace_config()) {
145     ParseTraceConfig(packet.trace_config());
146   }
147 
148   if (packet.has_module_symbols()) {
149     ParseModuleSymbols(packet.module_symbols());
150   }
151 
152   if (packet.has_trigger()) {
153     ParseTrigger(ts, packet.trigger());
154   }
155 }
156 
ParseFtracePacket(uint32_t cpu,int64_t,TimestampedTracePiece ttp)157 void ProtoTraceParser::ParseFtracePacket(uint32_t cpu,
158                                          int64_t /*ts*/,
159                                          TimestampedTracePiece ttp) {
160   PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kFtraceEvent ||
161                   ttp.type == TimestampedTracePiece::Type::kInlineSchedSwitch ||
162                   ttp.type == TimestampedTracePiece::Type::kInlineSchedWaking);
163   PERFETTO_DCHECK(context_->ftrace_module);
164   context_->ftrace_module->ParseFtracePacket(cpu, ttp);
165 
166   // TODO(lalitm): maybe move this to the flush method in the trace processor
167   // once we have it. This may reduce performance in the ArgsTracker though so
168   // needs to be handled carefully.
169   context_->args_tracker->Flush();
170 }
171 
ParseTraceStats(ConstBytes blob)172 void ProtoTraceParser::ParseTraceStats(ConstBytes blob) {
173   protos::pbzero::TraceStats::Decoder evt(blob.data, blob.size);
174   auto* storage = context_->storage.get();
175   storage->SetStats(stats::traced_producers_connected,
176                     static_cast<int64_t>(evt.producers_connected()));
177   storage->SetStats(stats::traced_data_sources_registered,
178                     static_cast<int64_t>(evt.data_sources_registered()));
179   storage->SetStats(stats::traced_data_sources_seen,
180                     static_cast<int64_t>(evt.data_sources_seen()));
181   storage->SetStats(stats::traced_tracing_sessions,
182                     static_cast<int64_t>(evt.tracing_sessions()));
183   storage->SetStats(stats::traced_total_buffers,
184                     static_cast<int64_t>(evt.total_buffers()));
185   storage->SetStats(stats::traced_chunks_discarded,
186                     static_cast<int64_t>(evt.chunks_discarded()));
187   storage->SetStats(stats::traced_patches_discarded,
188                     static_cast<int64_t>(evt.patches_discarded()));
189 
190   int buf_num = 0;
191   for (auto it = evt.buffer_stats(); it; ++it, ++buf_num) {
192     protos::pbzero::TraceStats::BufferStats::Decoder buf(*it);
193     storage->SetIndexedStats(stats::traced_buf_buffer_size, buf_num,
194                              static_cast<int64_t>(buf.buffer_size()));
195     storage->SetIndexedStats(stats::traced_buf_bytes_written, buf_num,
196                              static_cast<int64_t>(buf.bytes_written()));
197     storage->SetIndexedStats(stats::traced_buf_bytes_overwritten, buf_num,
198                              static_cast<int64_t>(buf.bytes_overwritten()));
199     storage->SetIndexedStats(stats::traced_buf_bytes_read, buf_num,
200                              static_cast<int64_t>(buf.bytes_read()));
201     storage->SetIndexedStats(stats::traced_buf_padding_bytes_written, buf_num,
202                              static_cast<int64_t>(buf.padding_bytes_written()));
203     storage->SetIndexedStats(stats::traced_buf_padding_bytes_cleared, buf_num,
204                              static_cast<int64_t>(buf.padding_bytes_cleared()));
205     storage->SetIndexedStats(stats::traced_buf_chunks_written, buf_num,
206                              static_cast<int64_t>(buf.chunks_written()));
207     storage->SetIndexedStats(stats::traced_buf_chunks_rewritten, buf_num,
208                              static_cast<int64_t>(buf.chunks_rewritten()));
209     storage->SetIndexedStats(stats::traced_buf_chunks_overwritten, buf_num,
210                              static_cast<int64_t>(buf.chunks_overwritten()));
211     storage->SetIndexedStats(stats::traced_buf_chunks_discarded, buf_num,
212                              static_cast<int64_t>(buf.chunks_discarded()));
213     storage->SetIndexedStats(stats::traced_buf_chunks_read, buf_num,
214                              static_cast<int64_t>(buf.chunks_read()));
215     storage->SetIndexedStats(
216         stats::traced_buf_chunks_committed_out_of_order, buf_num,
217         static_cast<int64_t>(buf.chunks_committed_out_of_order()));
218     storage->SetIndexedStats(stats::traced_buf_write_wrap_count, buf_num,
219                              static_cast<int64_t>(buf.write_wrap_count()));
220     storage->SetIndexedStats(stats::traced_buf_patches_succeeded, buf_num,
221                              static_cast<int64_t>(buf.patches_succeeded()));
222     storage->SetIndexedStats(stats::traced_buf_patches_failed, buf_num,
223                              static_cast<int64_t>(buf.patches_failed()));
224     storage->SetIndexedStats(stats::traced_buf_readaheads_succeeded, buf_num,
225                              static_cast<int64_t>(buf.readaheads_succeeded()));
226     storage->SetIndexedStats(stats::traced_buf_readaheads_failed, buf_num,
227                              static_cast<int64_t>(buf.readaheads_failed()));
228     storage->SetIndexedStats(
229         stats::traced_buf_trace_writer_packet_loss, buf_num,
230         static_cast<int64_t>(buf.trace_writer_packet_loss()));
231   }
232 }
233 
ParseProfilePacket(int64_t,PacketSequenceStateGeneration * sequence_state,uint32_t seq_id,ConstBytes blob)234 void ProtoTraceParser::ParseProfilePacket(
235     int64_t,
236     PacketSequenceStateGeneration* sequence_state,
237     uint32_t seq_id,
238     ConstBytes blob) {
239   protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
240   context_->heap_profile_tracker->SetProfilePacketIndex(seq_id, packet.index());
241 
242   for (auto it = packet.strings(); it; ++it) {
243     protos::pbzero::InternedString::Decoder entry(*it);
244 
245     const char* str = reinterpret_cast<const char*>(entry.str().data);
246     auto str_view = base::StringView(str, entry.str().size);
247     sequence_state->state()->stack_profile_tracker().AddString(entry.iid(),
248                                                                str_view);
249   }
250 
251   for (auto it = packet.mappings(); it; ++it) {
252     protos::pbzero::Mapping::Decoder entry(*it);
253     StackProfileTracker::SourceMapping src_mapping =
254         ProfilePacketUtils::MakeSourceMapping(entry);
255     sequence_state->state()->stack_profile_tracker().AddMapping(entry.iid(),
256                                                                 src_mapping);
257   }
258 
259   for (auto it = packet.frames(); it; ++it) {
260     protos::pbzero::Frame::Decoder entry(*it);
261     StackProfileTracker::SourceFrame src_frame =
262         ProfilePacketUtils::MakeSourceFrame(entry);
263     sequence_state->state()->stack_profile_tracker().AddFrame(entry.iid(),
264                                                               src_frame);
265   }
266 
267   for (auto it = packet.callstacks(); it; ++it) {
268     protos::pbzero::Callstack::Decoder entry(*it);
269     StackProfileTracker::SourceCallstack src_callstack =
270         ProfilePacketUtils::MakeSourceCallstack(entry);
271     sequence_state->state()->stack_profile_tracker().AddCallstack(
272         entry.iid(), src_callstack);
273   }
274 
275   for (auto it = packet.process_dumps(); it; ++it) {
276     protos::pbzero::ProfilePacket::ProcessHeapSamples::Decoder entry(*it);
277 
278     auto maybe_timestamp = context_->clock_tracker->ToTraceTime(
279         protos::pbzero::ClockSnapshot::Clock::MONOTONIC_COARSE,
280         static_cast<int64_t>(entry.timestamp()));
281 
282     if (!maybe_timestamp) {
283       context_->storage->IncrementStats(stats::clock_sync_failure);
284       continue;
285     }
286 
287     int64_t timestamp = *maybe_timestamp;
288 
289     int pid = static_cast<int>(entry.pid());
290 
291     if (entry.disconnected())
292       context_->storage->IncrementIndexedStats(
293           stats::heapprofd_client_disconnected, pid);
294     if (entry.buffer_corrupted())
295       context_->storage->IncrementIndexedStats(
296           stats::heapprofd_buffer_corrupted, pid);
297     if (entry.buffer_overran())
298       context_->storage->IncrementIndexedStats(stats::heapprofd_buffer_overran,
299                                                pid);
300     if (entry.rejected_concurrent())
301       context_->storage->IncrementIndexedStats(
302           stats::heapprofd_rejected_concurrent, pid);
303     if (entry.hit_guardrail())
304       context_->storage->IncrementIndexedStats(stats::heapprofd_hit_guardrail,
305                                                pid);
306 
307     for (auto sample_it = entry.samples(); sample_it; ++sample_it) {
308       protos::pbzero::ProfilePacket::HeapSample::Decoder sample(*sample_it);
309 
310       HeapProfileTracker::SourceAllocation src_allocation;
311       src_allocation.pid = entry.pid();
312       src_allocation.timestamp = timestamp;
313       src_allocation.callstack_id = sample.callstack_id();
314       if (sample.self_max()) {
315         src_allocation.self_allocated = sample.self_max();
316       } else {
317         src_allocation.self_allocated = sample.self_allocated();
318         src_allocation.self_freed = sample.self_freed();
319       }
320       src_allocation.alloc_count = sample.alloc_count();
321       src_allocation.free_count = sample.free_count();
322 
323       context_->heap_profile_tracker->StoreAllocation(seq_id, src_allocation);
324     }
325   }
326   if (!packet.continued()) {
327     PERFETTO_CHECK(sequence_state);
328     ProfilePacketInternLookup intern_lookup(sequence_state);
329     context_->heap_profile_tracker->FinalizeProfile(
330         seq_id, &sequence_state->state()->stack_profile_tracker(),
331         &intern_lookup);
332   }
333 }
334 
ParsePerfSample(int64_t ts,PacketSequenceStateGeneration * sequence_state,ConstBytes blob)335 void ProtoTraceParser::ParsePerfSample(
336     int64_t ts,
337     PacketSequenceStateGeneration* sequence_state,
338     ConstBytes blob) {
339   using PerfSample = protos::pbzero::PerfSample;
340   PerfSample::Decoder sample(blob.data, blob.size);
341 
342   // Not a sample, but an indication of data loss in the ring buffer shared with
343   // the kernel.
344   if (sample.kernel_records_lost() > 0) {
345     PERFETTO_DCHECK(sample.pid() == 0);
346 
347     context_->storage->IncrementIndexedStats(
348         stats::perf_cpu_lost_records, static_cast<int>(sample.cpu()),
349         static_cast<int64_t>(sample.kernel_records_lost()));
350     return;
351   }
352 
353   // Sample that looked relevant for the tracing session, but had to be skipped.
354   // Either we failed to look up the procfs file descriptors necessary for
355   // remote stack unwinding (not unexpected in most cases), or the unwind queue
356   // was out of capacity (producer lost data on its own).
357   if (sample.has_sample_skipped_reason()) {
358     context_->storage->IncrementStats(stats::perf_samples_skipped);
359 
360     if (sample.sample_skipped_reason() ==
361         PerfSample::PROFILER_SKIP_UNWIND_ENQUEUE)
362       context_->storage->IncrementStats(stats::perf_samples_skipped_dataloss);
363 
364     return;
365   }
366 
367   uint64_t callstack_iid = sample.callstack_iid();
368   StackProfileTracker& stack_tracker =
369       sequence_state->state()->stack_profile_tracker();
370   ProfilePacketInternLookup intern_lookup(sequence_state);
371 
372   base::Optional<CallsiteId> cs_id =
373       stack_tracker.FindOrInsertCallstack(callstack_iid, &intern_lookup);
374   if (!cs_id) {
375     context_->storage->IncrementStats(stats::stackprofile_parser_error);
376     PERFETTO_ELOG("PerfSample referencing invalid callstack iid [%" PRIu64
377                   "] at timestamp [%" PRIi64 "]",
378                   callstack_iid, ts);
379     return;
380   }
381 
382   context_->perf_sample_tracker->AddStackToSliceTrack(
383       ts, *cs_id, sample.pid(), sample.tid(), sample.cpu());
384 }
385 
ParseChromeBenchmarkMetadata(ConstBytes blob)386 void ProtoTraceParser::ParseChromeBenchmarkMetadata(ConstBytes blob) {
387   TraceStorage* storage = context_->storage.get();
388   MetadataTracker* metadata = context_->metadata_tracker.get();
389 
390   protos::pbzero::ChromeBenchmarkMetadata::Decoder packet(blob.data, blob.size);
391   if (packet.has_benchmark_name()) {
392     auto benchmark_name_id = storage->InternString(packet.benchmark_name());
393     metadata->SetMetadata(metadata::benchmark_name,
394                           Variadic::String(benchmark_name_id));
395   }
396   if (packet.has_benchmark_description()) {
397     auto benchmark_description_id =
398         storage->InternString(packet.benchmark_description());
399     metadata->SetMetadata(metadata::benchmark_description,
400                           Variadic::String(benchmark_description_id));
401   }
402   if (packet.has_label()) {
403     auto label_id = storage->InternString(packet.label());
404     metadata->SetMetadata(metadata::benchmark_label,
405                           Variadic::String(label_id));
406   }
407   if (packet.has_story_name()) {
408     auto story_name_id = storage->InternString(packet.story_name());
409     metadata->SetMetadata(metadata::benchmark_story_name,
410                           Variadic::String(story_name_id));
411   }
412   for (auto it = packet.story_tags(); it; ++it) {
413     auto story_tag_id = storage->InternString(*it);
414     metadata->AppendMetadata(metadata::benchmark_story_tags,
415                              Variadic::String(story_tag_id));
416   }
417   if (packet.has_benchmark_start_time_us()) {
418     metadata->SetMetadata(metadata::benchmark_start_time_us,
419                           Variadic::Integer(packet.benchmark_start_time_us()));
420   }
421   if (packet.has_story_run_time_us()) {
422     metadata->SetMetadata(metadata::benchmark_story_run_time_us,
423                           Variadic::Integer(packet.story_run_time_us()));
424   }
425   if (packet.has_story_run_index()) {
426     metadata->SetMetadata(metadata::benchmark_story_run_index,
427                           Variadic::Integer(packet.story_run_index()));
428   }
429   if (packet.has_had_failures()) {
430     metadata->SetMetadata(metadata::benchmark_had_failures,
431                           Variadic::Integer(packet.had_failures()));
432   }
433 }
434 
ParseChromeEvents(int64_t ts,ConstBytes blob)435 void ProtoTraceParser::ParseChromeEvents(int64_t ts, ConstBytes blob) {
436   TraceStorage* storage = context_->storage.get();
437   protos::pbzero::ChromeEventBundle::Decoder bundle(blob.data, blob.size);
438   ArgsTracker args(context_);
439   if (bundle.has_metadata()) {
440     RawId id = storage->mutable_raw_table()
441                    ->Insert({ts, raw_chrome_metadata_event_id_, 0, 0})
442                    .id;
443     auto inserter = args.AddArgsTo(id);
444 
445     // Metadata is proxied via a special event in the raw table to JSON export.
446     for (auto it = bundle.metadata(); it; ++it) {
447       protos::pbzero::ChromeMetadata::Decoder metadata(*it);
448       StringId name_id = storage->InternString(metadata.name());
449       Variadic value;
450       if (metadata.has_string_value()) {
451         value =
452             Variadic::String(storage->InternString(metadata.string_value()));
453       } else if (metadata.has_int_value()) {
454         value = Variadic::Integer(metadata.int_value());
455       } else if (metadata.has_bool_value()) {
456         value = Variadic::Integer(metadata.bool_value());
457       } else if (metadata.has_json_value()) {
458         value = Variadic::Json(storage->InternString(metadata.json_value()));
459       } else {
460         context_->storage->IncrementStats(stats::empty_chrome_metadata);
461         continue;
462       }
463       args.AddArgsTo(id).AddArg(name_id, value);
464     }
465   }
466 
467   if (bundle.has_legacy_ftrace_output()) {
468     RawId id =
469         storage->mutable_raw_table()
470             ->Insert({ts, raw_chrome_legacy_system_trace_event_id_, 0, 0})
471             .id;
472 
473     std::string data;
474     for (auto it = bundle.legacy_ftrace_output(); it; ++it) {
475       data += (*it).ToStdString();
476     }
477     Variadic value =
478         Variadic::String(storage->InternString(base::StringView(data)));
479     args.AddArgsTo(id).AddArg(data_name_id_, value);
480   }
481 
482   if (bundle.has_legacy_json_trace()) {
483     for (auto it = bundle.legacy_json_trace(); it; ++it) {
484       protos::pbzero::ChromeLegacyJsonTrace::Decoder legacy_trace(*it);
485       if (legacy_trace.type() !=
486           protos::pbzero::ChromeLegacyJsonTrace::USER_TRACE) {
487         continue;
488       }
489       RawId id =
490           storage->mutable_raw_table()
491               ->Insert({ts, raw_chrome_legacy_user_trace_event_id_, 0, 0})
492               .id;
493       Variadic value =
494           Variadic::String(storage->InternString(legacy_trace.data()));
495       args.AddArgsTo(id).AddArg(data_name_id_, value);
496     }
497   }
498 }
499 
ParseMetatraceEvent(int64_t ts,ConstBytes blob)500 void ProtoTraceParser::ParseMetatraceEvent(int64_t ts, ConstBytes blob) {
501   protos::pbzero::PerfettoMetatrace::Decoder event(blob.data, blob.size);
502   auto utid = context_->process_tracker->GetOrCreateThread(event.thread_id());
503 
504   StringId cat_id = metatrace_id_;
505   StringId name_id = kNullStringId;
506   char fallback[64];
507 
508   if (event.has_event_id()) {
509     auto eid = event.event_id();
510     if (eid < metatrace::EVENTS_MAX) {
511       name_id = context_->storage->InternString(metatrace::kEventNames[eid]);
512     } else {
513       sprintf(fallback, "Event %d", eid);
514       name_id = context_->storage->InternString(fallback);
515     }
516     TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
517     context_->slice_tracker->Scoped(ts, track_id, cat_id, name_id,
518                                     event.event_duration_ns());
519   } else if (event.has_counter_id()) {
520     auto cid = event.counter_id();
521     if (cid < metatrace::COUNTERS_MAX) {
522       name_id = context_->storage->InternString(metatrace::kCounterNames[cid]);
523     } else {
524       sprintf(fallback, "Counter %d", cid);
525       name_id = context_->storage->InternString(fallback);
526     }
527     TrackId track =
528         context_->track_tracker->InternThreadCounterTrack(name_id, utid);
529     context_->event_tracker->PushCounter(ts, event.counter_value(), track);
530   }
531 
532   if (event.has_overruns())
533     context_->storage->IncrementStats(stats::metatrace_overruns);
534 }
535 
ParseTraceConfig(ConstBytes blob)536 void ProtoTraceParser::ParseTraceConfig(ConstBytes blob) {
537   protos::pbzero::TraceConfig::Decoder trace_config(blob.data, blob.size);
538 
539   // TODO(eseckler): Propagate statuses from modules.
540   for (auto& module : context_->modules) {
541     module->ParseTraceConfig(trace_config);
542   }
543 
544   int64_t uuid_msb = trace_config.trace_uuid_msb();
545   int64_t uuid_lsb = trace_config.trace_uuid_lsb();
546   if (uuid_msb != 0 || uuid_lsb != 0) {
547     base::Uuid uuid(uuid_lsb, uuid_msb);
548     std::string str = uuid.ToPrettyString();
549     StringId id = context_->storage->InternString(base::StringView(str));
550     context_->metadata_tracker->SetMetadata(metadata::trace_uuid,
551                                             Variadic::String(id));
552   }
553 }
554 
ParseModuleSymbols(ConstBytes blob)555 void ProtoTraceParser::ParseModuleSymbols(ConstBytes blob) {
556   protos::pbzero::ModuleSymbols::Decoder module_symbols(blob.data, blob.size);
557   StringId build_id;
558   // TODO(b/148109467): Remove workaround once all active Chrome versions
559   // write raw bytes instead of a string as build_id.
560   if (module_symbols.build_id().size == 33) {
561     build_id = context_->storage->InternString(module_symbols.build_id());
562   } else {
563     build_id = context_->storage->InternString(base::StringView(base::ToHex(
564         module_symbols.build_id().data, module_symbols.build_id().size)));
565   }
566 
567   auto mapping_ids = context_->storage->FindMappingRow(
568       context_->storage->InternString(module_symbols.path()), build_id);
569   if (mapping_ids.empty()) {
570     context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
571     return;
572   }
573   for (auto addr_it = module_symbols.address_symbols(); addr_it; ++addr_it) {
574     protos::pbzero::AddressSymbols::Decoder address_symbols(*addr_it);
575 
576     uint32_t symbol_set_id = context_->storage->symbol_table().row_count();
577     bool frame_found = false;
578     for (MappingId mapping_id : mapping_ids) {
579       std::vector<FrameId> frame_ids = context_->storage->FindFrameIds(
580           mapping_id, address_symbols.address());
581 
582       for (const FrameId frame_id : frame_ids) {
583         auto* frames = context_->storage->mutable_stack_profile_frame_table();
584         uint32_t frame_row = *frames->id().IndexOf(frame_id);
585         frames->mutable_symbol_set_id()->Set(frame_row, symbol_set_id);
586         frame_found = true;
587       }
588     }
589 
590     if (!frame_found) {
591       context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
592       continue;
593     }
594 
595     for (auto line_it = address_symbols.lines(); line_it; ++line_it) {
596       protos::pbzero::Line::Decoder line(*line_it);
597       context_->storage->mutable_symbol_table()->Insert(
598           {symbol_set_id, context_->storage->InternString(line.function_name()),
599            context_->storage->InternString(line.source_file_name()),
600            line.line_number()});
601     }
602   }
603 }
604 
ParseTrigger(int64_t ts,ConstBytes blob)605 void ProtoTraceParser::ParseTrigger(int64_t ts, ConstBytes blob) {
606   protos::pbzero::Trigger::Decoder trigger(blob.data, blob.size);
607   StringId cat_id = kNullStringId;
608   TrackId track_id = context_->track_tracker->GetOrCreateTriggerTrack();
609   StringId name_id = context_->storage->InternString(trigger.trigger_name());
610   context_->slice_tracker->Scoped(
611       ts, track_id, cat_id, name_id,
612       /* duration = */ 0,
613       [&trigger, this](ArgsTracker::BoundInserter* args_table) {
614         StringId producer_name_key =
615             context_->storage->InternString("producer_name");
616         args_table->AddArg(producer_name_key,
617                            Variadic::String(context_->storage->InternString(
618                                trigger.producer_name())));
619         StringId trusted_producer_uid_key =
620             context_->storage->InternString("trusted_producer_uid");
621         args_table->AddArg(trusted_producer_uid_key,
622                            Variadic::Integer(trigger.trusted_producer_uid()));
623       });
624 }
625 
626 }  // namespace trace_processor
627 }  // namespace perfetto
628