1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/ftrace/ftrace_parser.h"
18
19 #include "perfetto/base/logging.h"
20 #include "perfetto/protozero/proto_decoder.h"
21 #include "src/trace_processor/importers/common/args_tracker.h"
22 #include "src/trace_processor/importers/common/process_tracker.h"
23 #include "src/trace_processor/importers/ftrace/binder_tracker.h"
24 #include "src/trace_processor/importers/proto/async_track_set_tracker.h"
25 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
26 #include "src/trace_processor/importers/systrace/systrace_parser.h"
27 #include "src/trace_processor/storage/stats.h"
28 #include "src/trace_processor/storage/trace_storage.h"
29 #include "src/trace_processor/types/softirq_action.h"
30
31 #include "protos/perfetto/common/gpu_counter_descriptor.pbzero.h"
32 #include "protos/perfetto/trace/ftrace/binder.pbzero.h"
33 #include "protos/perfetto/trace/ftrace/cpuhp.pbzero.h"
34 #include "protos/perfetto/trace/ftrace/dmabuf_heap.pbzero.h"
35 #include "protos/perfetto/trace/ftrace/dpu.pbzero.h"
36 #include "protos/perfetto/trace/ftrace/fastrpc.pbzero.h"
37 #include "protos/perfetto/trace/ftrace/ftrace.pbzero.h"
38 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
39 #include "protos/perfetto/trace/ftrace/ftrace_stats.pbzero.h"
40 #include "protos/perfetto/trace/ftrace/g2d.pbzero.h"
41 #include "protos/perfetto/trace/ftrace/generic.pbzero.h"
42 #include "protos/perfetto/trace/ftrace/gpu_mem.pbzero.h"
43 #include "protos/perfetto/trace/ftrace/ion.pbzero.h"
44 #include "protos/perfetto/trace/ftrace/irq.pbzero.h"
45 #include "protos/perfetto/trace/ftrace/kmem.pbzero.h"
46 #include "protos/perfetto/trace/ftrace/lowmemorykiller.pbzero.h"
47 #include "protos/perfetto/trace/ftrace/mali.pbzero.h"
48 #include "protos/perfetto/trace/ftrace/mm_event.pbzero.h"
49 #include "protos/perfetto/trace/ftrace/oom.pbzero.h"
50 #include "protos/perfetto/trace/ftrace/power.pbzero.h"
51 #include "protos/perfetto/trace/ftrace/raw_syscalls.pbzero.h"
52 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
53 #include "protos/perfetto/trace/ftrace/scm.pbzero.h"
54 #include "protos/perfetto/trace/ftrace/sde.pbzero.h"
55 #include "protos/perfetto/trace/ftrace/signal.pbzero.h"
56 #include "protos/perfetto/trace/ftrace/systrace.pbzero.h"
57 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
58 #include "protos/perfetto/trace/ftrace/thermal.pbzero.h"
59 #include "protos/perfetto/trace/ftrace/workqueue.pbzero.h"
60 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
61
62 namespace perfetto {
63 namespace trace_processor {
64
65 namespace {
66
67 using protozero::ConstBytes;
68 using protozero::ProtoDecoder;
69
70 // kthreadd is the parent process for all kernel threads and always has
71 // pid == 2 on Linux and Android.
72 const uint32_t kKthreaddPid = 2;
73 const char kKthreaddName[] = "kthreadd";
74
75 struct FtraceEventAndFieldId {
76 uint32_t event_id;
77 uint32_t field_id;
78 };
79
80 // Contains a list of all the proto fields in ftrace events which represent
81 // kernel functions. This list is used to convert the iids in these fields to
82 // proper kernel symbols.
83 // TODO(lalitm): going through this array is O(n) on a hot-path (see
84 // ParseTypedFtraceToRaw). Consider changing this if we end up adding a lot of
85 // events here.
86 constexpr auto kKernelFunctionFields = std::array<FtraceEventAndFieldId, 3>{
87 {FtraceEventAndFieldId{
88 protos::pbzero::FtraceEvent::kSchedBlockedReasonFieldNumber,
89 protos::pbzero::SchedBlockedReasonFtraceEvent::kCallerFieldNumber},
90 FtraceEventAndFieldId{
91 protos::pbzero::FtraceEvent::kWorkqueueExecuteStartFieldNumber,
92 protos::pbzero::WorkqueueExecuteStartFtraceEvent::
93 kFunctionFieldNumber},
94 FtraceEventAndFieldId{
95 protos::pbzero::FtraceEvent::kWorkqueueQueueWorkFieldNumber,
96 protos::pbzero::WorkqueueQueueWorkFtraceEvent::kFunctionFieldNumber}}};
97
98 } // namespace
99
FtraceParser(TraceProcessorContext * context)100 FtraceParser::FtraceParser(TraceProcessorContext* context)
101 : context_(context),
102 rss_stat_tracker_(context),
103 sched_wakeup_name_id_(context->storage->InternString("sched_wakeup")),
104 sched_waking_name_id_(context->storage->InternString("sched_waking")),
105 cpu_freq_name_id_(context->storage->InternString("cpufreq")),
106 gpu_freq_name_id_(context->storage->InternString("gpufreq")),
107 cpu_idle_name_id_(context->storage->InternString("cpuidle")),
108 ion_total_id_(context->storage->InternString("mem.ion")),
109 ion_change_id_(context->storage->InternString("mem.ion_change")),
110 ion_buffer_id_(context->storage->InternString("mem.ion_buffer")),
111 dma_heap_total_id_(context->storage->InternString("mem.dma_heap")),
112 dma_heap_change_id_(
113 context->storage->InternString("mem.dma_heap_change")),
114 dma_buffer_id_(context->storage->InternString("mem.dma_buffer")),
115 ion_total_unknown_id_(context->storage->InternString("mem.ion.unknown")),
116 ion_change_unknown_id_(
117 context->storage->InternString("mem.ion_change.unknown")),
118 signal_generate_id_(context->storage->InternString("signal_generate")),
119 signal_deliver_id_(context->storage->InternString("signal_deliver")),
120 oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
121 lmk_id_(context->storage->InternString("mem.lmk")),
122 comm_name_id_(context->storage->InternString("comm")),
123 signal_name_id_(context_->storage->InternString("signal.sig")),
124 oom_kill_id_(context_->storage->InternString("mem.oom_kill")),
125 workqueue_id_(context_->storage->InternString("workqueue")),
126 irq_id_(context_->storage->InternString("irq")),
127 ret_arg_id_(context_->storage->InternString("ret")),
128 vec_arg_id_(context->storage->InternString("vec")),
129 gpu_mem_total_name_id_(context->storage->InternString("GPU Memory")),
130 gpu_mem_total_unit_id_(context->storage->InternString(
131 std::to_string(protos::pbzero::GpuCounterDescriptor::BYTE).c_str())),
132 gpu_mem_total_global_desc_id_(context->storage->InternString(
133 "Total GPU memory used by the entire system")),
134 gpu_mem_total_proc_desc_id_(context->storage->InternString(
135 "Total GPU memory used by this process")),
136 sched_blocked_reason_id_(
137 context->storage->InternString("sched_blocked_reason")),
138 io_wait_id_(context->storage->InternString("io_wait")),
139 function_id_(context->storage->InternString("function")) {
140 // Build the lookup table for the strings inside ftrace events (e.g. the
141 // name of ftrace event fields and the names of their args).
142 for (size_t i = 0; i < GetDescriptorsSize(); i++) {
143 auto* descriptor = GetMessageDescriptorForId(i);
144 if (!descriptor->name) {
145 ftrace_message_strings_.emplace_back();
146 continue;
147 }
148
149 FtraceMessageStrings ftrace_strings;
150 ftrace_strings.message_name_id =
151 context->storage->InternString(descriptor->name);
152
153 for (size_t fid = 0; fid <= descriptor->max_field_id; fid++) {
154 const auto& field = descriptor->fields[fid];
155 if (!field.name)
156 continue;
157 ftrace_strings.field_name_ids[fid] =
158 context->storage->InternString(field.name);
159 }
160 ftrace_message_strings_.emplace_back(ftrace_strings);
161 }
162
163 // Array initialization causes a spurious warning due to llvm bug.
164 // See https://bugs.llvm.org/show_bug.cgi?id=21629
165 fast_rpc_delta_names_[0] =
166 context->storage->InternString("mem.fastrpc_change[ASDP]");
167 fast_rpc_delta_names_[1] =
168 context->storage->InternString("mem.fastrpc_change[MDSP]");
169 fast_rpc_delta_names_[2] =
170 context->storage->InternString("mem.fastrpc_change[SDSP]");
171 fast_rpc_delta_names_[3] =
172 context->storage->InternString("mem.fastrpc_change[CDSP]");
173 fast_rpc_total_names_[0] =
174 context->storage->InternString("mem.fastrpc[ASDP]");
175 fast_rpc_total_names_[1] =
176 context->storage->InternString("mem.fastrpc[MDSP]");
177 fast_rpc_total_names_[2] =
178 context->storage->InternString("mem.fastrpc[SDSP]");
179 fast_rpc_total_names_[3] =
180 context->storage->InternString("mem.fastrpc[CDSP]");
181
182 mm_event_counter_names_ = {
183 {MmEventCounterNames(
184 context->storage->InternString("mem.mm.min_flt.count"),
185 context->storage->InternString("mem.mm.min_flt.max_lat"),
186 context->storage->InternString("mem.mm.min_flt.avg_lat")),
187 MmEventCounterNames(
188 context->storage->InternString("mem.mm.maj_flt.count"),
189 context->storage->InternString("mem.mm.maj_flt.max_lat"),
190 context->storage->InternString("mem.mm.maj_flt.avg_lat")),
191 MmEventCounterNames(
192 context->storage->InternString("mem.mm.read_io.count"),
193 context->storage->InternString("mem.mm.read_io.max_lat"),
194 context->storage->InternString("mem.mm.read_io.avg_lat")),
195 MmEventCounterNames(
196 context->storage->InternString("mem.mm.compaction.count"),
197 context->storage->InternString("mem.mm.compaction.max_lat"),
198 context->storage->InternString("mem.mm.compaction.avg_lat")),
199 MmEventCounterNames(
200 context->storage->InternString("mem.mm.reclaim.count"),
201 context->storage->InternString("mem.mm.reclaim.max_lat"),
202 context->storage->InternString("mem.mm.reclaim.avg_lat")),
203 MmEventCounterNames(
204 context->storage->InternString("mem.mm.swp_flt.count"),
205 context->storage->InternString("mem.mm.swp_flt.max_lat"),
206 context->storage->InternString("mem.mm.swp_flt.avg_lat")),
207 MmEventCounterNames(
208 context->storage->InternString("mem.mm.kern_alloc.count"),
209 context->storage->InternString("mem.mm.kern_alloc.max_lat"),
210 context->storage->InternString("mem.mm.kern_alloc.avg_lat"))}};
211 }
212
ParseFtraceStats(ConstBytes blob)213 void FtraceParser::ParseFtraceStats(ConstBytes blob) {
214 protos::pbzero::FtraceStats::Decoder evt(blob.data, blob.size);
215 size_t phase =
216 evt.phase() == protos::pbzero::FtraceStats_Phase_END_OF_TRACE ? 1 : 0;
217
218 // This code relies on the fact that each ftrace_cpu_XXX_end event is
219 // just after the corresponding ftrace_cpu_XXX_begin event.
220 static_assert(
221 stats::ftrace_cpu_read_events_end - stats::ftrace_cpu_read_events_begin ==
222 1 &&
223 stats::ftrace_cpu_entries_end - stats::ftrace_cpu_entries_begin == 1,
224 "ftrace_cpu_XXX stats definition are messed up");
225
226 auto* storage = context_->storage.get();
227 for (auto it = evt.cpu_stats(); it; ++it) {
228 protos::pbzero::FtraceCpuStats::Decoder cpu_stats(*it);
229 int cpu = static_cast<int>(cpu_stats.cpu());
230 storage->SetIndexedStats(stats::ftrace_cpu_entries_begin + phase, cpu,
231 static_cast<int64_t>(cpu_stats.entries()));
232 storage->SetIndexedStats(stats::ftrace_cpu_overrun_begin + phase, cpu,
233 static_cast<int64_t>(cpu_stats.overrun()));
234 storage->SetIndexedStats(stats::ftrace_cpu_commit_overrun_begin + phase,
235 cpu,
236 static_cast<int64_t>(cpu_stats.commit_overrun()));
237 storage->SetIndexedStats(stats::ftrace_cpu_bytes_read_begin + phase, cpu,
238 static_cast<int64_t>(cpu_stats.bytes_read()));
239
240 // oldest_event_ts can often be set to very high values, possibly because
241 // of wrapping. Ensure that we are not overflowing to avoid ubsan
242 // complaining.
243 double oldest_event_ts = cpu_stats.oldest_event_ts() * 1e9;
244 // NB: This comparison is correct only because of the >=, it would be
245 // incorrect with >. std::numeric_limits<int64_t>::max() converted to
246 // a double is the next value representable as a double that is *larger*
247 // than std::numeric_limits<int64_t>::max(). All values that are
248 // representable as doubles and < than that value are thus representable as
249 // int64_t.
250 if (oldest_event_ts >=
251 static_cast<double>(std::numeric_limits<int64_t>::max())) {
252 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
253 cpu, std::numeric_limits<int64_t>::max());
254 } else {
255 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
256 cpu, static_cast<int64_t>(oldest_event_ts));
257 }
258
259 storage->SetIndexedStats(stats::ftrace_cpu_now_ts_begin + phase, cpu,
260 static_cast<int64_t>(cpu_stats.now_ts() * 1e9));
261 storage->SetIndexedStats(stats::ftrace_cpu_dropped_events_begin + phase,
262 cpu,
263 static_cast<int64_t>(cpu_stats.dropped_events()));
264 storage->SetIndexedStats(stats::ftrace_cpu_read_events_begin + phase, cpu,
265 static_cast<int64_t>(cpu_stats.read_events()));
266 }
267 }
268
269 PERFETTO_ALWAYS_INLINE
ParseFtraceEvent(uint32_t cpu,const TimestampedTracePiece & ttp)270 util::Status FtraceParser::ParseFtraceEvent(uint32_t cpu,
271 const TimestampedTracePiece& ttp) {
272 int64_t ts = ttp.timestamp;
273
274 // On the first ftrace packet, check the metadata table for the
275 // ts of the event which is specified in the config. If it exists we can use
276 // it to filter out ftrace packets which happen earlier than it.
277 if (PERFETTO_UNLIKELY(!has_seen_first_ftrace_packet_)) {
278 DropFtraceDataBefore drop_before = context_->config.drop_ftrace_data_before;
279 switch (drop_before) {
280 case DropFtraceDataBefore::kNoDrop: {
281 drop_ftrace_data_before_ts_ = 0;
282 break;
283 }
284 case DropFtraceDataBefore::kAllDataSourcesStarted:
285 case DropFtraceDataBefore::kTracingStarted: {
286 metadata::KeyId event_key =
287 drop_before == DropFtraceDataBefore::kAllDataSourcesStarted
288 ? metadata::all_data_source_started_ns
289 : metadata::tracing_started_ns;
290 const auto& metadata = context_->storage->metadata_table();
291 base::Optional<uint32_t> opt_row =
292 metadata.name().IndexOf(metadata::kNames[event_key]);
293 if (opt_row) {
294 drop_ftrace_data_before_ts_ = *metadata.int_value()[*opt_row];
295 }
296 break;
297 }
298 }
299 has_seen_first_ftrace_packet_ = true;
300 }
301
302 if (PERFETTO_UNLIKELY(ts < drop_ftrace_data_before_ts_)) {
303 context_->storage->IncrementStats(
304 stats::ftrace_packet_before_tracing_start);
305 return util::OkStatus();
306 }
307
308 using protos::pbzero::FtraceEvent;
309 SchedEventTracker* sched_tracker = SchedEventTracker::GetOrCreate(context_);
310
311 // Handle the (optional) alternative encoding format for sched_switch.
312 if (ttp.type == TimestampedTracePiece::Type::kInlineSchedSwitch) {
313 const auto& event = ttp.sched_switch;
314 sched_tracker->PushSchedSwitchCompact(cpu, ts, event.prev_state,
315 static_cast<uint32_t>(event.next_pid),
316 event.next_prio, event.next_comm);
317 return util::OkStatus();
318 }
319
320 // Handle the (optional) alternative encoding format for sched_waking.
321 if (ttp.type == TimestampedTracePiece::Type::kInlineSchedWaking) {
322 const auto& event = ttp.sched_waking;
323 sched_tracker->PushSchedWakingCompact(
324 cpu, ts, static_cast<uint32_t>(event.pid), event.target_cpu, event.prio,
325 event.comm);
326 return util::OkStatus();
327 }
328
329 PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kFtraceEvent);
330 const TraceBlobView& event = ttp.ftrace_event.event;
331 PacketSequenceStateGeneration* seq_state =
332 ttp.ftrace_event.sequence_state.get();
333 ProtoDecoder decoder(event.data(), event.length());
334 uint64_t raw_pid = 0;
335 if (auto pid_field = decoder.FindField(FtraceEvent::kPidFieldNumber)) {
336 raw_pid = pid_field.as_uint64();
337 } else {
338 return util::ErrStatus("Pid field not found in ftrace packet");
339 }
340 uint32_t pid = static_cast<uint32_t>(raw_pid);
341
342 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
343 bool is_metadata_field = fld.id() == FtraceEvent::kPidFieldNumber ||
344 fld.id() == FtraceEvent::kTimestampFieldNumber;
345 if (is_metadata_field)
346 continue;
347
348 ConstBytes data = fld.as_bytes();
349 if (fld.id() == FtraceEvent::kGenericFieldNumber) {
350 ParseGenericFtrace(ts, cpu, pid, data);
351 } else if (fld.id() != FtraceEvent::kSchedSwitchFieldNumber) {
352 // sched_switch parsing populates the raw table by itself
353 ParseTypedFtraceToRaw(fld.id(), ts, cpu, pid, data, seq_state);
354 }
355
356 switch (fld.id()) {
357 case FtraceEvent::kSchedSwitchFieldNumber: {
358 ParseSchedSwitch(cpu, ts, data);
359 break;
360 }
361 case FtraceEvent::kSchedWakeupFieldNumber: {
362 ParseSchedWakeup(ts, data);
363 break;
364 }
365 case FtraceEvent::kSchedWakingFieldNumber: {
366 ParseSchedWaking(ts, data);
367 break;
368 }
369 case FtraceEvent::kSchedProcessFreeFieldNumber: {
370 ParseSchedProcessFree(ts, data);
371 break;
372 }
373 case FtraceEvent::kCpuFrequencyFieldNumber: {
374 ParseCpuFreq(ts, data);
375 break;
376 }
377 case FtraceEvent::kGpuFrequencyFieldNumber: {
378 ParseGpuFreq(ts, data);
379 break;
380 }
381 case FtraceEvent::kCpuIdleFieldNumber: {
382 ParseCpuIdle(ts, data);
383 break;
384 }
385 case FtraceEvent::kPrintFieldNumber: {
386 ParsePrint(ts, pid, data);
387 break;
388 }
389 case FtraceEvent::kZeroFieldNumber: {
390 ParseZero(ts, pid, data);
391 break;
392 }
393 case FtraceEvent::kRssStatFieldNumber: {
394 rss_stat_tracker_.ParseRssStat(ts, pid, data);
395 break;
396 }
397 case FtraceEvent::kIonHeapGrowFieldNumber: {
398 ParseIonHeapGrowOrShrink(ts, pid, data, true);
399 break;
400 }
401 case FtraceEvent::kIonHeapShrinkFieldNumber: {
402 ParseIonHeapGrowOrShrink(ts, pid, data, false);
403 break;
404 }
405 case FtraceEvent::kIonStatFieldNumber: {
406 ParseIonStat(ts, pid, data);
407 break;
408 }
409 case FtraceEvent::kDmaHeapStatFieldNumber: {
410 ParseDmaHeapStat(ts, pid, data);
411 break;
412 }
413 case FtraceEvent::kSignalGenerateFieldNumber: {
414 ParseSignalGenerate(ts, data);
415 break;
416 }
417 case FtraceEvent::kSignalDeliverFieldNumber: {
418 ParseSignalDeliver(ts, pid, data);
419 break;
420 }
421 case FtraceEvent::kLowmemoryKillFieldNumber: {
422 ParseLowmemoryKill(ts, data);
423 break;
424 }
425 case FtraceEvent::kOomScoreAdjUpdateFieldNumber: {
426 ParseOOMScoreAdjUpdate(ts, data);
427 break;
428 }
429 case FtraceEvent::kMarkVictimFieldNumber: {
430 ParseOOMKill(ts, data);
431 break;
432 }
433 case FtraceEvent::kMmEventRecordFieldNumber: {
434 ParseMmEventRecord(ts, pid, data);
435 break;
436 }
437 case FtraceEvent::kSysEnterFieldNumber: {
438 ParseSysEvent(ts, pid, true, data);
439 break;
440 }
441 case FtraceEvent::kSysExitFieldNumber: {
442 ParseSysEvent(ts, pid, false, data);
443 break;
444 }
445 case FtraceEvent::kTaskNewtaskFieldNumber: {
446 ParseTaskNewTask(ts, pid, data);
447 break;
448 }
449 case FtraceEvent::kTaskRenameFieldNumber: {
450 ParseTaskRename(data);
451 break;
452 }
453 case FtraceEvent::kBinderTransactionFieldNumber: {
454 ParseBinderTransaction(ts, pid, data);
455 break;
456 }
457 case FtraceEvent::kBinderTransactionReceivedFieldNumber: {
458 ParseBinderTransactionReceived(ts, pid, data);
459 break;
460 }
461 case FtraceEvent::kBinderTransactionAllocBufFieldNumber: {
462 ParseBinderTransactionAllocBuf(ts, pid, data);
463 break;
464 }
465 case FtraceEvent::kBinderLockFieldNumber: {
466 ParseBinderLock(ts, pid, data);
467 break;
468 }
469 case FtraceEvent::kBinderUnlockFieldNumber: {
470 ParseBinderUnlock(ts, pid, data);
471 break;
472 }
473 case FtraceEvent::kBinderLockedFieldNumber: {
474 ParseBinderLocked(ts, pid, data);
475 break;
476 }
477 case FtraceEvent::kSdeTracingMarkWriteFieldNumber: {
478 ParseSdeTracingMarkWrite(ts, pid, data);
479 break;
480 }
481 case FtraceEvent::kClockSetRateFieldNumber: {
482 ParseClockSetRate(ts, data);
483 break;
484 }
485 case FtraceEvent::kClockEnableFieldNumber: {
486 ParseClockEnable(ts, data);
487 break;
488 }
489 case FtraceEvent::kClockDisableFieldNumber: {
490 ParseClockDisable(ts, data);
491 break;
492 }
493 case FtraceEvent::kScmCallStartFieldNumber: {
494 ParseScmCallStart(ts, pid, data);
495 break;
496 }
497 case FtraceEvent::kScmCallEndFieldNumber: {
498 ParseScmCallEnd(ts, pid, data);
499 break;
500 }
501 case FtraceEvent::kWorkqueueExecuteStartFieldNumber: {
502 ParseWorkqueueExecuteStart(ts, pid, data, seq_state);
503 break;
504 }
505 case FtraceEvent::kWorkqueueExecuteEndFieldNumber: {
506 ParseWorkqueueExecuteEnd(ts, pid, data);
507 break;
508 }
509 case FtraceEvent::kIrqHandlerEntryFieldNumber: {
510 ParseIrqHandlerEntry(cpu, ts, data);
511 break;
512 }
513 case FtraceEvent::kIrqHandlerExitFieldNumber: {
514 ParseIrqHandlerExit(cpu, ts, data);
515 break;
516 }
517 case FtraceEvent::kSoftirqEntryFieldNumber: {
518 ParseSoftIrqEntry(cpu, ts, data);
519 break;
520 }
521 case FtraceEvent::kSoftirqExitFieldNumber: {
522 ParseSoftIrqExit(cpu, ts, data);
523 break;
524 }
525 case FtraceEvent::kGpuMemTotalFieldNumber: {
526 ParseGpuMemTotal(ts, data);
527 break;
528 }
529 case FtraceEvent::kThermalTemperatureFieldNumber: {
530 ParseThermalTemperature(ts, data);
531 break;
532 }
533 case FtraceEvent::kCdevUpdateFieldNumber: {
534 ParseCdevUpdate(ts, data);
535 break;
536 }
537 case FtraceEvent::kSchedBlockedReasonFieldNumber: {
538 ParseSchedBlockedReason(ts, data, seq_state);
539 break;
540 }
541 case FtraceEvent::kFastrpcDmaStatFieldNumber: {
542 ParseFastRpcDmaStat(ts, pid, data);
543 break;
544 }
545 case FtraceEvent::kG2dTracingMarkWriteFieldNumber: {
546 ParseG2dTracingMarkWrite(ts, pid, data);
547 break;
548 }
549 case FtraceEvent::kDpuTracingMarkWriteFieldNumber: {
550 ParseDpuTracingMarkWrite(ts, pid, data);
551 break;
552 }
553 case FtraceEvent::kMaliTracingMarkWriteFieldNumber: {
554 ParseMaliTracingMarkWrite(ts, pid, data);
555 break;
556 }
557 case FtraceEvent::kCpuhpPauseFieldNumber: {
558 ParseCpuhpPause(ts, pid, data);
559 break;
560 }
561 default:
562 break;
563 }
564 }
565
566 PERFETTO_DCHECK(!decoder.bytes_left());
567 return util::OkStatus();
568 }
569
ParseGenericFtrace(int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)570 void FtraceParser::ParseGenericFtrace(int64_t ts,
571 uint32_t cpu,
572 uint32_t tid,
573 ConstBytes blob) {
574 protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
575 StringId event_id = context_->storage->InternString(evt.event_name());
576 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
577 RawId id = context_->storage->mutable_raw_table()
578 ->Insert({ts, event_id, cpu, utid})
579 .id;
580 auto inserter = context_->args_tracker->AddArgsTo(id);
581
582 for (auto it = evt.field(); it; ++it) {
583 protos::pbzero::GenericFtraceEvent::Field::Decoder fld(*it);
584 auto field_name_id = context_->storage->InternString(fld.name());
585 if (fld.has_int_value()) {
586 inserter.AddArg(field_name_id, Variadic::Integer(fld.int_value()));
587 } else if (fld.has_uint_value()) {
588 inserter.AddArg(
589 field_name_id,
590 Variadic::Integer(static_cast<int64_t>(fld.uint_value())));
591 } else if (fld.has_str_value()) {
592 StringId str_value = context_->storage->InternString(fld.str_value());
593 inserter.AddArg(field_name_id, Variadic::String(str_value));
594 }
595 }
596 }
597
ParseTypedFtraceToRaw(uint32_t ftrace_id,int64_t timestamp,uint32_t cpu,uint32_t tid,ConstBytes blob,PacketSequenceStateGeneration * seq_state)598 void FtraceParser::ParseTypedFtraceToRaw(
599 uint32_t ftrace_id,
600 int64_t timestamp,
601 uint32_t cpu,
602 uint32_t tid,
603 ConstBytes blob,
604 PacketSequenceStateGeneration* seq_state) {
605 if (PERFETTO_UNLIKELY(!context_->config.ingest_ftrace_in_raw_table))
606 return;
607
608 ProtoDecoder decoder(blob.data, blob.size);
609 if (ftrace_id >= GetDescriptorsSize()) {
610 PERFETTO_DLOG("Event with id: %d does not exist and cannot be parsed.",
611 ftrace_id);
612 return;
613 }
614
615 MessageDescriptor* m = GetMessageDescriptorForId(ftrace_id);
616 const auto& message_strings = ftrace_message_strings_[ftrace_id];
617 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
618 RawId id =
619 context_->storage->mutable_raw_table()
620 ->Insert({timestamp, message_strings.message_name_id, cpu, utid})
621 .id;
622 auto inserter = context_->args_tracker->AddArgsTo(id);
623
624 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
625 uint16_t field_id = fld.id();
626 if (PERFETTO_UNLIKELY(field_id >= kMaxFtraceEventFields)) {
627 PERFETTO_DLOG(
628 "Skipping ftrace arg - proto field id is too large (%" PRIu16 ")",
629 field_id);
630 continue;
631 }
632
633 ProtoSchemaType type = m->fields[field_id].type;
634 StringId name_id = message_strings.field_name_ids[field_id];
635
636 // Check if this field represents a kernel function.
637 auto it = std::find_if(
638 kKernelFunctionFields.begin(), kKernelFunctionFields.end(),
639 [ftrace_id, field_id](const FtraceEventAndFieldId& ev) {
640 return ev.event_id == ftrace_id && ev.field_id == field_id;
641 });
642 if (it != kKernelFunctionFields.end()) {
643 PERFETTO_CHECK(type == ProtoSchemaType::kUint64);
644
645 auto* interned_string = seq_state->LookupInternedMessage<
646 protos::pbzero::InternedData::kKernelSymbolsFieldNumber,
647 protos::pbzero::InternedString>(fld.as_uint64());
648
649 // If we don't have the string for this field (can happen if symbolization
650 // wasn't enabled, if reading the symbols errored out or on legacy traces)
651 // then just add the field as a normal arg.
652 if (interned_string) {
653 protozero::ConstBytes str = interned_string->str();
654 StringId str_id = context_->storage->InternString(base::StringView(
655 reinterpret_cast<const char*>(str.data), str.size));
656 inserter.AddArg(name_id, Variadic::String(str_id));
657 continue;
658 }
659 }
660
661 switch (type) {
662 case ProtoSchemaType::kInt32:
663 case ProtoSchemaType::kInt64:
664 case ProtoSchemaType::kSfixed32:
665 case ProtoSchemaType::kSfixed64:
666 case ProtoSchemaType::kSint32:
667 case ProtoSchemaType::kSint64:
668 case ProtoSchemaType::kBool:
669 case ProtoSchemaType::kEnum: {
670 inserter.AddArg(name_id, Variadic::Integer(fld.as_int64()));
671 break;
672 }
673 case ProtoSchemaType::kUint32:
674 case ProtoSchemaType::kUint64:
675 case ProtoSchemaType::kFixed32:
676 case ProtoSchemaType::kFixed64: {
677 // Note that SQLite functions will still treat unsigned values
678 // as a signed 64 bit integers (but the translation back to ftrace
679 // refers to this storage directly).
680 inserter.AddArg(name_id, Variadic::UnsignedInteger(fld.as_uint64()));
681 break;
682 }
683 case ProtoSchemaType::kString:
684 case ProtoSchemaType::kBytes: {
685 StringId value = context_->storage->InternString(fld.as_string());
686 inserter.AddArg(name_id, Variadic::String(value));
687 break;
688 }
689 case ProtoSchemaType::kDouble: {
690 inserter.AddArg(name_id, Variadic::Real(fld.as_double()));
691 break;
692 }
693 case ProtoSchemaType::kFloat: {
694 inserter.AddArg(name_id,
695 Variadic::Real(static_cast<double>(fld.as_float())));
696 break;
697 }
698 case ProtoSchemaType::kUnknown:
699 case ProtoSchemaType::kGroup:
700 case ProtoSchemaType::kMessage:
701 PERFETTO_DLOG("Could not store %s as a field in args table.",
702 ProtoSchemaToString(type));
703 break;
704 }
705 }
706 }
707
708 PERFETTO_ALWAYS_INLINE
ParseSchedSwitch(uint32_t cpu,int64_t timestamp,ConstBytes blob)709 void FtraceParser::ParseSchedSwitch(uint32_t cpu,
710 int64_t timestamp,
711 ConstBytes blob) {
712 protos::pbzero::SchedSwitchFtraceEvent::Decoder ss(blob.data, blob.size);
713 uint32_t prev_pid = static_cast<uint32_t>(ss.prev_pid());
714 uint32_t next_pid = static_cast<uint32_t>(ss.next_pid());
715 SchedEventTracker::GetOrCreate(context_)->PushSchedSwitch(
716 cpu, timestamp, prev_pid, ss.prev_comm(), ss.prev_prio(), ss.prev_state(),
717 next_pid, ss.next_comm(), ss.next_prio());
718 }
719
ParseSchedWakeup(int64_t timestamp,ConstBytes blob)720 void FtraceParser::ParseSchedWakeup(int64_t timestamp, ConstBytes blob) {
721 protos::pbzero::SchedWakeupFtraceEvent::Decoder sw(blob.data, blob.size);
722 uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
723 StringId name_id = context_->storage->InternString(sw.comm());
724 auto utid = context_->process_tracker->UpdateThreadName(
725 wakee_pid, name_id, ThreadNamePriority::kFtrace);
726 context_->event_tracker->PushInstant(timestamp, sched_wakeup_name_id_, utid,
727 RefType::kRefUtid);
728 }
729
ParseSchedWaking(int64_t timestamp,ConstBytes blob)730 void FtraceParser::ParseSchedWaking(int64_t timestamp, ConstBytes blob) {
731 protos::pbzero::SchedWakingFtraceEvent::Decoder sw(blob.data, blob.size);
732 uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
733 StringId name_id = context_->storage->InternString(sw.comm());
734 auto utid = context_->process_tracker->UpdateThreadName(
735 wakee_pid, name_id, ThreadNamePriority::kFtrace);
736 context_->event_tracker->PushInstant(timestamp, sched_waking_name_id_, utid,
737 RefType::kRefUtid);
738 }
739
ParseSchedProcessFree(int64_t timestamp,ConstBytes blob)740 void FtraceParser::ParseSchedProcessFree(int64_t timestamp, ConstBytes blob) {
741 protos::pbzero::SchedProcessFreeFtraceEvent::Decoder ex(blob.data, blob.size);
742 uint32_t pid = static_cast<uint32_t>(ex.pid());
743 context_->process_tracker->EndThread(timestamp, pid);
744 }
745
ParseCpuFreq(int64_t timestamp,ConstBytes blob)746 void FtraceParser::ParseCpuFreq(int64_t timestamp, ConstBytes blob) {
747 protos::pbzero::CpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
748 uint32_t cpu = freq.cpu_id();
749 uint32_t new_freq = freq.state();
750 TrackId track =
751 context_->track_tracker->InternCpuCounterTrack(cpu_freq_name_id_, cpu);
752 context_->event_tracker->PushCounter(timestamp, new_freq, track);
753 }
754
ParseGpuFreq(int64_t timestamp,ConstBytes blob)755 void FtraceParser::ParseGpuFreq(int64_t timestamp, ConstBytes blob) {
756 protos::pbzero::GpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
757 uint32_t gpu = freq.gpu_id();
758 uint32_t new_freq = freq.state();
759 TrackId track =
760 context_->track_tracker->InternGpuCounterTrack(gpu_freq_name_id_, gpu);
761 context_->event_tracker->PushCounter(timestamp, new_freq, track);
762 }
763
ParseCpuIdle(int64_t timestamp,ConstBytes blob)764 void FtraceParser::ParseCpuIdle(int64_t timestamp, ConstBytes blob) {
765 protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob.data, blob.size);
766 uint32_t cpu = idle.cpu_id();
767 uint32_t new_state = idle.state();
768 TrackId track =
769 context_->track_tracker->InternCpuCounterTrack(cpu_idle_name_id_, cpu);
770 context_->event_tracker->PushCounter(timestamp, new_state, track);
771 }
772
ParsePrint(int64_t timestamp,uint32_t pid,ConstBytes blob)773 void FtraceParser::ParsePrint(int64_t timestamp,
774 uint32_t pid,
775 ConstBytes blob) {
776 protos::pbzero::PrintFtraceEvent::Decoder evt(blob.data, blob.size);
777 SystraceParser::GetOrCreate(context_)->ParsePrintEvent(timestamp, pid,
778 evt.buf());
779 }
780
ParseZero(int64_t timestamp,uint32_t pid,ConstBytes blob)781 void FtraceParser::ParseZero(int64_t timestamp, uint32_t pid, ConstBytes blob) {
782 protos::pbzero::ZeroFtraceEvent::Decoder evt(blob.data, blob.size);
783 uint32_t tgid = static_cast<uint32_t>(evt.pid());
784 SystraceParser::GetOrCreate(context_)->ParseZeroEvent(
785 timestamp, pid, evt.flag(), evt.name(), tgid, evt.value());
786 }
787
ParseSdeTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)788 void FtraceParser::ParseSdeTracingMarkWrite(int64_t timestamp,
789 uint32_t pid,
790 ConstBytes blob) {
791 protos::pbzero::SdeTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
792 blob.size);
793 if (!evt.has_trace_type() && !evt.has_trace_begin()) {
794 context_->storage->IncrementStats(stats::systrace_parse_failure);
795 return;
796 }
797
798 uint32_t tgid = static_cast<uint32_t>(evt.pid());
799 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
800 timestamp, pid, static_cast<char>(evt.trace_type()), evt.trace_begin(),
801 evt.trace_name(), tgid, evt.value());
802 }
803
ParseDpuTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)804 void FtraceParser::ParseDpuTracingMarkWrite(int64_t timestamp,
805 uint32_t pid,
806 ConstBytes blob) {
807 protos::pbzero::DpuTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
808 blob.size);
809 if (!evt.type()) {
810 context_->storage->IncrementStats(stats::systrace_parse_failure);
811 return;
812 }
813
814 uint32_t tgid = static_cast<uint32_t>(evt.pid());
815 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
816 timestamp, pid, static_cast<char>(evt.type()), false /*trace_begin*/,
817 evt.name(), tgid, evt.value());
818 }
819
ParseG2dTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)820 void FtraceParser::ParseG2dTracingMarkWrite(int64_t timestamp,
821 uint32_t pid,
822 ConstBytes blob) {
823 protos::pbzero::G2dTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
824 blob.size);
825 if (!evt.type()) {
826 context_->storage->IncrementStats(stats::systrace_parse_failure);
827 return;
828 }
829
830 uint32_t tgid = static_cast<uint32_t>(evt.pid());
831 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
832 timestamp, pid, static_cast<char>(evt.type()), false /*trace_begin*/,
833 evt.name(), tgid, evt.value());
834 }
835
ParseMaliTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)836 void FtraceParser::ParseMaliTracingMarkWrite(int64_t timestamp,
837 uint32_t pid,
838 ConstBytes blob) {
839 protos::pbzero::MaliTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
840 blob.size);
841 if (!evt.type()) {
842 context_->storage->IncrementStats(stats::systrace_parse_failure);
843 return;
844 }
845
846 uint32_t tgid = static_cast<uint32_t>(evt.pid());
847 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
848 timestamp, pid, static_cast<char>(evt.type()), false /*trace_begin*/,
849 evt.name(), tgid, evt.value());
850 }
851
852 /** Parses ion heap events present in Pixel kernels. */
ParseIonHeapGrowOrShrink(int64_t timestamp,uint32_t pid,ConstBytes blob,bool grow)853 void FtraceParser::ParseIonHeapGrowOrShrink(int64_t timestamp,
854 uint32_t pid,
855 ConstBytes blob,
856 bool grow) {
857 protos::pbzero::IonHeapGrowFtraceEvent::Decoder ion(blob.data, blob.size);
858 int64_t change_bytes = static_cast<int64_t>(ion.len()) * (grow ? 1 : -1);
859 // The total_allocated ftrace event reports the value before the
860 // atomic_long_add / sub takes place.
861 int64_t total_bytes = ion.total_allocated() + change_bytes;
862 StringId global_name_id = ion_total_unknown_id_;
863 StringId change_name_id = ion_change_unknown_id_;
864
865 if (ion.has_heap_name()) {
866 char counter_name[255];
867 base::StringView heap_name = ion.heap_name();
868 snprintf(counter_name, sizeof(counter_name), "mem.ion.%.*s",
869 int(heap_name.size()), heap_name.data());
870 global_name_id = context_->storage->InternString(counter_name);
871 snprintf(counter_name, sizeof(counter_name), "mem.ion_change.%.*s",
872 int(heap_name.size()), heap_name.data());
873 change_name_id = context_->storage->InternString(counter_name);
874 }
875
876 // Push the global counter.
877 TrackId track =
878 context_->track_tracker->InternGlobalCounterTrack(global_name_id);
879 context_->event_tracker->PushCounter(timestamp,
880 static_cast<double>(total_bytes), track);
881
882 // Push the change counter.
883 // TODO(b/121331269): these should really be instant events.
884 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
885 track =
886 context_->track_tracker->InternThreadCounterTrack(change_name_id, utid);
887 context_->event_tracker->PushCounter(
888 timestamp, static_cast<double>(change_bytes), track);
889
890 // We are reusing the same function for ion_heap_grow and ion_heap_shrink.
891 // It is fine as the arguments are the same, but we need to be sure that the
892 // protobuf field id for both are the same.
893 static_assert(
894 static_cast<int>(
895 protos::pbzero::IonHeapGrowFtraceEvent::kTotalAllocatedFieldNumber) ==
896 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
897 kTotalAllocatedFieldNumber) &&
898 static_cast<int>(
899 protos::pbzero::IonHeapGrowFtraceEvent::kLenFieldNumber) ==
900 static_cast<int>(
901 protos::pbzero::IonHeapShrinkFtraceEvent::kLenFieldNumber) &&
902 static_cast<int>(
903 protos::pbzero::IonHeapGrowFtraceEvent::kHeapNameFieldNumber) ==
904 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
905 kHeapNameFieldNumber),
906 "ION field mismatch");
907 }
908
909 /** Parses ion heap events (introduced in 4.19 kernels). */
ParseIonStat(int64_t timestamp,uint32_t pid,protozero::ConstBytes data)910 void FtraceParser::ParseIonStat(int64_t timestamp,
911 uint32_t pid,
912 protozero::ConstBytes data) {
913 protos::pbzero::IonStatFtraceEvent::Decoder ion(data.data, data.size);
914 // Push the global counter.
915 TrackId track =
916 context_->track_tracker->InternGlobalCounterTrack(ion_total_id_);
917 context_->event_tracker->PushCounter(
918 timestamp, static_cast<double>(ion.total_allocated()), track);
919
920 // Push the change counter.
921 // TODO(b/121331269): these should really be instant events.
922 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
923 track =
924 context_->track_tracker->InternThreadCounterTrack(ion_change_id_, utid);
925 context_->event_tracker->PushCounter(timestamp,
926 static_cast<double>(ion.len()), track);
927
928 // Global track for individual buffer tracking
929 auto async_track =
930 context_->async_track_set_tracker->InternGlobalTrackSet(ion_buffer_id_);
931 if (ion.len() > 0) {
932 TrackId start_id =
933 context_->async_track_set_tracker->Begin(async_track, ion.buffer_id());
934 std::string buf = std::to_string(ion.len() / 1024) + " kB";
935 context_->slice_tracker->Begin(
936 timestamp, start_id, kNullStringId,
937 context_->storage->InternString(base::StringView(buf)));
938 } else {
939 TrackId end_id =
940 context_->async_track_set_tracker->End(async_track, ion.buffer_id());
941 context_->slice_tracker->End(timestamp, end_id);
942 }
943 }
944
ParseDmaHeapStat(int64_t timestamp,uint32_t pid,protozero::ConstBytes data)945 void FtraceParser::ParseDmaHeapStat(int64_t timestamp,
946 uint32_t pid,
947 protozero::ConstBytes data) {
948 protos::pbzero::DmaHeapStatFtraceEvent::Decoder dma_heap(data.data,
949 data.size);
950 // Push the global counter.
951 TrackId track =
952 context_->track_tracker->InternGlobalCounterTrack(dma_heap_total_id_);
953 context_->event_tracker->PushCounter(
954 timestamp, static_cast<double>(dma_heap.total_allocated()), track);
955
956 // Push the change counter.
957 // TODO(b/121331269): these should really be instant events.
958 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
959 track = context_->track_tracker->InternThreadCounterTrack(dma_heap_change_id_,
960 utid);
961 context_->event_tracker->PushCounter(
962 timestamp, static_cast<double>(dma_heap.len()), track);
963
964 // Global track for individual buffer tracking
965 auto async_track =
966 context_->async_track_set_tracker->InternGlobalTrackSet(dma_buffer_id_);
967 if (dma_heap.len() > 0) {
968 TrackId start_id = context_->async_track_set_tracker->Begin(
969 async_track, static_cast<int64_t>(dma_heap.inode()));
970 std::string buf = std::to_string(dma_heap.len() / 1024) + " kB";
971 context_->slice_tracker->Begin(
972 timestamp, start_id, kNullStringId,
973 context_->storage->InternString(base::StringView(buf)));
974 } else {
975 TrackId end_id = context_->async_track_set_tracker->End(
976 async_track, static_cast<int64_t>(dma_heap.inode()));
977 context_->slice_tracker->End(timestamp, end_id);
978 }
979 }
980
981 // This event has both the pid of the thread that sent the signal and the
982 // destination of the signal. Currently storing the pid of the destination.
ParseSignalGenerate(int64_t timestamp,ConstBytes blob)983 void FtraceParser::ParseSignalGenerate(int64_t timestamp, ConstBytes blob) {
984 protos::pbzero::SignalGenerateFtraceEvent::Decoder sig(blob.data, blob.size);
985
986 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
987 static_cast<uint32_t>(sig.pid()));
988 InstantId id = context_->event_tracker->PushInstant(
989 timestamp, signal_generate_id_, utid, RefType::kRefUtid);
990
991 context_->args_tracker->AddArgsTo(id).AddArg(signal_name_id_,
992 Variadic::Integer(sig.sig()));
993 }
994
ParseSignalDeliver(int64_t timestamp,uint32_t pid,ConstBytes blob)995 void FtraceParser::ParseSignalDeliver(int64_t timestamp,
996 uint32_t pid,
997 ConstBytes blob) {
998 protos::pbzero::SignalDeliverFtraceEvent::Decoder sig(blob.data, blob.size);
999 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1000 InstantId id = context_->event_tracker->PushInstant(
1001 timestamp, signal_deliver_id_, utid, RefType::kRefUtid);
1002
1003 context_->args_tracker->AddArgsTo(id).AddArg(signal_name_id_,
1004 Variadic::Integer(sig.sig()));
1005 }
1006
ParseLowmemoryKill(int64_t timestamp,ConstBytes blob)1007 void FtraceParser::ParseLowmemoryKill(int64_t timestamp, ConstBytes blob) {
1008 // TODO(hjd): Store the pagecache_size, pagecache_limit and free fields
1009 // in an args table
1010 protos::pbzero::LowmemoryKillFtraceEvent::Decoder lmk(blob.data, blob.size);
1011
1012 // Store the pid of the event that is lmk-ed.
1013 auto pid = static_cast<uint32_t>(lmk.pid());
1014 auto opt_utid = context_->process_tracker->GetThreadOrNull(pid);
1015
1016 // Don't add LMK events for threads we've never seen before. This works around
1017 // the case where we get an LMK event after a thread has already been killed.
1018 if (!opt_utid)
1019 return;
1020
1021 InstantId id = context_->event_tracker->PushInstant(
1022 timestamp, lmk_id_, opt_utid.value(), RefType::kRefUtid, true);
1023
1024 // Store the comm as an arg.
1025 auto comm_id = context_->storage->InternString(
1026 lmk.has_comm() ? lmk.comm() : base::StringView());
1027 context_->args_tracker->AddArgsTo(id).AddArg(comm_name_id_,
1028 Variadic::String(comm_id));
1029 }
1030
ParseOOMScoreAdjUpdate(int64_t timestamp,ConstBytes blob)1031 void FtraceParser::ParseOOMScoreAdjUpdate(int64_t timestamp, ConstBytes blob) {
1032 protos::pbzero::OomScoreAdjUpdateFtraceEvent::Decoder evt(blob.data,
1033 blob.size);
1034 // The int16_t static cast is because older version of the on-device tracer
1035 // had a bug on negative varint encoding (b/120618641).
1036 int16_t oom_adj = static_cast<int16_t>(evt.oom_score_adj());
1037 uint32_t tid = static_cast<uint32_t>(evt.pid());
1038 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
1039 context_->event_tracker->PushProcessCounterForThread(timestamp, oom_adj,
1040 oom_score_adj_id_, utid);
1041 }
1042
ParseOOMKill(int64_t timestamp,ConstBytes blob)1043 void FtraceParser::ParseOOMKill(int64_t timestamp, ConstBytes blob) {
1044 protos::pbzero::MarkVictimFtraceEvent::Decoder evt(blob.data, blob.size);
1045 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
1046 static_cast<uint32_t>(evt.pid()));
1047 context_->event_tracker->PushInstant(timestamp, oom_kill_id_, utid,
1048 RefType::kRefUtid, true);
1049 }
1050
ParseMmEventRecord(int64_t timestamp,uint32_t pid,ConstBytes blob)1051 void FtraceParser::ParseMmEventRecord(int64_t timestamp,
1052 uint32_t pid,
1053 ConstBytes blob) {
1054 protos::pbzero::MmEventRecordFtraceEvent::Decoder evt(blob.data, blob.size);
1055 uint32_t type = evt.type();
1056 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1057
1058 if (type >= mm_event_counter_names_.size()) {
1059 context_->storage->IncrementStats(stats::mm_unknown_type);
1060 return;
1061 }
1062
1063 const auto& counter_names = mm_event_counter_names_[type];
1064 context_->event_tracker->PushProcessCounterForThread(
1065 timestamp, evt.count(), counter_names.count, utid);
1066 context_->event_tracker->PushProcessCounterForThread(
1067 timestamp, evt.max_lat(), counter_names.max_lat, utid);
1068 context_->event_tracker->PushProcessCounterForThread(
1069 timestamp, evt.avg_lat(), counter_names.avg_lat, utid);
1070 }
1071
ParseSysEvent(int64_t timestamp,uint32_t pid,bool is_enter,ConstBytes blob)1072 void FtraceParser::ParseSysEvent(int64_t timestamp,
1073 uint32_t pid,
1074 bool is_enter,
1075 ConstBytes blob) {
1076 protos::pbzero::SysEnterFtraceEvent::Decoder evt(blob.data, blob.size);
1077 uint32_t syscall_num = static_cast<uint32_t>(evt.id());
1078 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1079
1080 SyscallTracker* syscall_tracker = SyscallTracker::GetOrCreate(context_);
1081 if (is_enter) {
1082 syscall_tracker->Enter(timestamp, utid, syscall_num);
1083 } else {
1084 syscall_tracker->Exit(timestamp, utid, syscall_num);
1085 }
1086
1087 // We are reusing the same function for sys_enter and sys_exit.
1088 // It is fine as the arguments are the same, but we need to be sure that the
1089 // protobuf field id for both are the same.
1090 static_assert(
1091 static_cast<int>(protos::pbzero::SysEnterFtraceEvent::kIdFieldNumber) ==
1092 static_cast<int>(protos::pbzero::SysExitFtraceEvent::kIdFieldNumber),
1093 "field mismatch");
1094 }
1095
ParseTaskNewTask(int64_t timestamp,uint32_t source_tid,ConstBytes blob)1096 void FtraceParser::ParseTaskNewTask(int64_t timestamp,
1097 uint32_t source_tid,
1098 ConstBytes blob) {
1099 protos::pbzero::TaskNewtaskFtraceEvent::Decoder evt(blob.data, blob.size);
1100 uint32_t clone_flags = static_cast<uint32_t>(evt.clone_flags());
1101 uint32_t new_tid = static_cast<uint32_t>(evt.pid());
1102 StringId new_comm = context_->storage->InternString(evt.comm());
1103 auto* proc_tracker = context_->process_tracker.get();
1104
1105 // task_newtask is raised both in the case of a new process creation (fork()
1106 // family) and thread creation (clone(CLONE_THREAD, ...)).
1107 static const uint32_t kCloneThread = 0x00010000; // From kernel's sched.h.
1108
1109 // If the process is a fork, start a new process except if the source tid is
1110 // kthreadd in which case just make it a new thread associated with kthreadd.
1111 if ((clone_flags & kCloneThread) == 0 && source_tid != kKthreaddPid) {
1112 // This is a plain-old fork() or equivalent.
1113 proc_tracker->StartNewProcess(timestamp, source_tid, new_tid, new_comm);
1114 return;
1115 }
1116
1117 if (source_tid == kKthreaddPid) {
1118 context_->process_tracker->SetProcessMetadata(
1119 kKthreaddPid, base::nullopt, kKthreaddName, base::StringView());
1120 }
1121
1122 // This is a pthread_create or similar. Bind the two threads together, so
1123 // they get resolved to the same process.
1124 auto source_utid = proc_tracker->GetOrCreateThread(source_tid);
1125 auto new_utid = proc_tracker->StartNewThread(timestamp, new_tid);
1126 proc_tracker->UpdateThreadNameByUtid(new_utid, new_comm,
1127 ThreadNamePriority::kFtrace);
1128 proc_tracker->AssociateThreads(source_utid, new_utid);
1129 }
1130
ParseTaskRename(ConstBytes blob)1131 void FtraceParser::ParseTaskRename(ConstBytes blob) {
1132 protos::pbzero::TaskRenameFtraceEvent::Decoder evt(blob.data, blob.size);
1133 uint32_t tid = static_cast<uint32_t>(evt.pid());
1134 StringId comm = context_->storage->InternString(evt.newcomm());
1135 context_->process_tracker->UpdateThreadName(tid, comm,
1136 ThreadNamePriority::kFtrace);
1137 context_->process_tracker->UpdateProcessNameFromThreadName(tid, comm);
1138 }
1139
ParseBinderTransaction(int64_t timestamp,uint32_t pid,ConstBytes blob)1140 void FtraceParser::ParseBinderTransaction(int64_t timestamp,
1141 uint32_t pid,
1142 ConstBytes blob) {
1143 protos::pbzero::BinderTransactionFtraceEvent::Decoder evt(blob.data,
1144 blob.size);
1145 int32_t dest_node = static_cast<int32_t>(evt.target_node());
1146 int32_t dest_tgid = static_cast<int32_t>(evt.to_proc());
1147 int32_t dest_tid = static_cast<int32_t>(evt.to_thread());
1148 int32_t transaction_id = static_cast<int32_t>(evt.debug_id());
1149 bool is_reply = static_cast<int32_t>(evt.reply()) == 1;
1150 uint32_t flags = static_cast<uint32_t>(evt.flags());
1151 auto code_str = base::IntToHexString(evt.code()) + " Java Layer Dependent";
1152 StringId code = context_->storage->InternString(base::StringView(code_str));
1153 BinderTracker::GetOrCreate(context_)->Transaction(
1154 timestamp, pid, transaction_id, dest_node, dest_tgid, dest_tid, is_reply,
1155 flags, code);
1156 }
1157
ParseBinderTransactionReceived(int64_t timestamp,uint32_t pid,ConstBytes blob)1158 void FtraceParser::ParseBinderTransactionReceived(int64_t timestamp,
1159 uint32_t pid,
1160 ConstBytes blob) {
1161 protos::pbzero::BinderTransactionReceivedFtraceEvent::Decoder evt(blob.data,
1162 blob.size);
1163 int32_t transaction_id = static_cast<int32_t>(evt.debug_id());
1164 BinderTracker::GetOrCreate(context_)->TransactionReceived(timestamp, pid,
1165 transaction_id);
1166 }
1167
ParseBinderTransactionAllocBuf(int64_t timestamp,uint32_t pid,ConstBytes blob)1168 void FtraceParser::ParseBinderTransactionAllocBuf(int64_t timestamp,
1169 uint32_t pid,
1170 ConstBytes blob) {
1171 protos::pbzero::BinderTransactionAllocBufFtraceEvent::Decoder evt(blob.data,
1172 blob.size);
1173 uint64_t data_size = static_cast<uint64_t>(evt.data_size());
1174 uint64_t offsets_size = static_cast<uint64_t>(evt.offsets_size());
1175
1176 BinderTracker::GetOrCreate(context_)->TransactionAllocBuf(
1177 timestamp, pid, data_size, offsets_size);
1178 }
1179
ParseBinderLocked(int64_t timestamp,uint32_t pid,ConstBytes blob)1180 void FtraceParser::ParseBinderLocked(int64_t timestamp,
1181 uint32_t pid,
1182 ConstBytes blob) {
1183 protos::pbzero::BinderLockedFtraceEvent::Decoder evt(blob.data, blob.size);
1184 BinderTracker::GetOrCreate(context_)->Locked(timestamp, pid);
1185 }
1186
ParseBinderLock(int64_t timestamp,uint32_t pid,ConstBytes blob)1187 void FtraceParser::ParseBinderLock(int64_t timestamp,
1188 uint32_t pid,
1189 ConstBytes blob) {
1190 protos::pbzero::BinderLockFtraceEvent::Decoder evt(blob.data, blob.size);
1191 BinderTracker::GetOrCreate(context_)->Lock(timestamp, pid);
1192 }
1193
ParseBinderUnlock(int64_t timestamp,uint32_t pid,ConstBytes blob)1194 void FtraceParser::ParseBinderUnlock(int64_t timestamp,
1195 uint32_t pid,
1196 ConstBytes blob) {
1197 protos::pbzero::BinderUnlockFtraceEvent::Decoder evt(blob.data, blob.size);
1198 BinderTracker::GetOrCreate(context_)->Unlock(timestamp, pid);
1199 }
1200
ParseClockSetRate(int64_t timestamp,ConstBytes blob)1201 void FtraceParser::ParseClockSetRate(int64_t timestamp, ConstBytes blob) {
1202 protos::pbzero::ClockSetRateFtraceEvent::Decoder evt(blob.data, blob.size);
1203 static const char kSubtitle[] = "Frequency";
1204 ClockRate(timestamp, evt.name(), kSubtitle, evt.state());
1205 }
1206
ParseClockEnable(int64_t timestamp,ConstBytes blob)1207 void FtraceParser::ParseClockEnable(int64_t timestamp, ConstBytes blob) {
1208 protos::pbzero::ClockEnableFtraceEvent::Decoder evt(blob.data, blob.size);
1209 static const char kSubtitle[] = "State";
1210 ClockRate(timestamp, evt.name(), kSubtitle, evt.state());
1211 }
1212
ParseClockDisable(int64_t timestamp,ConstBytes blob)1213 void FtraceParser::ParseClockDisable(int64_t timestamp, ConstBytes blob) {
1214 protos::pbzero::ClockDisableFtraceEvent::Decoder evt(blob.data, blob.size);
1215 static const char kSubtitle[] = "State";
1216 ClockRate(timestamp, evt.name(), kSubtitle, evt.state());
1217 }
1218
ClockRate(int64_t timestamp,base::StringView clock_name,base::StringView subtitle,uint64_t rate)1219 void FtraceParser::ClockRate(int64_t timestamp,
1220 base::StringView clock_name,
1221 base::StringView subtitle,
1222 uint64_t rate) {
1223 char counter_name[255];
1224 snprintf(counter_name, sizeof(counter_name), "%.*s %.*s",
1225 int(clock_name.size()), clock_name.data(), int(subtitle.size()),
1226 subtitle.data());
1227 StringId name = context_->storage->InternString(counter_name);
1228 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1229 context_->event_tracker->PushCounter(timestamp, static_cast<double>(rate),
1230 track);
1231 }
1232
ParseScmCallStart(int64_t timestamp,uint32_t pid,ConstBytes blob)1233 void FtraceParser::ParseScmCallStart(int64_t timestamp,
1234 uint32_t pid,
1235 ConstBytes blob) {
1236 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1237 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
1238 protos::pbzero::ScmCallStartFtraceEvent::Decoder evt(blob.data, blob.size);
1239
1240 char str[64];
1241 sprintf(str, "scm id=%#" PRIx64, evt.x0());
1242 StringId name_id = context_->storage->InternString(str);
1243 context_->slice_tracker->Begin(timestamp, track_id, kNullStringId, name_id);
1244 }
1245
ParseScmCallEnd(int64_t timestamp,uint32_t pid,ConstBytes blob)1246 void FtraceParser::ParseScmCallEnd(int64_t timestamp,
1247 uint32_t pid,
1248 ConstBytes blob) {
1249 protos::pbzero::ScmCallEndFtraceEvent::Decoder evt(blob.data, blob.size);
1250 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1251 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
1252 context_->slice_tracker->End(timestamp, track_id);
1253 }
1254
ParseWorkqueueExecuteStart(int64_t timestamp,uint32_t pid,ConstBytes blob,PacketSequenceStateGeneration * seq_state)1255 void FtraceParser::ParseWorkqueueExecuteStart(
1256 int64_t timestamp,
1257 uint32_t pid,
1258 ConstBytes blob,
1259 PacketSequenceStateGeneration* seq_state) {
1260 protos::pbzero::WorkqueueExecuteStartFtraceEvent::Decoder evt(blob.data,
1261 blob.size);
1262
1263 auto* interned_string = seq_state->LookupInternedMessage<
1264 protos::pbzero::InternedData::kKernelSymbolsFieldNumber,
1265 protos::pbzero::InternedString>(static_cast<uint32_t>(evt.function()));
1266 StringId name_id;
1267 if (interned_string) {
1268 protozero::ConstBytes str = interned_string->str();
1269 name_id = context_->storage->InternString(
1270 base::StringView(reinterpret_cast<const char*>(str.data), str.size));
1271 } else {
1272 char slice_name[255];
1273 snprintf(slice_name, base::ArraySize(slice_name), "%#" PRIx64,
1274 evt.function());
1275 name_id = context_->storage->InternString(base::StringView(slice_name));
1276 }
1277
1278 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1279 TrackId track = context_->track_tracker->InternThreadTrack(utid);
1280 context_->slice_tracker->Begin(timestamp, track, workqueue_id_, name_id);
1281 }
1282
ParseWorkqueueExecuteEnd(int64_t timestamp,uint32_t pid,ConstBytes blob)1283 void FtraceParser::ParseWorkqueueExecuteEnd(int64_t timestamp,
1284 uint32_t pid,
1285 ConstBytes blob) {
1286 protos::pbzero::WorkqueueExecuteEndFtraceEvent::Decoder evt(blob.data,
1287 blob.size);
1288 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1289 TrackId track = context_->track_tracker->InternThreadTrack(utid);
1290 context_->slice_tracker->End(timestamp, track, workqueue_id_);
1291 }
1292
ParseIrqHandlerEntry(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1293 void FtraceParser::ParseIrqHandlerEntry(uint32_t cpu,
1294 int64_t timestamp,
1295 protozero::ConstBytes blob) {
1296 protos::pbzero::IrqHandlerEntryFtraceEvent::Decoder evt(blob.data, blob.size);
1297 char track_name[255];
1298 snprintf(track_name, sizeof(track_name), "Irq Cpu %d", cpu);
1299 StringId track_name_id = context_->storage->InternString(track_name);
1300 char slice_name[255];
1301 base::StringView irq_name = evt.name();
1302 snprintf(slice_name, sizeof(slice_name), "IRQ (%.*s)", int(irq_name.size()),
1303 irq_name.data());
1304 StringId slice_name_id = context_->storage->InternString(slice_name);
1305 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1306 context_->slice_tracker->Begin(timestamp, track, irq_id_, slice_name_id);
1307 }
1308
ParseIrqHandlerExit(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1309 void FtraceParser::ParseIrqHandlerExit(uint32_t cpu,
1310 int64_t timestamp,
1311 protozero::ConstBytes blob) {
1312 protos::pbzero::IrqHandlerExitFtraceEvent::Decoder evt(blob.data, blob.size);
1313 char track_name[255];
1314 snprintf(track_name, sizeof(track_name), "Irq Cpu %d", cpu);
1315 StringId track_name_id = context_->storage->InternString(track_name);
1316 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1317 char status[255];
1318 snprintf(status, sizeof(status), "%s",
1319 evt.ret() == 1 ? "handled" : "unhandled");
1320 StringId status_id = context_->storage->InternString(status);
1321 auto args_inserter = [this,
1322 &status_id](ArgsTracker::BoundInserter* inserter) {
1323 inserter->AddArg(ret_arg_id_, Variadic::String(status_id));
1324 };
1325 context_->slice_tracker->End(timestamp, track, irq_id_, {}, args_inserter);
1326 }
1327
ParseSoftIrqEntry(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1328 void FtraceParser::ParseSoftIrqEntry(uint32_t cpu,
1329 int64_t timestamp,
1330 protozero::ConstBytes blob) {
1331 protos::pbzero::SoftirqEntryFtraceEvent::Decoder evt(blob.data, blob.size);
1332 char track_name[255];
1333 snprintf(track_name, sizeof(track_name), "SoftIrq Cpu %d", cpu);
1334 StringId track_name_id = context_->storage->InternString(track_name);
1335 auto num_actions = sizeof(kActionNames) / sizeof(*kActionNames);
1336 if (evt.vec() >= num_actions) {
1337 PERFETTO_DFATAL("No action name at index %d for softirq event.", evt.vec());
1338 return;
1339 }
1340 base::StringView slice_name = kActionNames[evt.vec()];
1341 StringId slice_name_id = context_->storage->InternString(slice_name);
1342 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1343 context_->slice_tracker->Begin(timestamp, track, irq_id_, slice_name_id);
1344 }
1345
ParseSoftIrqExit(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1346 void FtraceParser::ParseSoftIrqExit(uint32_t cpu,
1347 int64_t timestamp,
1348 protozero::ConstBytes blob) {
1349 protos::pbzero::SoftirqExitFtraceEvent::Decoder evt(blob.data, blob.size);
1350 char track_name[255];
1351 snprintf(track_name, sizeof(track_name), "SoftIrq Cpu %d", cpu);
1352 StringId track_name_id = context_->storage->InternString(track_name);
1353 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1354 auto vec = evt.vec();
1355 auto args_inserter = [this, vec](ArgsTracker::BoundInserter* inserter) {
1356 inserter->AddArg(vec_arg_id_, Variadic::Integer(vec));
1357 };
1358 context_->slice_tracker->End(timestamp, track, irq_id_, {}, args_inserter);
1359 }
1360
ParseGpuMemTotal(int64_t timestamp,protozero::ConstBytes data)1361 void FtraceParser::ParseGpuMemTotal(int64_t timestamp,
1362 protozero::ConstBytes data) {
1363 protos::pbzero::GpuMemTotalFtraceEvent::Decoder gpu_mem_total(data.data,
1364 data.size);
1365
1366 TrackId track = kInvalidTrackId;
1367 const uint32_t pid = gpu_mem_total.pid();
1368 if (pid == 0) {
1369 // Pid 0 is used to indicate the global total
1370 track = context_->track_tracker->InternGlobalCounterTrack(
1371 gpu_mem_total_name_id_, gpu_mem_total_unit_id_,
1372 gpu_mem_total_global_desc_id_);
1373 } else {
1374 // Process emitting the packet can be different from the pid in the event.
1375 UniqueTid utid = context_->process_tracker->UpdateThread(pid, pid);
1376 UniquePid upid = context_->storage->thread_table().upid()[utid].value_or(0);
1377 track = context_->track_tracker->InternProcessCounterTrack(
1378 gpu_mem_total_name_id_, upid, gpu_mem_total_unit_id_,
1379 gpu_mem_total_proc_desc_id_);
1380 }
1381 context_->event_tracker->PushCounter(
1382 timestamp, static_cast<double>(gpu_mem_total.size()), track);
1383 }
1384
ParseThermalTemperature(int64_t timestamp,protozero::ConstBytes blob)1385 void FtraceParser::ParseThermalTemperature(int64_t timestamp,
1386 protozero::ConstBytes blob) {
1387 protos::pbzero::ThermalTemperatureFtraceEvent::Decoder evt(blob.data,
1388 blob.size);
1389 char counter_name[255];
1390 base::StringView thermal_zone = evt.thermal_zone();
1391 snprintf(counter_name, sizeof(counter_name), "%.*s Temperature",
1392 int(thermal_zone.size()), thermal_zone.data());
1393 StringId name = context_->storage->InternString(counter_name);
1394 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1395 context_->event_tracker->PushCounter(timestamp, evt.temp(), track);
1396 }
1397
ParseCdevUpdate(int64_t timestamp,protozero::ConstBytes blob)1398 void FtraceParser::ParseCdevUpdate(int64_t timestamp,
1399 protozero::ConstBytes blob) {
1400 protos::pbzero::CdevUpdateFtraceEvent::Decoder evt(blob.data, blob.size);
1401 char counter_name[255];
1402 base::StringView type = evt.type();
1403 snprintf(counter_name, sizeof(counter_name), "%.*s Cooling Device",
1404 int(type.size()), type.data());
1405 StringId name = context_->storage->InternString(counter_name);
1406 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1407 context_->event_tracker->PushCounter(
1408 timestamp, static_cast<double>(evt.target()), track);
1409 }
1410
ParseSchedBlockedReason(int64_t timestamp,protozero::ConstBytes blob,PacketSequenceStateGeneration * seq_state)1411 void FtraceParser::ParseSchedBlockedReason(
1412 int64_t timestamp,
1413 protozero::ConstBytes blob,
1414 PacketSequenceStateGeneration* seq_state) {
1415 protos::pbzero::SchedBlockedReasonFtraceEvent::Decoder evt(blob);
1416 uint32_t pid = static_cast<uint32_t>(evt.pid());
1417 auto utid = context_->process_tracker->GetOrCreateThread(pid);
1418 InstantId id = context_->event_tracker->PushInstant(
1419 timestamp, sched_blocked_reason_id_, utid, RefType::kRefUtid, false);
1420
1421 auto inserter = context_->args_tracker->AddArgsTo(id);
1422 inserter.AddArg(io_wait_id_, Variadic::Boolean(evt.io_wait()));
1423
1424 uint32_t caller_iid = static_cast<uint32_t>(evt.caller());
1425 auto* interned_string = seq_state->LookupInternedMessage<
1426 protos::pbzero::InternedData::kKernelSymbolsFieldNumber,
1427 protos::pbzero::InternedString>(caller_iid);
1428
1429 if (interned_string) {
1430 protozero::ConstBytes str = interned_string->str();
1431 StringId str_id = context_->storage->InternString(
1432 base::StringView(reinterpret_cast<const char*>(str.data), str.size));
1433 inserter.AddArg(function_id_, Variadic::String(str_id));
1434 }
1435 }
1436
ParseFastRpcDmaStat(int64_t timestamp,uint32_t pid,protozero::ConstBytes blob)1437 void FtraceParser::ParseFastRpcDmaStat(int64_t timestamp,
1438 uint32_t pid,
1439 protozero::ConstBytes blob) {
1440 protos::pbzero::FastrpcDmaStatFtraceEvent::Decoder evt(blob.data, blob.size);
1441
1442 StringId name;
1443 if (0 <= evt.cid() && evt.cid() < static_cast<int32_t>(kFastRpcCounterSize)) {
1444 name = fast_rpc_delta_names_[static_cast<size_t>(evt.cid())];
1445 } else {
1446 char str[64];
1447 snprintf(str, sizeof(str), "mem.fastrpc[%" PRId32 "]", evt.cid());
1448 name = context_->storage->InternString(str);
1449 }
1450
1451 StringId total_name;
1452 if (0 <= evt.cid() && evt.cid() < static_cast<int32_t>(kFastRpcCounterSize)) {
1453 total_name = fast_rpc_total_names_[static_cast<size_t>(evt.cid())];
1454 } else {
1455 char str[64];
1456 snprintf(str, sizeof(str), "mem.fastrpc[%" PRId32 "]", evt.cid());
1457 total_name = context_->storage->InternString(str);
1458 }
1459
1460 // Push the global counter.
1461 TrackId track = context_->track_tracker->InternGlobalCounterTrack(total_name);
1462 context_->event_tracker->PushCounter(
1463 timestamp, static_cast<double>(evt.total_allocated()), track);
1464
1465 // Push the change counter.
1466 // TODO(b/121331269): these should really be instant events.
1467 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1468 TrackId delta_track =
1469 context_->track_tracker->InternThreadCounterTrack(name, utid);
1470 context_->event_tracker->PushCounter(
1471 timestamp, static_cast<double>(evt.len()), delta_track);
1472 }
1473
ParseCpuhpPause(int64_t,uint32_t,protozero::ConstBytes blob)1474 void FtraceParser::ParseCpuhpPause(int64_t,
1475 uint32_t,
1476 protozero::ConstBytes blob) {
1477 protos::pbzero::CpuhpPauseFtraceEvent::Decoder evt(blob.data, blob.size);
1478 // TODO(b/183110813): Parse and visualize this event.
1479 }
1480
1481 } // namespace trace_processor
1482 } // namespace perfetto
1483