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/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/base/optional.h"
26 #include "perfetto/base/string_view.h"
27 #include "perfetto/base/utils.h"
28 #include "perfetto/protozero/proto_decoder.h"
29 #include "perfetto/traced/sys_stats_counters.h"
30 #include "src/trace_processor/args_tracker.h"
31 #include "src/trace_processor/clock_tracker.h"
32 #include "src/trace_processor/event_tracker.h"
33 #include "src/trace_processor/ftrace_descriptors.h"
34 #include "src/trace_processor/heap_profile_tracker.h"
35 #include "src/trace_processor/process_tracker.h"
36 #include "src/trace_processor/slice_tracker.h"
37 #include "src/trace_processor/syscall_tracker.h"
38 #include "src/trace_processor/trace_processor_context.h"
39
40 #include "perfetto/common/android_log_constants.pbzero.h"
41 #include "perfetto/common/trace_stats.pbzero.h"
42 #include "perfetto/trace/android/android_log.pbzero.h"
43 #include "perfetto/trace/clock_snapshot.pbzero.h"
44 #include "perfetto/trace/ftrace/ftrace.pbzero.h"
45 #include "perfetto/trace/ftrace/ftrace_event.pbzero.h"
46 #include "perfetto/trace/ftrace/ftrace_stats.pbzero.h"
47 #include "perfetto/trace/ftrace/generic.pbzero.h"
48 #include "perfetto/trace/ftrace/kmem.pbzero.h"
49 #include "perfetto/trace/ftrace/lowmemorykiller.pbzero.h"
50 #include "perfetto/trace/ftrace/mm_event.pbzero.h"
51 #include "perfetto/trace/ftrace/oom.pbzero.h"
52 #include "perfetto/trace/ftrace/power.pbzero.h"
53 #include "perfetto/trace/ftrace/raw_syscalls.pbzero.h"
54 #include "perfetto/trace/ftrace/sched.pbzero.h"
55 #include "perfetto/trace/ftrace/signal.pbzero.h"
56 #include "perfetto/trace/ftrace/task.pbzero.h"
57 #include "perfetto/trace/interned_data/interned_data.pbzero.h"
58 #include "perfetto/trace/power/battery_counters.pbzero.h"
59 #include "perfetto/trace/power/power_rails.pbzero.h"
60 #include "perfetto/trace/profiling/profile_packet.pbzero.h"
61 #include "perfetto/trace/ps/process_stats.pbzero.h"
62 #include "perfetto/trace/ps/process_tree.pbzero.h"
63 #include "perfetto/trace/sys_stats/sys_stats.pbzero.h"
64 #include "perfetto/trace/system_info.pbzero.h"
65 #include "perfetto/trace/trace.pbzero.h"
66 #include "perfetto/trace/trace_packet.pbzero.h"
67 #include "perfetto/trace/track_event/debug_annotation.pbzero.h"
68 #include "perfetto/trace/track_event/task_execution.pbzero.h"
69 #include "perfetto/trace/track_event/track_event.pbzero.h"
70
71 namespace perfetto {
72 namespace trace_processor {
73
74 namespace {
75
76 using protozero::ProtoDecoder;
77 using Variadic = TraceStorage::Args::Variadic;
78
79 } // namespace
80
81 // We have to handle trace_marker events of a few different types:
82 // 1. some random text
83 // 2. B|1636|pokeUserActivity
84 // 3. E|1636
85 // 4. C|1636|wq:monitor|0
ParseSystraceTracePoint(base::StringView str,SystraceTracePoint * out)86 SystraceParseResult ParseSystraceTracePoint(base::StringView str,
87 SystraceTracePoint* out) {
88 // THIS char* IS NOT NULL TERMINATED.
89 const char* s = str.data();
90 size_t len = str.size();
91
92 if (len < 2)
93 return SystraceParseResult::kFailure;
94
95 // If str matches '[BEC]\|[0-9]+[\|\n]' set tgid_length to the length of
96 // the number. Otherwise return kFailure.
97 if (s[1] != '|' && s[1] != '\n')
98 return SystraceParseResult::kFailure;
99 if (s[0] != 'B' && s[0] != 'E' && s[0] != 'C') {
100 // TODO: support android async slices
101 return s[0] == 'S' || s[0] == 'F' ? SystraceParseResult::kUnsupported
102 : SystraceParseResult::kFailure;
103 }
104 size_t tgid_length = 0;
105 for (size_t i = 2; i < len; i++) {
106 if (s[i] == '|' || s[i] == '\n') {
107 tgid_length = i - 2;
108 break;
109 }
110 if (s[i] < '0' || s[i] > '9')
111 return SystraceParseResult::kFailure;
112 }
113
114 if (tgid_length == 0) {
115 out->tgid = 0;
116 } else {
117 std::string tgid_str(s + 2, tgid_length);
118 out->tgid = static_cast<uint32_t>(std::stoi(tgid_str.c_str()));
119 }
120
121 out->phase = s[0];
122 switch (s[0]) {
123 case 'B': {
124 size_t name_index = 2 + tgid_length + 1;
125 out->name = base::StringView(
126 s + name_index, len - name_index - (s[len - 1] == '\n' ? 1 : 0));
127 return SystraceParseResult::kSuccess;
128 }
129 case 'E': {
130 return SystraceParseResult::kSuccess;
131 }
132 case 'C': {
133 size_t name_index = 2 + tgid_length + 1;
134 size_t name_length = 0;
135 for (size_t i = name_index; i < len; i++) {
136 if (s[i] == '|' || s[i] == '\n') {
137 name_length = i - name_index;
138 break;
139 }
140 }
141 out->name = base::StringView(s + name_index, name_length);
142
143 size_t value_index = name_index + name_length + 1;
144 size_t value_len = len - value_index;
145 char value_str[32];
146 if (value_len >= sizeof(value_str)) {
147 return SystraceParseResult::kFailure;
148 }
149 memcpy(value_str, s + value_index, value_len);
150 value_str[value_len] = 0;
151 out->value = std::stod(value_str);
152 return SystraceParseResult::kSuccess;
153 }
154 default:
155 return SystraceParseResult::kFailure;
156 }
157 }
158
ProtoTraceParser(TraceProcessorContext * context)159 ProtoTraceParser::ProtoTraceParser(TraceProcessorContext* context)
160 : context_(context),
161 utid_name_id_(context->storage->InternString("utid")),
162 sched_wakeup_name_id_(context->storage->InternString("sched_wakeup")),
163 cpu_freq_name_id_(context->storage->InternString("cpufreq")),
164 cpu_idle_name_id_(context->storage->InternString("cpuidle")),
165 comm_name_id_(context->storage->InternString("comm")),
166 num_forks_name_id_(context->storage->InternString("num_forks")),
167 num_irq_total_name_id_(context->storage->InternString("num_irq_total")),
168 num_softirq_total_name_id_(
169 context->storage->InternString("num_softirq_total")),
170 num_irq_name_id_(context->storage->InternString("num_irq")),
171 num_softirq_name_id_(context->storage->InternString("num_softirq")),
172 cpu_times_user_ns_id_(
173 context->storage->InternString("cpu.times.user_ns")),
174 cpu_times_user_nice_ns_id_(
175 context->storage->InternString("cpu.times.user_nice_ns")),
176 cpu_times_system_mode_ns_id_(
177 context->storage->InternString("cpu.times.system_mode_ns")),
178 cpu_times_idle_ns_id_(
179 context->storage->InternString("cpu.times.idle_ns")),
180 cpu_times_io_wait_ns_id_(
181 context->storage->InternString("cpu.times.io_wait_ns")),
182 cpu_times_irq_ns_id_(context->storage->InternString("cpu.times.irq_ns")),
183 cpu_times_softirq_ns_id_(
184 context->storage->InternString("cpu.times.softirq_ns")),
185 signal_deliver_id_(context->storage->InternString("signal_deliver")),
186 signal_generate_id_(context->storage->InternString("signal_generate")),
187 batt_charge_id_(context->storage->InternString("batt.charge_uah")),
188 batt_capacity_id_(context->storage->InternString("batt.capacity_pct")),
189 batt_current_id_(context->storage->InternString("batt.current_ua")),
190 batt_current_avg_id_(
191 context->storage->InternString("batt.current.avg_ua")),
192 lmk_id_(context->storage->InternString("mem.lmk")),
193 oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
194 ion_total_unknown_id_(context->storage->InternString("mem.ion.unknown")),
195 ion_change_unknown_id_(
196 context->storage->InternString("mem.ion_change.unknown")) {
197 for (const auto& name : BuildMeminfoCounterNames()) {
198 meminfo_strs_id_.emplace_back(context->storage->InternString(name));
199 }
200 for (const auto& name : BuildVmstatCounterNames()) {
201 vmstat_strs_id_.emplace_back(context->storage->InternString(name));
202 }
203 rss_members_.emplace_back(context->storage->InternString("mem.rss.file"));
204 rss_members_.emplace_back(context->storage->InternString("mem.rss.anon"));
205 rss_members_.emplace_back(context->storage->InternString("mem.swap"));
206 rss_members_.emplace_back(context->storage->InternString("mem.rss.shmem"));
207 rss_members_.emplace_back(
208 context->storage->InternString("mem.rss.unknown")); // Keep this last.
209
210 using ProcessStats = protos::pbzero::ProcessStats;
211 proc_stats_process_names_[ProcessStats::Process::kVmSizeKbFieldNumber] =
212 context->storage->InternString("mem.virt");
213 proc_stats_process_names_[ProcessStats::Process::kVmRssKbFieldNumber] =
214 context->storage->InternString("mem.rss");
215 proc_stats_process_names_[ProcessStats::Process::kRssAnonKbFieldNumber] =
216 context->storage->InternString("mem.rss.anon");
217 proc_stats_process_names_[ProcessStats::Process::kRssFileKbFieldNumber] =
218 context->storage->InternString("mem.rss.file");
219 proc_stats_process_names_[ProcessStats::Process::kRssShmemKbFieldNumber] =
220 context->storage->InternString("mem.rss.shmem");
221 proc_stats_process_names_[ProcessStats::Process::kVmSwapKbFieldNumber] =
222 context->storage->InternString("mem.swap");
223 proc_stats_process_names_[ProcessStats::Process::kVmLockedKbFieldNumber] =
224 context->storage->InternString("mem.locked");
225 proc_stats_process_names_[ProcessStats::Process::kVmHwmKbFieldNumber] =
226 context->storage->InternString("mem.rss.watermark");
227 proc_stats_process_names_[ProcessStats::Process::kOomScoreAdjFieldNumber] =
228 oom_score_adj_id_;
229
230 mm_event_counter_names_ = {
231 {MmEventCounterNames(
232 context->storage->InternString("mem.mm.min_flt.count"),
233 context->storage->InternString("mem.mm.min_flt.max_lat"),
234 context->storage->InternString("mem.mm.min_flt.avg_lat")),
235 MmEventCounterNames(
236 context->storage->InternString("mem.mm.maj_flt.count"),
237 context->storage->InternString("mem.mm.maj_flt.max_lat"),
238 context->storage->InternString("mem.mm.maj_flt.avg_lat")),
239 MmEventCounterNames(
240 context->storage->InternString("mem.mm.read_io.count"),
241 context->storage->InternString("mem.mm.read_io.max_lat"),
242 context->storage->InternString("mem.mm.read_io.avg_lat")),
243 MmEventCounterNames(
244 context->storage->InternString("mem.mm.compaction.count"),
245 context->storage->InternString("mem.mm.compaction.max_lat"),
246 context->storage->InternString("mem.mm.compaction.avg_lat")),
247 MmEventCounterNames(
248 context->storage->InternString("mem.mm.reclaim.count"),
249 context->storage->InternString("mem.mm.reclaim.max_lat"),
250 context->storage->InternString("mem.mm.reclaim.avg_lat")),
251 MmEventCounterNames(
252 context->storage->InternString("mem.mm.swp_flt.count"),
253 context->storage->InternString("mem.mm.swp_flt.max_lat"),
254 context->storage->InternString("mem.mm.swp_flt.avg_lat")),
255 MmEventCounterNames(
256 context->storage->InternString("mem.mm.kern_alloc.count"),
257 context->storage->InternString("mem.mm.kern_alloc.max_lat"),
258 context->storage->InternString("mem.mm.kern_alloc.avg_lat"))}};
259
260 // Build the lookup table for the strings inside ftrace events (e.g. the
261 // name of ftrace event fields and the names of their args).
262 for (size_t i = 0; i < GetDescriptorsSize(); i++) {
263 auto* descriptor = GetMessageDescriptorForId(i);
264 if (!descriptor->name) {
265 ftrace_message_strings_.emplace_back();
266 continue;
267 }
268
269 FtraceMessageStrings ftrace_strings;
270 ftrace_strings.message_name_id =
271 context->storage->InternString(descriptor->name);
272
273 for (size_t fid = 0; fid <= descriptor->max_field_id; fid++) {
274 const auto& field = descriptor->fields[fid];
275 if (!field.name)
276 continue;
277 ftrace_strings.field_name_ids[fid] =
278 context->storage->InternString(field.name);
279 }
280 ftrace_message_strings_.emplace_back(ftrace_strings);
281 }
282 }
283
284 ProtoTraceParser::~ProtoTraceParser() = default;
285
ParseTracePacket(int64_t ts,TraceSorter::TimestampedTracePiece ttp)286 void ProtoTraceParser::ParseTracePacket(
287 int64_t ts,
288 TraceSorter::TimestampedTracePiece ttp) {
289 PERFETTO_DCHECK(ttp.json_value == nullptr);
290 const TraceBlobView& blob = ttp.blob_view;
291
292 protos::pbzero::TracePacket::Decoder packet(blob.data(), blob.length());
293
294 if (packet.has_process_tree())
295 ParseProcessTree(packet.process_tree());
296
297 if (packet.has_process_stats())
298 ParseProcessStats(ts, packet.process_stats());
299
300 if (packet.has_sys_stats())
301 ParseSysStats(ts, packet.sys_stats());
302
303 if (packet.has_battery())
304 ParseBatteryCounters(ts, packet.battery());
305
306 if (packet.has_power_rails())
307 ParsePowerRails(packet.power_rails());
308
309 if (packet.has_trace_stats())
310 ParseTraceStats(packet.trace_stats());
311
312 if (packet.has_ftrace_stats())
313 ParseFtraceStats(packet.ftrace_stats());
314
315 if (packet.has_clock_snapshot())
316 ParseClockSnapshot(packet.clock_snapshot());
317
318 if (packet.has_android_log())
319 ParseAndroidLogPacket(packet.android_log());
320
321 if (packet.has_profile_packet())
322 ParseProfilePacket(packet.profile_packet());
323
324 if (packet.has_system_info())
325 ParseSystemInfo(packet.system_info());
326
327 if (packet.has_track_event()) {
328 ParseTrackEvent(ts, ttp.thread_timestamp, ttp.packet_sequence_state,
329 packet.track_event());
330 }
331
332 // TODO(lalitm): maybe move this to the flush method in the trace processor
333 // once we have it. This may reduce performance in the ArgsTracker though so
334 // needs to be handled carefully.
335 context_->args_tracker->Flush();
336 PERFETTO_DCHECK(!packet.bytes_left());
337 }
338
ParseSysStats(int64_t ts,ConstBytes blob)339 void ProtoTraceParser::ParseSysStats(int64_t ts, ConstBytes blob) {
340 protos::pbzero::SysStats::Decoder sys_stats(blob.data, blob.size);
341
342 for (auto it = sys_stats.meminfo(); it; ++it) {
343 protos::pbzero::SysStats::MeminfoValue::Decoder mi(it->data(), it->size());
344 auto key = static_cast<size_t>(mi.key());
345 if (PERFETTO_UNLIKELY(key >= meminfo_strs_id_.size())) {
346 PERFETTO_ELOG("MemInfo key %zu is not recognized.", key);
347 context_->storage->IncrementStats(stats::meminfo_unknown_keys);
348 continue;
349 }
350 // /proc/meminfo counters are in kB, convert to bytes
351 context_->event_tracker->PushCounter(
352 ts, mi.value() * 1024L, meminfo_strs_id_[key], 0, RefType::kRefNoRef);
353 }
354
355 for (auto it = sys_stats.vmstat(); it; ++it) {
356 protos::pbzero::SysStats::VmstatValue::Decoder vm(it->data(), it->size());
357 auto key = static_cast<size_t>(vm.key());
358 if (PERFETTO_UNLIKELY(key >= vmstat_strs_id_.size())) {
359 PERFETTO_ELOG("VmStat key %zu is not recognized.", key);
360 context_->storage->IncrementStats(stats::vmstat_unknown_keys);
361 continue;
362 }
363 context_->event_tracker->PushCounter(ts, vm.value(), vmstat_strs_id_[key],
364 0, RefType::kRefNoRef);
365 }
366
367 for (auto it = sys_stats.cpu_stat(); it; ++it) {
368 protos::pbzero::SysStats::CpuTimes::Decoder ct(it->data(), it->size());
369 if (PERFETTO_UNLIKELY(!ct.has_cpu_id())) {
370 PERFETTO_ELOG("CPU field not found in CpuTimes");
371 context_->storage->IncrementStats(stats::invalid_cpu_times);
372 continue;
373 }
374 context_->event_tracker->PushCounter(ts, ct.user_ns(),
375 cpu_times_user_ns_id_, ct.cpu_id(),
376 RefType::kRefCpuId);
377 context_->event_tracker->PushCounter(ts, ct.user_ice_ns(),
378 cpu_times_user_nice_ns_id_,
379 ct.cpu_id(), RefType::kRefCpuId);
380 context_->event_tracker->PushCounter(ts, ct.system_mode_ns(),
381 cpu_times_system_mode_ns_id_,
382 ct.cpu_id(), RefType::kRefCpuId);
383 context_->event_tracker->PushCounter(ts, ct.idle_ns(),
384 cpu_times_idle_ns_id_, ct.cpu_id(),
385 RefType::kRefCpuId);
386 context_->event_tracker->PushCounter(ts, ct.io_wait_ns(),
387 cpu_times_io_wait_ns_id_, ct.cpu_id(),
388 RefType::kRefCpuId);
389 context_->event_tracker->PushCounter(ts, ct.irq_ns(), cpu_times_irq_ns_id_,
390 ct.cpu_id(), RefType::kRefCpuId);
391 context_->event_tracker->PushCounter(ts, ct.softirq_ns(),
392 cpu_times_softirq_ns_id_, ct.cpu_id(),
393 RefType::kRefCpuId);
394 }
395
396 for (auto it = sys_stats.num_irq(); it; ++it) {
397 protos::pbzero::SysStats::InterruptCount::Decoder ic(it->data(),
398 it->size());
399 context_->event_tracker->PushCounter(ts, ic.count(), num_irq_name_id_,
400 ic.irq(), RefType::kRefIrq);
401 }
402
403 for (auto it = sys_stats.num_softirq(); it; ++it) {
404 protos::pbzero::SysStats::InterruptCount::Decoder ic(it->data(),
405 it->size());
406 context_->event_tracker->PushCounter(ts, ic.count(), num_softirq_name_id_,
407 ic.irq(), RefType::kRefSoftIrq);
408 }
409
410 if (sys_stats.has_num_forks()) {
411 context_->event_tracker->PushCounter(
412 ts, sys_stats.num_forks(), num_forks_name_id_, 0, RefType::kRefNoRef);
413 }
414
415 if (sys_stats.has_num_irq_total()) {
416 context_->event_tracker->PushCounter(ts, sys_stats.num_irq_total(),
417 num_irq_total_name_id_, 0,
418 RefType::kRefNoRef);
419 }
420
421 if (sys_stats.has_num_softirq_total()) {
422 context_->event_tracker->PushCounter(ts, sys_stats.num_softirq_total(),
423 num_softirq_total_name_id_, 0,
424 RefType::kRefNoRef);
425 }
426 }
427
ParseProcessTree(ConstBytes blob)428 void ProtoTraceParser::ParseProcessTree(ConstBytes blob) {
429 protos::pbzero::ProcessTree::Decoder ps(blob.data, blob.size);
430
431 for (auto it = ps.processes(); it; ++it) {
432 protos::pbzero::ProcessTree::Process::Decoder proc(it->data(), it->size());
433 if (!proc.has_cmdline())
434 continue;
435 auto pid = static_cast<uint32_t>(proc.pid());
436 auto ppid = static_cast<uint32_t>(proc.ppid());
437
438 context_->process_tracker->UpdateProcess(pid, ppid,
439 proc.cmdline()->as_string());
440 }
441
442 for (auto it = ps.threads(); it; ++it) {
443 protos::pbzero::ProcessTree::Thread::Decoder thd(it->data(), it->size());
444 auto tid = static_cast<uint32_t>(thd.tid());
445 auto tgid = static_cast<uint32_t>(thd.tgid());
446 context_->process_tracker->UpdateThread(tid, tgid);
447 }
448 }
449
ParseProcessStats(int64_t ts,ConstBytes blob)450 void ProtoTraceParser::ParseProcessStats(int64_t ts, ConstBytes blob) {
451 protos::pbzero::ProcessStats::Decoder stats(blob.data, blob.size);
452 const auto kOomScoreAdjFieldNumber =
453 protos::pbzero::ProcessStats::Process::kOomScoreAdjFieldNumber;
454 for (auto it = stats.processes(); it; ++it) {
455 // Maps a process counter field it to its value.
456 // E.g., 4 := 1024 -> "mem.rss.anon" := 1024.
457 std::array<int64_t, kProcStatsProcessSize> counter_values{};
458 std::array<bool, kProcStatsProcessSize> has_counter{};
459
460 ProtoDecoder proc(it->data(), it->size());
461 uint32_t pid = 0;
462 for (auto fld = proc.ReadField(); fld.valid(); fld = proc.ReadField()) {
463 if (fld.id() == protos::pbzero::ProcessStats::Process::kPidFieldNumber) {
464 pid = fld.as_uint32();
465 continue;
466 }
467 bool is_counter_field = fld.id() < proc_stats_process_names_.size() &&
468 proc_stats_process_names_[fld.id()] != 0;
469 if (is_counter_field) {
470 // Memory counters are in KB, keep values in bytes in the trace
471 // processor.
472 counter_values[fld.id()] = fld.id() == kOomScoreAdjFieldNumber
473 ? fld.as_int64()
474 : fld.as_int64() * 1024;
475 has_counter[fld.id()] = true;
476 } else {
477 context_->storage->IncrementStats(stats::proc_stat_unknown_counters);
478 }
479 }
480
481 // Skip field_id 0 (invalid) and 1 (pid).
482 for (size_t field_id = 2; field_id < counter_values.size(); field_id++) {
483 if (!has_counter[field_id])
484 continue;
485
486 // Lookup the interned string id from the field name using the
487 // pre-cached |proc_stats_process_names_| map.
488 StringId name = proc_stats_process_names_[field_id];
489 int64_t value = counter_values[field_id];
490 UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
491 context_->event_tracker->PushCounter(ts, value, name, upid,
492 RefType::kRefUpid);
493 }
494 }
495 }
496
ParseFtracePacket(uint32_t cpu,int64_t ts,TraceSorter::TimestampedTracePiece ttp)497 void ProtoTraceParser::ParseFtracePacket(
498 uint32_t cpu,
499 int64_t ts,
500 TraceSorter::TimestampedTracePiece ttp) {
501 PERFETTO_DCHECK(ttp.json_value == nullptr);
502 const TraceBlobView& ftrace = ttp.blob_view;
503
504 ProtoDecoder decoder(ftrace.data(), ftrace.length());
505 uint64_t raw_pid = 0;
506 if (auto pid_field =
507 decoder.FindField(protos::pbzero::FtraceEvent::kPidFieldNumber)) {
508 raw_pid = pid_field.as_uint64();
509 } else {
510 PERFETTO_ELOG("Pid field not found in ftrace packet");
511 return;
512 }
513 uint32_t pid = static_cast<uint32_t>(raw_pid);
514
515 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
516 bool is_metadata_field =
517 fld.id() == protos::pbzero::FtraceEvent::kPidFieldNumber ||
518 fld.id() == protos::pbzero::FtraceEvent::kTimestampFieldNumber;
519 if (is_metadata_field)
520 continue;
521
522 ConstBytes data = fld.as_bytes();
523 if (fld.id() == protos::pbzero::FtraceEvent::kGenericFieldNumber) {
524 ParseGenericFtrace(ts, cpu, pid, data);
525 } else if (fld.id() !=
526 protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber) {
527 ParseTypedFtraceToRaw(fld.id(), ts, cpu, pid, data);
528 }
529
530 switch (fld.id()) {
531 case protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber: {
532 ParseSchedSwitch(cpu, ts, data);
533 break;
534 }
535 case protos::pbzero::FtraceEvent::kSchedWakeupFieldNumber: {
536 ParseSchedWakeup(ts, data);
537 break;
538 }
539 case protos::pbzero::FtraceEvent::kCpuFrequencyFieldNumber: {
540 ParseCpuFreq(ts, data);
541 break;
542 }
543 case protos::pbzero::FtraceEvent::kCpuIdleFieldNumber: {
544 ParseCpuIdle(ts, data);
545 break;
546 }
547 case protos::pbzero::FtraceEvent::kPrintFieldNumber: {
548 ParsePrint(cpu, ts, pid, data);
549 break;
550 }
551 case protos::pbzero::FtraceEvent::kRssStatFieldNumber: {
552 ParseRssStat(ts, pid, data);
553 break;
554 }
555 case protos::pbzero::FtraceEvent::kIonHeapGrowFieldNumber: {
556 ParseIonHeapGrowOrShrink(ts, pid, data, true);
557 break;
558 }
559 case protos::pbzero::FtraceEvent::kIonHeapShrinkFieldNumber: {
560 ParseIonHeapGrowOrShrink(ts, pid, data, false);
561 break;
562 }
563 case protos::pbzero::FtraceEvent::kSignalGenerateFieldNumber: {
564 ParseSignalGenerate(ts, data);
565 break;
566 }
567 case protos::pbzero::FtraceEvent::kSignalDeliverFieldNumber: {
568 ParseSignalDeliver(ts, pid, data);
569 break;
570 }
571 case protos::pbzero::FtraceEvent::kLowmemoryKillFieldNumber: {
572 ParseLowmemoryKill(ts, data);
573 break;
574 }
575 case protos::pbzero::FtraceEvent::kOomScoreAdjUpdateFieldNumber: {
576 ParseOOMScoreAdjUpdate(ts, data);
577 break;
578 }
579 case protos::pbzero::FtraceEvent::kMmEventRecordFieldNumber: {
580 ParseMmEventRecord(ts, pid, data);
581 break;
582 }
583 case protos::pbzero::FtraceEvent::kSysEnterFieldNumber: {
584 ParseSysEvent(ts, pid, true, data);
585 break;
586 }
587 case protos::pbzero::FtraceEvent::kSysExitFieldNumber: {
588 ParseSysEvent(ts, pid, false, data);
589 break;
590 }
591 case protos::pbzero::FtraceEvent::kTaskNewtaskFieldNumber: {
592 ParseTaskNewTask(ts, pid, data);
593 break;
594 }
595 case protos::pbzero::FtraceEvent::kTaskRenameFieldNumber: {
596 ParseTaskRename(data);
597 break;
598 }
599 default:
600 break;
601 }
602 }
603 // TODO(lalitm): maybe move this to the flush method in the trace processor
604 // once we have it. This may reduce performance in the ArgsTracker though so
605 // needs to be handled carefully.
606 context_->args_tracker->Flush();
607
608 PERFETTO_DCHECK(!decoder.bytes_left());
609 }
610
ParseSignalDeliver(int64_t ts,uint32_t pid,ConstBytes blob)611 void ProtoTraceParser::ParseSignalDeliver(int64_t ts,
612 uint32_t pid,
613 ConstBytes blob) {
614 protos::pbzero::SignalDeliverFtraceEvent::Decoder sig(blob.data, blob.size);
615 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
616 context_->event_tracker->PushInstant(ts, signal_deliver_id_, sig.sig(), utid,
617 RefType::kRefUtid);
618 }
619
620 // This event has both the pid of the thread that sent the signal and the
621 // destination of the signal. Currently storing the pid of the destination.
ParseSignalGenerate(int64_t ts,ConstBytes blob)622 void ProtoTraceParser::ParseSignalGenerate(int64_t ts, ConstBytes blob) {
623 protos::pbzero::SignalGenerateFtraceEvent::Decoder sig(blob.data, blob.size);
624
625 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
626 static_cast<uint32_t>(sig.pid()));
627 context_->event_tracker->PushInstant(ts, signal_generate_id_, sig.sig(), utid,
628 RefType::kRefUtid);
629 }
630
ParseLowmemoryKill(int64_t ts,ConstBytes blob)631 void ProtoTraceParser::ParseLowmemoryKill(int64_t ts, ConstBytes blob) {
632 // TODO(taylori): Store the pagecache_size, pagecache_limit and free fields
633 // in an args table
634 protos::pbzero::LowmemoryKillFtraceEvent::Decoder lmk(blob.data, blob.size);
635
636 // Store the pid of the event that is lmk-ed.
637 auto pid = static_cast<uint32_t>(lmk.pid());
638 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
639 auto row_id = context_->event_tracker->PushInstant(ts, lmk_id_, 0, utid,
640 RefType::kRefUtid, true);
641
642 // Store the comm as an arg.
643 auto comm_id = context_->storage->InternString(
644 lmk.has_comm() ? lmk.comm() : base::StringView());
645 context_->args_tracker->AddArg(row_id, comm_name_id_, comm_name_id_,
646 Variadic::String(comm_id));
647 }
648
ParseRssStat(int64_t ts,uint32_t pid,ConstBytes blob)649 void ProtoTraceParser::ParseRssStat(int64_t ts, uint32_t pid, ConstBytes blob) {
650 protos::pbzero::RssStatFtraceEvent::Decoder rss(blob.data, blob.size);
651 const auto kRssStatUnknown = static_cast<uint32_t>(rss_members_.size()) - 1;
652 auto member = static_cast<uint32_t>(rss.member());
653 int64_t size = rss.size();
654 if (member >= rss_members_.size()) {
655 context_->storage->IncrementStats(stats::rss_stat_unknown_keys);
656 member = kRssStatUnknown;
657 }
658
659 if (size >= 0) {
660 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
661 context_->event_tracker->PushCounter(ts, size, rss_members_[member], utid,
662 RefType::kRefUtid, true);
663 } else {
664 context_->storage->IncrementStats(stats::rss_stat_negative_size);
665 }
666 }
667
ParseIonHeapGrowOrShrink(int64_t ts,uint32_t pid,ConstBytes blob,bool grow)668 void ProtoTraceParser::ParseIonHeapGrowOrShrink(int64_t ts,
669 uint32_t pid,
670 ConstBytes blob,
671 bool grow) {
672 protos::pbzero::IonHeapGrowFtraceEvent::Decoder ion(blob.data, blob.size);
673 int64_t total_bytes = ion.total_allocated();
674 int64_t change_bytes = static_cast<int64_t>(ion.len()) * (grow ? 1 : -1);
675 StringId global_name_id = ion_total_unknown_id_;
676 StringId change_name_id = ion_change_unknown_id_;
677
678 if (ion.has_heap_name()) {
679 char counter_name[255];
680 base::StringView heap_name = ion.heap_name();
681 snprintf(counter_name, sizeof(counter_name), "mem.ion.%.*s",
682 int(heap_name.size()), heap_name.data());
683 global_name_id = context_->storage->InternString(counter_name);
684 snprintf(counter_name, sizeof(counter_name), "mem.ion_change.%.*s",
685 int(heap_name.size()), heap_name.data());
686 change_name_id = context_->storage->InternString(counter_name);
687 }
688
689 // Push the global counter.
690 context_->event_tracker->PushCounter(ts, total_bytes, global_name_id, 0,
691 RefType::kRefNoRef);
692
693 // Push the change counter.
694 // TODO(b/121331269): these should really be instant events. For now we
695 // manually reset them to 0 after 1ns.
696 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
697 context_->event_tracker->PushCounter(ts, change_bytes, change_name_id, utid,
698 RefType::kRefUtid);
699 context_->event_tracker->PushCounter(ts + 1, 0, change_name_id, utid,
700 RefType::kRefUtid);
701
702 // We are reusing the same function for ion_heap_grow and ion_heap_shrink.
703 // It is fine as the arguments are the same, but we need to be sure that the
704 // protobuf field id for both are the same.
705 static_assert(
706 static_cast<int>(
707 protos::pbzero::IonHeapGrowFtraceEvent::kTotalAllocatedFieldNumber) ==
708 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
709 kTotalAllocatedFieldNumber) &&
710 static_cast<int>(
711 protos::pbzero::IonHeapGrowFtraceEvent::kLenFieldNumber) ==
712 static_cast<int>(
713 protos::pbzero::IonHeapShrinkFtraceEvent::kLenFieldNumber) &&
714 static_cast<int>(
715 protos::pbzero::IonHeapGrowFtraceEvent::kHeapNameFieldNumber) ==
716 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
717 kHeapNameFieldNumber),
718 "ION field mismatch");
719 }
720
ParseCpuFreq(int64_t ts,ConstBytes blob)721 void ProtoTraceParser::ParseCpuFreq(int64_t ts, ConstBytes blob) {
722 protos::pbzero::CpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
723 uint32_t cpu = freq.cpu_id();
724 uint32_t new_freq = freq.state();
725 context_->event_tracker->PushCounter(ts, new_freq, cpu_freq_name_id_, cpu,
726 RefType::kRefCpuId);
727 }
728
ParseCpuIdle(int64_t ts,ConstBytes blob)729 void ProtoTraceParser::ParseCpuIdle(int64_t ts, ConstBytes blob) {
730 protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob.data, blob.size);
731 uint32_t cpu = idle.cpu_id();
732 uint32_t new_state = idle.state();
733 context_->event_tracker->PushCounter(ts, new_state, cpu_idle_name_id_, cpu,
734 RefType::kRefCpuId);
735 }
736
737 PERFETTO_ALWAYS_INLINE
ParseSchedSwitch(uint32_t cpu,int64_t ts,ConstBytes blob)738 void ProtoTraceParser::ParseSchedSwitch(uint32_t cpu,
739 int64_t ts,
740 ConstBytes blob) {
741 protos::pbzero::SchedSwitchFtraceEvent::Decoder ss(blob.data, blob.size);
742 uint32_t prev_pid = static_cast<uint32_t>(ss.prev_pid());
743 uint32_t next_pid = static_cast<uint32_t>(ss.next_pid());
744 context_->event_tracker->PushSchedSwitch(
745 cpu, ts, prev_pid, ss.prev_comm(), ss.prev_prio(), ss.prev_state(),
746 next_pid, ss.next_comm(), ss.next_prio());
747 }
748
ParseSchedWakeup(int64_t ts,ConstBytes blob)749 void ProtoTraceParser::ParseSchedWakeup(int64_t ts, ConstBytes blob) {
750 protos::pbzero::SchedWakeupFtraceEvent::Decoder sw(blob.data, blob.size);
751 uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
752 StringId name_id = context_->storage->InternString(sw.comm());
753 auto utid = context_->process_tracker->UpdateThreadName(wakee_pid, name_id);
754 context_->event_tracker->PushInstant(ts, sched_wakeup_name_id_, 0 /* value */,
755 utid, RefType::kRefUtid);
756 }
757
ParseTaskNewTask(int64_t ts,uint32_t source_tid,ConstBytes blob)758 void ProtoTraceParser::ParseTaskNewTask(int64_t ts,
759 uint32_t source_tid,
760 ConstBytes blob) {
761 protos::pbzero::TaskNewtaskFtraceEvent::Decoder evt(blob.data, blob.size);
762 uint32_t clone_flags = static_cast<uint32_t>(evt.clone_flags());
763 uint32_t new_tid = static_cast<uint32_t>(evt.pid());
764 StringId new_comm = context_->storage->InternString(evt.comm());
765 auto* proc_tracker = context_->process_tracker.get();
766
767 // task_newtask is raised both in the case of a new process creation (fork()
768 // family) and thread creation (clone(CLONE_THREAD, ...)).
769 static const uint32_t kCloneThread = 0x00010000; // From kernel's sched.h.
770 if ((clone_flags & kCloneThread) == 0) {
771 // This is a plain-old fork() or equivalent.
772 proc_tracker->StartNewProcess(ts, new_tid);
773 return;
774 }
775
776 // This is a pthread_create or similar. Bind the two threads together, so
777 // they get resolved to the same process.
778 auto source_utid = proc_tracker->GetOrCreateThread(source_tid);
779 auto new_utid = proc_tracker->StartNewThread(ts, new_tid, new_comm);
780 proc_tracker->AssociateThreads(source_utid, new_utid);
781 }
782
ParseTaskRename(ConstBytes blob)783 void ProtoTraceParser::ParseTaskRename(ConstBytes blob) {
784 protos::pbzero::TaskRenameFtraceEvent::Decoder evt(blob.data, blob.size);
785 uint32_t tid = static_cast<uint32_t>(evt.pid());
786 StringId comm = context_->storage->InternString(evt.newcomm());
787 context_->process_tracker->UpdateThreadName(tid, comm);
788 }
789
ParsePrint(uint32_t,int64_t ts,uint32_t pid,ConstBytes blob)790 void ProtoTraceParser::ParsePrint(uint32_t,
791 int64_t ts,
792 uint32_t pid,
793 ConstBytes blob) {
794 protos::pbzero::PrintFtraceEvent::Decoder evt(blob.data, blob.size);
795 SystraceTracePoint point{};
796 auto r = ParseSystraceTracePoint(evt.buf(), &point);
797 if (r != SystraceParseResult::kSuccess) {
798 if (r == SystraceParseResult::kFailure) {
799 context_->storage->IncrementStats(stats::systrace_parse_failure);
800 }
801 return;
802 }
803
804 switch (point.phase) {
805 case 'B': {
806 StringId name_id = context_->storage->InternString(point.name);
807 context_->slice_tracker->BeginAndroid(ts, pid, point.tgid, 0 /*cat_id*/,
808 name_id);
809 break;
810 }
811
812 case 'E': {
813 context_->slice_tracker->EndAndroid(ts, pid, point.tgid);
814 break;
815 }
816
817 case 'C': {
818 // LMK events from userspace are hacked as counter events with the "value"
819 // of the counter representing the pid of the killed process which is
820 // reset to 0 once the kill is complete.
821 // Homogenise this with kernel LMK events as an instant event, ignoring
822 // the resets to 0.
823 if (point.name == "kill_one_process") {
824 auto killed_pid = static_cast<uint32_t>(point.value);
825 if (killed_pid != 0) {
826 UniquePid killed_upid =
827 context_->process_tracker->GetOrCreateProcess(killed_pid);
828 context_->event_tracker->PushInstant(ts, lmk_id_, 0, killed_upid,
829 RefType::kRefUpid);
830 }
831 // TODO(lalitm): we should not add LMK events to the counters table
832 // once the UI has support for displaying instants.
833 }
834 // This is per upid on purpose. Some counters are pushed from arbitrary
835 // threads but are really per process.
836 UniquePid upid =
837 context_->process_tracker->GetOrCreateProcess(point.tgid);
838 StringId name_id = context_->storage->InternString(point.name);
839 context_->event_tracker->PushCounter(ts, point.value, name_id, upid,
840 RefType::kRefUpid);
841 }
842 }
843 }
844
ParseBatteryCounters(int64_t ts,ConstBytes blob)845 void ProtoTraceParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
846 protos::pbzero::BatteryCounters::Decoder evt(blob.data, blob.size);
847 if (evt.has_charge_counter_uah()) {
848 context_->event_tracker->PushCounter(
849 ts, evt.charge_counter_uah(), batt_charge_id_, 0, RefType::kRefNoRef);
850 }
851 if (evt.has_capacity_percent()) {
852 context_->event_tracker->PushCounter(
853 ts, static_cast<double>(evt.capacity_percent()), batt_capacity_id_, 0,
854 RefType::kRefNoRef);
855 }
856 if (evt.has_current_ua()) {
857 context_->event_tracker->PushCounter(ts, evt.current_ua(), batt_current_id_,
858 0, RefType::kRefNoRef);
859 }
860 if (evt.has_current_avg_ua()) {
861 context_->event_tracker->PushCounter(
862 ts, evt.current_avg_ua(), batt_current_avg_id_, 0, RefType::kRefNoRef);
863 }
864 }
865
ParsePowerRails(ConstBytes blob)866 void ProtoTraceParser::ParsePowerRails(ConstBytes blob) {
867 protos::pbzero::PowerRails::Decoder evt(blob.data, blob.size);
868 if (evt.has_rail_descriptor()) {
869 for (auto it = evt.rail_descriptor(); it; ++it) {
870 protos::pbzero::PowerRails::RailDescriptor::Decoder desc(it->data(),
871 it->size());
872 uint32_t idx = desc.index();
873 if (PERFETTO_UNLIKELY(idx > 256)) {
874 PERFETTO_DLOG("Skipping excessively large power_rail index %" PRIu32,
875 idx);
876 continue;
877 }
878 if (power_rails_strs_id_.size() <= idx)
879 power_rails_strs_id_.resize(idx + 1);
880 char counter_name[255];
881 snprintf(counter_name, sizeof(counter_name), "power.%.*s_uws",
882 int(desc.rail_name().size), desc.rail_name().data);
883 power_rails_strs_id_[idx] = context_->storage->InternString(counter_name);
884 }
885 }
886
887 if (evt.has_energy_data()) {
888 for (auto it = evt.energy_data(); it; ++it) {
889 protos::pbzero::PowerRails::EnergyData::Decoder desc(it->data(),
890 it->size());
891 if (desc.index() < power_rails_strs_id_.size()) {
892 int64_t ts = static_cast<int64_t>(desc.timestamp_ms()) * 1000000;
893 context_->event_tracker->PushCounter(ts, desc.energy(),
894 power_rails_strs_id_[desc.index()],
895 0, RefType::kRefNoRef);
896 } else {
897 context_->storage->IncrementStats(stats::power_rail_unknown_index);
898 }
899 }
900 }
901 }
902
ParseOOMScoreAdjUpdate(int64_t ts,ConstBytes blob)903 void ProtoTraceParser::ParseOOMScoreAdjUpdate(int64_t ts, ConstBytes blob) {
904 protos::pbzero::OomScoreAdjUpdateFtraceEvent::Decoder evt(blob.data,
905 blob.size);
906 // The int16_t static cast is because older version of the on-device tracer
907 // had a bug on negative varint encoding (b/120618641).
908 int16_t oom_adj = static_cast<int16_t>(evt.oom_score_adj());
909 uint32_t pid = static_cast<uint32_t>(evt.pid());
910 UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
911 context_->event_tracker->PushCounter(ts, oom_adj, oom_score_adj_id_, upid,
912 RefType::kRefUpid);
913 }
914
ParseMmEventRecord(int64_t ts,uint32_t pid,ConstBytes blob)915 void ProtoTraceParser::ParseMmEventRecord(int64_t ts,
916 uint32_t pid,
917 ConstBytes blob) {
918 protos::pbzero::MmEventRecordFtraceEvent::Decoder evt(blob.data, blob.size);
919 uint32_t type = evt.type();
920 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
921
922 if (type >= mm_event_counter_names_.size()) {
923 context_->storage->IncrementStats(stats::mm_unknown_type);
924 return;
925 }
926
927 const auto& counter_names = mm_event_counter_names_[type];
928 context_->event_tracker->PushCounter(ts, evt.count(), counter_names.count,
929 utid, RefType::kRefUtid, true);
930 context_->event_tracker->PushCounter(ts, evt.max_lat(), counter_names.max_lat,
931 utid, RefType::kRefUtid, true);
932 context_->event_tracker->PushCounter(ts, evt.avg_lat(), counter_names.avg_lat,
933 utid, RefType::kRefUtid, true);
934 }
935
ParseSysEvent(int64_t ts,uint32_t pid,bool is_enter,ConstBytes blob)936 void ProtoTraceParser::ParseSysEvent(int64_t ts,
937 uint32_t pid,
938 bool is_enter,
939 ConstBytes blob) {
940 protos::pbzero::SysEnterFtraceEvent::Decoder evt(blob.data, blob.size);
941 uint32_t syscall_num = static_cast<uint32_t>(evt.id());
942 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
943
944 if (is_enter) {
945 context_->syscall_tracker->Enter(ts, utid, syscall_num);
946 } else {
947 context_->syscall_tracker->Exit(ts, utid, syscall_num);
948 }
949
950 // We are reusing the same function for sys_enter and sys_exit.
951 // It is fine as the arguments are the same, but we need to be sure that the
952 // protobuf field id for both are the same.
953 static_assert(
954 static_cast<int>(protos::pbzero::SysEnterFtraceEvent::kIdFieldNumber) ==
955 static_cast<int>(protos::pbzero::SysExitFtraceEvent::kIdFieldNumber),
956 "field mismatch");
957 }
958
ParseGenericFtrace(int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)959 void ProtoTraceParser::ParseGenericFtrace(int64_t ts,
960 uint32_t cpu,
961 uint32_t tid,
962 ConstBytes blob) {
963 protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
964 StringId event_id = context_->storage->InternString(evt.event_name());
965 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
966 RowId row_id = context_->storage->mutable_raw_events()->AddRawEvent(
967 ts, event_id, cpu, utid);
968
969 for (auto it = evt.field(); it; ++it) {
970 protos::pbzero::GenericFtraceEvent::Field::Decoder fld(it->data(),
971 it->size());
972 auto field_name_id = context_->storage->InternString(fld.name());
973 if (fld.has_int_value()) {
974 context_->args_tracker->AddArg(row_id, field_name_id, field_name_id,
975 Variadic::Integer(fld.int_value()));
976 } else if (fld.has_uint_value()) {
977 context_->args_tracker->AddArg(
978 row_id, field_name_id, field_name_id,
979 Variadic::Integer(static_cast<int64_t>(fld.uint_value())));
980 } else if (fld.has_str_value()) {
981 StringId str_value = context_->storage->InternString(fld.str_value());
982 context_->args_tracker->AddArg(row_id, field_name_id, field_name_id,
983 Variadic::String(str_value));
984 }
985 }
986 }
987
ParseTypedFtraceToRaw(uint32_t ftrace_id,int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)988 void ProtoTraceParser::ParseTypedFtraceToRaw(uint32_t ftrace_id,
989 int64_t ts,
990 uint32_t cpu,
991 uint32_t tid,
992 ConstBytes blob) {
993 ProtoDecoder decoder(blob.data, blob.size);
994 if (ftrace_id >= GetDescriptorsSize()) {
995 PERFETTO_DLOG("Event with id: %d does not exist and cannot be parsed.",
996 ftrace_id);
997 return;
998 }
999
1000 MessageDescriptor* m = GetMessageDescriptorForId(ftrace_id);
1001 const auto& message_strings = ftrace_message_strings_[ftrace_id];
1002 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
1003 RowId raw_event_id = context_->storage->mutable_raw_events()->AddRawEvent(
1004 ts, message_strings.message_name_id, cpu, utid);
1005 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
1006 if (PERFETTO_UNLIKELY(fld.id() >= kMaxFtraceEventFields)) {
1007 PERFETTO_DLOG(
1008 "Skipping ftrace arg - proto field id is too large (%" PRIu16 ")",
1009 fld.id());
1010 continue;
1011 }
1012 ProtoSchemaType type = m->fields[fld.id()].type;
1013 StringId name_id = message_strings.field_name_ids[fld.id()];
1014 switch (type) {
1015 case ProtoSchemaType::kUint32:
1016 case ProtoSchemaType::kInt32:
1017 case ProtoSchemaType::kUint64:
1018 case ProtoSchemaType::kInt64:
1019 case ProtoSchemaType::kFixed64:
1020 case ProtoSchemaType::kFixed32:
1021 case ProtoSchemaType::kSfixed32:
1022 case ProtoSchemaType::kSfixed64:
1023 case ProtoSchemaType::kSint32:
1024 case ProtoSchemaType::kSint64:
1025 case ProtoSchemaType::kBool:
1026 case ProtoSchemaType::kEnum: {
1027 context_->args_tracker->AddArg(raw_event_id, name_id, name_id,
1028 Variadic::Integer(fld.as_int64()));
1029 break;
1030 }
1031 case ProtoSchemaType::kString:
1032 case ProtoSchemaType::kBytes: {
1033 StringId value = context_->storage->InternString(fld.as_string());
1034 context_->args_tracker->AddArg(raw_event_id, name_id, name_id,
1035 Variadic::String(value));
1036 break;
1037 }
1038 case ProtoSchemaType::kDouble: {
1039 context_->args_tracker->AddArg(raw_event_id, name_id, name_id,
1040 Variadic::Real(fld.as_double()));
1041 break;
1042 }
1043 case ProtoSchemaType::kFloat: {
1044 context_->args_tracker->AddArg(
1045 raw_event_id, name_id, name_id,
1046 Variadic::Real(static_cast<double>(fld.as_float())));
1047 break;
1048 }
1049 case ProtoSchemaType::kUnknown:
1050 case ProtoSchemaType::kGroup:
1051 case ProtoSchemaType::kMessage:
1052 PERFETTO_DLOG("Could not store %s as a field in args table.",
1053 ProtoSchemaToString(type));
1054 break;
1055 }
1056 }
1057 }
1058
ParseClockSnapshot(ConstBytes blob)1059 void ProtoTraceParser::ParseClockSnapshot(ConstBytes blob) {
1060 protos::pbzero::ClockSnapshot::Decoder evt(blob.data, blob.size);
1061 int64_t clock_boottime = 0;
1062 int64_t clock_monotonic = 0;
1063 int64_t clock_realtime = 0;
1064 for (auto it = evt.clocks(); it; ++it) {
1065 protos::pbzero::ClockSnapshot::Clock::Decoder clk(it->data(), it->size());
1066 if (clk.type() == protos::pbzero::ClockSnapshot::Clock::BOOTTIME) {
1067 clock_boottime = static_cast<int64_t>(clk.timestamp());
1068 } else if (clk.type() == protos::pbzero::ClockSnapshot::Clock::REALTIME) {
1069 clock_realtime = static_cast<int64_t>(clk.timestamp());
1070 } else if (clk.type() == protos::pbzero::ClockSnapshot::Clock::MONOTONIC) {
1071 clock_monotonic = static_cast<int64_t>(clk.timestamp());
1072 }
1073 }
1074
1075 // Usually these snapshots come all together.
1076 PERFETTO_DCHECK(clock_boottime > 0 && clock_monotonic > 0 &&
1077 clock_realtime > 0);
1078
1079 if (clock_boottime <= 0) {
1080 PERFETTO_ELOG("ClockSnapshot has an invalid BOOTTIME (%" PRId64 ")",
1081 clock_boottime);
1082 context_->storage->IncrementStats(stats::invalid_clock_snapshots);
1083 return;
1084 }
1085
1086 auto* ct = context_->clock_tracker.get();
1087
1088 // |clock_boottime| is used as the reference trace time.
1089 ct->SyncClocks(ClockDomain::kBootTime, clock_boottime, clock_boottime);
1090
1091 if (clock_monotonic > 0)
1092 ct->SyncClocks(ClockDomain::kMonotonic, clock_monotonic, clock_boottime);
1093
1094 if (clock_realtime > 0)
1095 ct->SyncClocks(ClockDomain::kRealTime, clock_realtime, clock_boottime);
1096 }
1097
ParseAndroidLogPacket(ConstBytes blob)1098 void ProtoTraceParser::ParseAndroidLogPacket(ConstBytes blob) {
1099 protos::pbzero::AndroidLogPacket::Decoder packet(blob.data, blob.size);
1100 for (auto it = packet.events(); it; ++it)
1101 ParseAndroidLogEvent(it->as_bytes());
1102
1103 if (packet.has_stats())
1104 ParseAndroidLogStats(packet.stats());
1105 }
1106
ParseAndroidLogEvent(ConstBytes blob)1107 void ProtoTraceParser::ParseAndroidLogEvent(ConstBytes blob) {
1108 // TODO(primiano): Add events and non-stringified fields to the "raw" table.
1109 protos::pbzero::AndroidLogPacket::LogEvent::Decoder evt(blob.data, blob.size);
1110 int64_t ts = static_cast<int64_t>(evt.timestamp());
1111 uint32_t pid = static_cast<uint32_t>(evt.pid());
1112 uint32_t tid = static_cast<uint32_t>(evt.tid());
1113 uint8_t prio = static_cast<uint8_t>(evt.prio());
1114 StringId tag_id = context_->storage->InternString(
1115 evt.has_tag() ? evt.tag() : base::StringView());
1116 StringId msg_id = context_->storage->InternString(
1117 evt.has_message() ? evt.message() : base::StringView());
1118
1119 char arg_msg[4096];
1120 char* arg_str = &arg_msg[0];
1121 *arg_str = '\0';
1122 auto arg_avail = [&arg_msg, &arg_str]() {
1123 return sizeof(arg_msg) - static_cast<size_t>(arg_str - arg_msg);
1124 };
1125 for (auto it = evt.args(); it; ++it) {
1126 protos::pbzero::AndroidLogPacket::LogEvent::Arg::Decoder arg(it->data(),
1127 it->size());
1128 if (!arg.has_name())
1129 continue;
1130 arg_str +=
1131 snprintf(arg_str, arg_avail(),
1132 " %.*s=", static_cast<int>(arg.name().size), arg.name().data);
1133 if (arg.has_string_value()) {
1134 arg_str += snprintf(arg_str, arg_avail(), "\"%.*s\"",
1135 static_cast<int>(arg.string_value().size),
1136 arg.string_value().data);
1137 } else if (arg.has_int_value()) {
1138 arg_str += snprintf(arg_str, arg_avail(), "%" PRId64, arg.int_value());
1139 } else if (arg.has_float_value()) {
1140 arg_str += snprintf(arg_str, arg_avail(), "%f",
1141 static_cast<double>(arg.float_value()));
1142 }
1143 }
1144
1145 if (prio == 0)
1146 prio = protos::pbzero::AndroidLogPriority::PRIO_INFO;
1147
1148 if (arg_str != &arg_msg[0]) {
1149 PERFETTO_DCHECK(!msg_id);
1150 // Skip the first space char (" foo=1 bar=2" -> "foo=1 bar=2").
1151 msg_id = context_->storage->InternString(&arg_msg[1]);
1152 }
1153 UniquePid utid = tid ? context_->process_tracker->UpdateThread(tid, pid) : 0;
1154 base::Optional<int64_t> opt_trace_time =
1155 context_->clock_tracker->ToTraceTime(ClockDomain::kRealTime, ts);
1156 if (!opt_trace_time)
1157 return;
1158
1159 // Log events are NOT required to be sorted by trace_time. The virtual table
1160 // will take care of sorting on-demand.
1161 context_->storage->mutable_android_log()->AddLogEvent(
1162 opt_trace_time.value(), utid, prio, tag_id, msg_id);
1163 }
1164
ParseAndroidLogStats(ConstBytes blob)1165 void ProtoTraceParser::ParseAndroidLogStats(ConstBytes blob) {
1166 protos::pbzero::AndroidLogPacket::Stats::Decoder evt(blob.data, blob.size);
1167 if (evt.has_num_failed()) {
1168 context_->storage->SetStats(stats::android_log_num_failed,
1169 static_cast<int64_t>(evt.num_failed()));
1170 }
1171
1172 if (evt.has_num_skipped()) {
1173 context_->storage->SetStats(stats::android_log_num_skipped,
1174 static_cast<int64_t>(evt.num_skipped()));
1175 }
1176
1177 if (evt.has_num_total()) {
1178 context_->storage->SetStats(stats::android_log_num_total,
1179 static_cast<int64_t>(evt.num_total()));
1180 }
1181 }
1182
ParseTraceStats(ConstBytes blob)1183 void ProtoTraceParser::ParseTraceStats(ConstBytes blob) {
1184 protos::pbzero::TraceStats::Decoder evt(blob.data, blob.size);
1185 auto* storage = context_->storage.get();
1186 storage->SetStats(stats::traced_producers_connected,
1187 static_cast<int64_t>(evt.producers_connected()));
1188 storage->SetStats(stats::traced_data_sources_registered,
1189 static_cast<int64_t>(evt.data_sources_registered()));
1190 storage->SetStats(stats::traced_data_sources_seen,
1191 static_cast<int64_t>(evt.data_sources_seen()));
1192 storage->SetStats(stats::traced_tracing_sessions,
1193 static_cast<int64_t>(evt.tracing_sessions()));
1194 storage->SetStats(stats::traced_total_buffers,
1195 static_cast<int64_t>(evt.total_buffers()));
1196 storage->SetStats(stats::traced_chunks_discarded,
1197 static_cast<int64_t>(evt.chunks_discarded()));
1198 storage->SetStats(stats::traced_patches_discarded,
1199 static_cast<int64_t>(evt.patches_discarded()));
1200
1201 int buf_num = 0;
1202 for (auto it = evt.buffer_stats(); it; ++it, ++buf_num) {
1203 protos::pbzero::TraceStats::BufferStats::Decoder buf(it->data(),
1204 it->size());
1205 storage->SetIndexedStats(stats::traced_buf_buffer_size, buf_num,
1206 static_cast<int64_t>(buf.buffer_size()));
1207 storage->SetIndexedStats(stats::traced_buf_bytes_written, buf_num,
1208 static_cast<int64_t>(buf.bytes_written()));
1209 storage->SetIndexedStats(stats::traced_buf_bytes_overwritten, buf_num,
1210 static_cast<int64_t>(buf.bytes_overwritten()));
1211 storage->SetIndexedStats(stats::traced_buf_bytes_read, buf_num,
1212 static_cast<int64_t>(buf.bytes_read()));
1213 storage->SetIndexedStats(stats::traced_buf_padding_bytes_written, buf_num,
1214 static_cast<int64_t>(buf.padding_bytes_written()));
1215 storage->SetIndexedStats(stats::traced_buf_padding_bytes_cleared, buf_num,
1216 static_cast<int64_t>(buf.padding_bytes_cleared()));
1217 storage->SetIndexedStats(stats::traced_buf_chunks_written, buf_num,
1218 static_cast<int64_t>(buf.chunks_written()));
1219 storage->SetIndexedStats(stats::traced_buf_chunks_rewritten, buf_num,
1220 static_cast<int64_t>(buf.chunks_rewritten()));
1221 storage->SetIndexedStats(stats::traced_buf_chunks_overwritten, buf_num,
1222 static_cast<int64_t>(buf.chunks_overwritten()));
1223 storage->SetIndexedStats(stats::traced_buf_chunks_discarded, buf_num,
1224 static_cast<int64_t>(buf.chunks_discarded()));
1225 storage->SetIndexedStats(stats::traced_buf_chunks_read, buf_num,
1226 static_cast<int64_t>(buf.chunks_read()));
1227 storage->SetIndexedStats(
1228 stats::traced_buf_chunks_committed_out_of_order, buf_num,
1229 static_cast<int64_t>(buf.chunks_committed_out_of_order()));
1230 storage->SetIndexedStats(stats::traced_buf_write_wrap_count, buf_num,
1231 static_cast<int64_t>(buf.write_wrap_count()));
1232 storage->SetIndexedStats(stats::traced_buf_patches_succeeded, buf_num,
1233 static_cast<int64_t>(buf.patches_succeeded()));
1234 storage->SetIndexedStats(stats::traced_buf_patches_failed, buf_num,
1235 static_cast<int64_t>(buf.patches_failed()));
1236 storage->SetIndexedStats(stats::traced_buf_readaheads_succeeded, buf_num,
1237 static_cast<int64_t>(buf.readaheads_succeeded()));
1238 storage->SetIndexedStats(stats::traced_buf_readaheads_failed, buf_num,
1239 static_cast<int64_t>(buf.readaheads_failed()));
1240 }
1241 }
1242
ParseFtraceStats(ConstBytes blob)1243 void ProtoTraceParser::ParseFtraceStats(ConstBytes blob) {
1244 protos::pbzero::FtraceStats::Decoder evt(blob.data, blob.size);
1245 size_t phase =
1246 evt.phase() == protos::pbzero::FtraceStats_Phase_END_OF_TRACE ? 1 : 0;
1247
1248 // This code relies on the fact that each ftrace_cpu_XXX_end event is
1249 // just after the corresponding ftrace_cpu_XXX_begin event.
1250 static_assert(
1251 stats::ftrace_cpu_read_events_end - stats::ftrace_cpu_read_events_begin ==
1252 1 &&
1253 stats::ftrace_cpu_entries_end - stats::ftrace_cpu_entries_begin == 1,
1254 "ftrace_cpu_XXX stats definition are messed up");
1255
1256 auto* storage = context_->storage.get();
1257 for (auto it = evt.cpu_stats(); it; ++it) {
1258 protos::pbzero::FtraceCpuStats::Decoder cpu_stats(it->data(), it->size());
1259 int cpu = static_cast<int>(cpu_stats.cpu());
1260 storage->SetIndexedStats(stats::ftrace_cpu_entries_begin + phase, cpu,
1261 static_cast<int64_t>(cpu_stats.entries()));
1262 storage->SetIndexedStats(stats::ftrace_cpu_overrun_begin + phase, cpu,
1263 static_cast<int64_t>(cpu_stats.overrun()));
1264 storage->SetIndexedStats(stats::ftrace_cpu_commit_overrun_begin + phase,
1265 cpu,
1266 static_cast<int64_t>(cpu_stats.commit_overrun()));
1267 storage->SetIndexedStats(stats::ftrace_cpu_bytes_read_begin + phase, cpu,
1268 static_cast<int64_t>(cpu_stats.bytes_read()));
1269
1270 // oldest_event_ts can often be set to very high values, possibly because
1271 // of wrapping. Ensure that we are not overflowing to avoid ubsan
1272 // complaining.
1273 double oldest_event_ts = cpu_stats.oldest_event_ts() * 1e9;
1274 if (oldest_event_ts >= std::numeric_limits<int64_t>::max()) {
1275 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
1276 cpu, std::numeric_limits<int64_t>::max());
1277 } else {
1278 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
1279 cpu, static_cast<int64_t>(oldest_event_ts));
1280 }
1281
1282 storage->SetIndexedStats(stats::ftrace_cpu_now_ts_begin + phase, cpu,
1283 static_cast<int64_t>(cpu_stats.now_ts() * 1e9));
1284 storage->SetIndexedStats(stats::ftrace_cpu_dropped_events_begin + phase,
1285 cpu,
1286 static_cast<int64_t>(cpu_stats.dropped_events()));
1287 storage->SetIndexedStats(stats::ftrace_cpu_read_events_begin + phase, cpu,
1288 static_cast<int64_t>(cpu_stats.read_events()));
1289 }
1290 }
1291
ParseProfilePacket(ConstBytes blob)1292 void ProtoTraceParser::ParseProfilePacket(ConstBytes blob) {
1293 uint64_t index = 0;
1294 protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
1295
1296 for (auto it = packet.strings(); it; ++it) {
1297 protos::pbzero::ProfilePacket::InternedString::Decoder entry(it->data(),
1298 it->size());
1299
1300 const char* str = reinterpret_cast<const char*>(entry.str().data);
1301 auto str_id = context_->storage->InternString(
1302 base::StringView(str, entry.str().size));
1303 context_->heap_profile_tracker->AddString(index, entry.id(), str_id);
1304 }
1305
1306 for (auto it = packet.mappings(); it; ++it) {
1307 protos::pbzero::ProfilePacket::Mapping::Decoder entry(it->data(),
1308 it->size());
1309 HeapProfileTracker::SourceMapping src_mapping;
1310 src_mapping.build_id = entry.build_id();
1311 src_mapping.offset = entry.offset();
1312 src_mapping.start = entry.start();
1313 src_mapping.end = entry.end();
1314 src_mapping.load_bias = entry.load_bias();
1315 src_mapping.name_id = 0;
1316 for (auto path_string_id_it = entry.path_string_ids(); path_string_id_it;
1317 ++path_string_id_it)
1318 src_mapping.name_id = path_string_id_it->as_uint64();
1319 context_->heap_profile_tracker->AddMapping(index, entry.id(), src_mapping);
1320 }
1321
1322 for (auto it = packet.frames(); it; ++it) {
1323 protos::pbzero::ProfilePacket::Frame::Decoder entry(it->data(), it->size());
1324 HeapProfileTracker::SourceFrame src_frame;
1325 src_frame.name_id = entry.function_name_id();
1326 src_frame.mapping_id = entry.mapping_id();
1327 src_frame.rel_pc = entry.rel_pc();
1328
1329 context_->heap_profile_tracker->AddFrame(index, entry.id(), src_frame);
1330 }
1331
1332 for (auto it = packet.callstacks(); it; ++it) {
1333 protos::pbzero::ProfilePacket::Callstack::Decoder entry(it->data(),
1334 it->size());
1335 HeapProfileTracker::SourceCallstack src_callstack;
1336 for (auto frame_it = entry.frame_ids(); frame_it; ++frame_it)
1337 src_callstack.emplace_back(frame_it->as_uint64());
1338
1339 context_->heap_profile_tracker->AddCallstack(index, entry.id(),
1340 src_callstack);
1341 }
1342
1343 for (auto it = packet.process_dumps(); it; ++it) {
1344 protos::pbzero::ProfilePacket::ProcessHeapSamples::Decoder entry(
1345 it->data(), it->size());
1346
1347 int pid = static_cast<int>(entry.pid());
1348
1349 if (entry.buffer_corrupted())
1350 context_->storage->IncrementIndexedStats(
1351 stats::heapprofd_buffer_corrupted, pid);
1352 if (entry.buffer_overran())
1353 context_->storage->IncrementIndexedStats(stats::heapprofd_buffer_overran,
1354 pid);
1355 if (entry.rejected_concurrent())
1356 context_->storage->IncrementIndexedStats(
1357 stats::heapprofd_rejected_concurrent, pid);
1358
1359 for (auto sample_it = entry.samples(); sample_it; ++sample_it) {
1360 protos::pbzero::ProfilePacket::HeapSample::Decoder sample(
1361 sample_it->data(), sample_it->size());
1362
1363 HeapProfileTracker::SourceAllocation src_allocation;
1364 src_allocation.pid = entry.pid();
1365 src_allocation.timestamp = sample.timestamp();
1366 src_allocation.callstack_id = sample.callstack_id();
1367 src_allocation.self_allocated = sample.self_allocated();
1368 src_allocation.self_freed = sample.self_freed();
1369 src_allocation.alloc_count = sample.alloc_count();
1370 src_allocation.free_count = sample.free_count();
1371
1372 context_->heap_profile_tracker->StoreAllocation(index, src_allocation);
1373 }
1374 }
1375 if (!packet.continued()) {
1376 context_->heap_profile_tracker->ApplyAllAllocations();
1377 index++;
1378 }
1379 }
1380
ParseSystemInfo(ConstBytes blob)1381 void ProtoTraceParser::ParseSystemInfo(ConstBytes blob) {
1382 protos::pbzero::SystemInfo::Decoder packet(blob.data, blob.size);
1383 if (packet.has_utsname()) {
1384 ConstBytes utsname_blob = packet.utsname();
1385 protos::pbzero::Utsname::Decoder utsname(utsname_blob.data,
1386 utsname_blob.size);
1387 base::StringView machine = utsname.machine();
1388 if (machine == "aarch64" || machine == "armv8l") {
1389 context_->syscall_tracker->SetArchitecture(kAarch64);
1390 } else if (machine == "x86_64") {
1391 context_->syscall_tracker->SetArchitecture(kX86_64);
1392 } else {
1393 PERFETTO_ELOG("Unknown architecture %s", machine.ToStdString().c_str());
1394 }
1395 }
1396 }
1397
ParseTrackEvent(int64_t ts,int64_t,ProtoIncrementalState::PacketSequenceState * sequence_state,ConstBytes blob)1398 void ProtoTraceParser::ParseTrackEvent(
1399 int64_t ts,
1400 int64_t /*tts*/,
1401 ProtoIncrementalState::PacketSequenceState* sequence_state,
1402 ConstBytes blob) {
1403 protos::pbzero::TrackEvent::Decoder event(blob.data, blob.size);
1404
1405 const auto legacy_event_blob = event.legacy_event();
1406 protos::pbzero::TrackEvent::LegacyEvent::Decoder legacy_event(
1407 legacy_event_blob.data, legacy_event_blob.size);
1408
1409 // TODO(eseckler): This legacy event field will eventually be replaced by
1410 // fields in TrackEvent itself.
1411 if (PERFETTO_UNLIKELY(!legacy_event.has_phase())) {
1412 PERFETTO_ELOG("TrackEvent without phase");
1413 return;
1414 }
1415
1416 ProcessTracker* procs = context_->process_tracker.get();
1417 TraceStorage* storage = context_->storage.get();
1418 SliceTracker* slice_tracker = context_->slice_tracker.get();
1419
1420 uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
1421 uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
1422 if (legacy_event.has_pid_override())
1423 pid = static_cast<uint32_t>(legacy_event.pid_override());
1424 if (legacy_event.has_tid_override())
1425 tid = static_cast<uint32_t>(legacy_event.tid_override());
1426 UniqueTid utid = procs->UpdateThread(tid, pid);
1427
1428 std::vector<uint32_t> category_iids;
1429 for (auto it = event.category_iids(); it; ++it) {
1430 category_iids.push_back(it->as_uint32());
1431 }
1432
1433 StringId category_id = 0;
1434
1435 // If there's a single category, we can avoid building a concatenated string.
1436 if (PERFETTO_LIKELY(category_iids.size() == 1)) {
1437 auto* map =
1438 sequence_state->GetInternedDataMap<protos::pbzero::EventCategory>();
1439 auto cat_view_it = map->find(category_iids[0]);
1440 if (cat_view_it == map->end()) {
1441 PERFETTO_ELOG("Could not find category interning entry for ID %u",
1442 category_iids[0]);
1443 } else {
1444 // If the name is already in the pool, no need to decode it again.
1445 if (cat_view_it->second.storage_refs) {
1446 category_id = cat_view_it->second.storage_refs->name_id;
1447 } else {
1448 auto cat = cat_view_it->second.CreateDecoder();
1449 category_id = storage->InternString(cat.name());
1450 // Avoid having to decode & look up the name again in the future.
1451 cat_view_it->second.storage_refs =
1452 ProtoIncrementalState::StorageReferences<
1453 protos::pbzero::EventCategory>{category_id};
1454 }
1455 }
1456 } else if (category_iids.size() > 1) {
1457 auto* map =
1458 sequence_state->GetInternedDataMap<protos::pbzero::EventCategory>();
1459 // We concatenate the category strings together since we currently only
1460 // support a single "cat" column.
1461 // TODO(eseckler): Support multi-category events in the table schema.
1462 std::string categories;
1463 for (uint32_t iid : category_iids) {
1464 auto cat_view_it = map->find(iid);
1465 if (cat_view_it == map->end()) {
1466 PERFETTO_ELOG("Could not find category interning entry for ID %u", iid);
1467 continue;
1468 }
1469 auto cat = cat_view_it->second.CreateDecoder();
1470 base::StringView name = cat.name();
1471 if (!categories.empty())
1472 categories.append(",");
1473 categories.append(name.data(), name.size());
1474 }
1475 if (!categories.empty())
1476 category_id = storage->InternString(base::StringView(categories));
1477 } else {
1478 PERFETTO_ELOG("TrackEvent without category");
1479 }
1480
1481 StringId name_id = 0;
1482
1483 if (PERFETTO_LIKELY(legacy_event.name_iid())) {
1484 auto* map =
1485 sequence_state->GetInternedDataMap<protos::pbzero::LegacyEventName>();
1486 auto name_view_it = map->find(legacy_event.name_iid());
1487 if (name_view_it == map->end()) {
1488 PERFETTO_ELOG("Could not find event name interning entry for ID %u",
1489 legacy_event.name_iid());
1490 } else {
1491 // If the name is already in the pool, no need to decode it again.
1492 if (name_view_it->second.storage_refs) {
1493 name_id = name_view_it->second.storage_refs->name_id;
1494 } else {
1495 auto event_name = name_view_it->second.CreateDecoder();
1496 name_id = storage->InternString(event_name.name());
1497 // Avoid having to decode & look up the name again in the future.
1498 name_view_it->second.storage_refs =
1499 ProtoIncrementalState::StorageReferences<
1500 protos::pbzero::LegacyEventName>{name_id};
1501 }
1502 }
1503 }
1504
1505 // TODO(eseckler): Handle thread timestamp/duration, debug annotations, task
1506 // souce locations, legacy event attributes, ...
1507
1508 int32_t phase = legacy_event.phase();
1509 switch (static_cast<char>(phase)) {
1510 case 'B': { // TRACE_EVENT_PHASE_BEGIN.
1511 slice_tracker->Begin(ts, utid, category_id, name_id);
1512 break;
1513 }
1514 case 'E': { // TRACE_EVENT_PHASE_END.
1515 slice_tracker->End(ts, utid, category_id, name_id);
1516 break;
1517 }
1518 case 'X': { // TRACE_EVENT_PHASE_COMPLETE.
1519 auto duration_ns = legacy_event.duration_us() * 1000;
1520 if (duration_ns < 0)
1521 return;
1522 slice_tracker->Scoped(ts, utid, category_id, name_id, duration_ns);
1523 break;
1524 }
1525 case 'M': { // TRACE_EVENT_PHASE_METADATA (process and thread names).
1526 // For now, we just compare the event name and assume there's a single
1527 // argument in these events with the name of the process/thread.
1528 // TODO(eseckler): Use names from process/thread descriptors instead.
1529 NullTermStringView event_name = storage->GetString(name_id);
1530 PERFETTO_DCHECK(event_name.data());
1531 if (strcmp(event_name.c_str(), "thread_name") == 0) {
1532 auto it = event.debug_annotations();
1533 if (!it)
1534 break;
1535 protos::pbzero::DebugAnnotation::Decoder annotation(it->data(),
1536 it->size());
1537 auto thread_name = annotation.string_value();
1538 if (!thread_name.size)
1539 break;
1540 auto thread_name_id = context_->storage->InternString(thread_name);
1541 procs->UpdateThreadName(tid, thread_name_id);
1542 } else if (strcmp(event_name.c_str(), "process_name") == 0) {
1543 auto it = event.debug_annotations();
1544 if (!it)
1545 break;
1546 protos::pbzero::DebugAnnotation::Decoder annotation(it->data(),
1547 it->size());
1548 auto process_name = annotation.string_value();
1549 if (!process_name.size)
1550 break;
1551 procs->UpdateProcess(pid, base::nullopt, process_name);
1552 }
1553 break;
1554 }
1555 }
1556 }
1557
1558 } // namespace trace_processor
1559 } // namespace perfetto
1560