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