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/proto/metadata_tracker.h"
26 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
27 #include "src/trace_processor/importers/systrace/systrace_parser.h"
28 #include "src/trace_processor/storage/stats.h"
29 #include "src/trace_processor/storage/trace_storage.h"
30 #include "src/trace_processor/types/softirq_action.h"
31 #include "src/trace_processor/types/tcp_state.h"
32
33 #include "protos/perfetto/common/gpu_counter_descriptor.pbzero.h"
34 #include "protos/perfetto/trace/ftrace/binder.pbzero.h"
35 #include "protos/perfetto/trace/ftrace/cpuhp.pbzero.h"
36 #include "protos/perfetto/trace/ftrace/cros_ec.pbzero.h"
37 #include "protos/perfetto/trace/ftrace/dmabuf_heap.pbzero.h"
38 #include "protos/perfetto/trace/ftrace/dpu.pbzero.h"
39 #include "protos/perfetto/trace/ftrace/fastrpc.pbzero.h"
40 #include "protos/perfetto/trace/ftrace/ftrace.pbzero.h"
41 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
42 #include "protos/perfetto/trace/ftrace/ftrace_stats.pbzero.h"
43 #include "protos/perfetto/trace/ftrace/g2d.pbzero.h"
44 #include "protos/perfetto/trace/ftrace/generic.pbzero.h"
45 #include "protos/perfetto/trace/ftrace/gpu_mem.pbzero.h"
46 #include "protos/perfetto/trace/ftrace/ion.pbzero.h"
47 #include "protos/perfetto/trace/ftrace/irq.pbzero.h"
48 #include "protos/perfetto/trace/ftrace/kmem.pbzero.h"
49 #include "protos/perfetto/trace/ftrace/lowmemorykiller.pbzero.h"
50 #include "protos/perfetto/trace/ftrace/mali.pbzero.h"
51 #include "protos/perfetto/trace/ftrace/mm_event.pbzero.h"
52 #include "protos/perfetto/trace/ftrace/net.pbzero.h"
53 #include "protos/perfetto/trace/ftrace/oom.pbzero.h"
54 #include "protos/perfetto/trace/ftrace/power.pbzero.h"
55 #include "protos/perfetto/trace/ftrace/raw_syscalls.pbzero.h"
56 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
57 #include "protos/perfetto/trace/ftrace/scm.pbzero.h"
58 #include "protos/perfetto/trace/ftrace/sde.pbzero.h"
59 #include "protos/perfetto/trace/ftrace/signal.pbzero.h"
60 #include "protos/perfetto/trace/ftrace/skb.pbzero.h"
61 #include "protos/perfetto/trace/ftrace/sock.pbzero.h"
62 #include "protos/perfetto/trace/ftrace/systrace.pbzero.h"
63 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
64 #include "protos/perfetto/trace/ftrace/tcp.pbzero.h"
65 #include "protos/perfetto/trace/ftrace/thermal.pbzero.h"
66 #include "protos/perfetto/trace/ftrace/ufs.pbzero.h"
67 #include "protos/perfetto/trace/ftrace/vmscan.pbzero.h"
68 #include "protos/perfetto/trace/ftrace/workqueue.pbzero.h"
69 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
70
71 namespace perfetto {
72 namespace trace_processor {
73
74 namespace {
75
76 using protozero::ConstBytes;
77 using protozero::ProtoDecoder;
78
79 // kthreadd is the parent process for all kernel threads and always has
80 // pid == 2 on Linux and Android.
81 const uint32_t kKthreaddPid = 2;
82 const char kKthreaddName[] = "kthreadd";
83
84 struct FtraceEventAndFieldId {
85 uint32_t event_id;
86 uint32_t field_id;
87 };
88
89 // Contains a list of all the proto fields in ftrace events which represent
90 // kernel functions. This list is used to convert the iids in these fields to
91 // proper kernel symbols.
92 // TODO(lalitm): going through this array is O(n) on a hot-path (see
93 // ParseTypedFtraceToRaw). Consider changing this if we end up adding a lot of
94 // events here.
95 constexpr auto kKernelFunctionFields = std::array<FtraceEventAndFieldId, 3>{
96 {FtraceEventAndFieldId{
97 protos::pbzero::FtraceEvent::kSchedBlockedReasonFieldNumber,
98 protos::pbzero::SchedBlockedReasonFtraceEvent::kCallerFieldNumber},
99 FtraceEventAndFieldId{
100 protos::pbzero::FtraceEvent::kWorkqueueExecuteStartFieldNumber,
101 protos::pbzero::WorkqueueExecuteStartFtraceEvent::
102 kFunctionFieldNumber},
103 FtraceEventAndFieldId{
104 protos::pbzero::FtraceEvent::kWorkqueueQueueWorkFieldNumber,
105 protos::pbzero::WorkqueueQueueWorkFtraceEvent::kFunctionFieldNumber}}};
106
107 } // namespace
108
FtraceParser(TraceProcessorContext * context)109 FtraceParser::FtraceParser(TraceProcessorContext* context)
110 : context_(context),
111 rss_stat_tracker_(context),
112 sched_wakeup_name_id_(context->storage->InternString("sched_wakeup")),
113 sched_waking_name_id_(context->storage->InternString("sched_waking")),
114 cpu_id_(context->storage->InternString("cpu")),
115 cpu_freq_name_id_(context->storage->InternString("cpufreq")),
116 gpu_freq_name_id_(context->storage->InternString("gpufreq")),
117 cpu_idle_name_id_(context->storage->InternString("cpuidle")),
118 suspend_resume_name_id_(
119 context->storage->InternString("Suspend/Resume Latency")),
120 kfree_skb_name_id_(context->storage->InternString("Kfree Skb IP Prot")),
121 ion_total_id_(context->storage->InternString("mem.ion")),
122 ion_change_id_(context->storage->InternString("mem.ion_change")),
123 ion_buffer_id_(context->storage->InternString("mem.ion_buffer")),
124 dma_heap_total_id_(context->storage->InternString("mem.dma_heap")),
125 dma_heap_change_id_(
126 context->storage->InternString("mem.dma_heap_change")),
127 dma_buffer_id_(context->storage->InternString("mem.dma_buffer")),
128 ion_total_unknown_id_(context->storage->InternString("mem.ion.unknown")),
129 ion_change_unknown_id_(
130 context->storage->InternString("mem.ion_change.unknown")),
131 signal_generate_id_(context->storage->InternString("signal_generate")),
132 signal_deliver_id_(context->storage->InternString("signal_deliver")),
133 oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
134 lmk_id_(context->storage->InternString("mem.lmk")),
135 comm_name_id_(context->storage->InternString("comm")),
136 signal_name_id_(context_->storage->InternString("signal.sig")),
137 oom_kill_id_(context_->storage->InternString("mem.oom_kill")),
138 workqueue_id_(context_->storage->InternString("workqueue")),
139 irq_id_(context_->storage->InternString("irq")),
140 tcp_state_id_(context_->storage->InternString("tcp_state")),
141 tcp_event_id_(context_->storage->InternString("tcp_event")),
142 protocol_arg_id_(context_->storage->InternString("protocol")),
143 napi_gro_id_(context_->storage->InternString("napi_gro")),
144 tcp_retransmited_name_id_(
145 context_->storage->InternString("TCP Retransmit Skb")),
146 ret_arg_id_(context_->storage->InternString("ret")),
147 len_arg_id_(context->storage->InternString("len")),
148 direct_reclaim_nr_reclaimed_id_(
149 context->storage->InternString("direct_reclaim_nr_reclaimed")),
150 direct_reclaim_order_id_(
151 context->storage->InternString("direct_reclaim_order")),
152 direct_reclaim_may_writepage_id_(
153 context->storage->InternString("direct_reclaim_may_writepage")),
154 direct_reclaim_gfp_flags_id_(
155 context->storage->InternString("direct_reclaim_gfp_flags")),
156 vec_arg_id_(context->storage->InternString("vec")),
157 gpu_mem_total_name_id_(context->storage->InternString("GPU Memory")),
158 gpu_mem_total_unit_id_(context->storage->InternString(
159 std::to_string(protos::pbzero::GpuCounterDescriptor::BYTE).c_str())),
160 gpu_mem_total_global_desc_id_(context->storage->InternString(
161 "Total GPU memory used by the entire system")),
162 gpu_mem_total_proc_desc_id_(context->storage->InternString(
163 "Total GPU memory used by this process")),
164 sched_blocked_reason_id_(
165 context->storage->InternString("sched_blocked_reason")),
166 io_wait_id_(context->storage->InternString("io_wait")),
167 function_id_(context->storage->InternString("function")),
168 waker_utid_id_(context->storage->InternString("waker_utid")),
169 cros_ec_arg_num_id_(context->storage->InternString("ec_num")),
170 cros_ec_arg_ec_id_(context->storage->InternString("ec_delta")),
171 cros_ec_arg_sample_ts_id_(context->storage->InternString("sample_ts")),
172 ufs_clkgating_id_(context->storage->InternString("UFS clkgating (OFF/REQ_OFF/REQ_ON/ON)")),
173 ufs_command_count_id_(context->storage->InternString("UFS Command Count")) {
174 // Build the lookup table for the strings inside ftrace events (e.g. the
175 // name of ftrace event fields and the names of their args).
176 for (size_t i = 0; i < GetDescriptorsSize(); i++) {
177 auto* descriptor = GetMessageDescriptorForId(i);
178 if (!descriptor->name) {
179 ftrace_message_strings_.emplace_back();
180 continue;
181 }
182
183 FtraceMessageStrings ftrace_strings;
184 ftrace_strings.message_name_id =
185 context->storage->InternString(descriptor->name);
186
187 for (size_t fid = 0; fid <= descriptor->max_field_id; fid++) {
188 const auto& field = descriptor->fields[fid];
189 if (!field.name)
190 continue;
191 ftrace_strings.field_name_ids[fid] =
192 context->storage->InternString(field.name);
193 }
194 ftrace_message_strings_.emplace_back(ftrace_strings);
195 }
196
197 // Array initialization causes a spurious warning due to llvm bug.
198 // See https://bugs.llvm.org/show_bug.cgi?id=21629
199 fast_rpc_delta_names_[0] =
200 context->storage->InternString("mem.fastrpc_change[ASDP]");
201 fast_rpc_delta_names_[1] =
202 context->storage->InternString("mem.fastrpc_change[MDSP]");
203 fast_rpc_delta_names_[2] =
204 context->storage->InternString("mem.fastrpc_change[SDSP]");
205 fast_rpc_delta_names_[3] =
206 context->storage->InternString("mem.fastrpc_change[CDSP]");
207 fast_rpc_total_names_[0] =
208 context->storage->InternString("mem.fastrpc[ASDP]");
209 fast_rpc_total_names_[1] =
210 context->storage->InternString("mem.fastrpc[MDSP]");
211 fast_rpc_total_names_[2] =
212 context->storage->InternString("mem.fastrpc[SDSP]");
213 fast_rpc_total_names_[3] =
214 context->storage->InternString("mem.fastrpc[CDSP]");
215
216 mm_event_counter_names_ = {
217 {MmEventCounterNames(
218 context->storage->InternString("mem.mm.min_flt.count"),
219 context->storage->InternString("mem.mm.min_flt.max_lat"),
220 context->storage->InternString("mem.mm.min_flt.avg_lat")),
221 MmEventCounterNames(
222 context->storage->InternString("mem.mm.maj_flt.count"),
223 context->storage->InternString("mem.mm.maj_flt.max_lat"),
224 context->storage->InternString("mem.mm.maj_flt.avg_lat")),
225 MmEventCounterNames(
226 context->storage->InternString("mem.mm.read_io.count"),
227 context->storage->InternString("mem.mm.read_io.max_lat"),
228 context->storage->InternString("mem.mm.read_io.avg_lat")),
229 MmEventCounterNames(
230 context->storage->InternString("mem.mm.compaction.count"),
231 context->storage->InternString("mem.mm.compaction.max_lat"),
232 context->storage->InternString("mem.mm.compaction.avg_lat")),
233 MmEventCounterNames(
234 context->storage->InternString("mem.mm.reclaim.count"),
235 context->storage->InternString("mem.mm.reclaim.max_lat"),
236 context->storage->InternString("mem.mm.reclaim.avg_lat")),
237 MmEventCounterNames(
238 context->storage->InternString("mem.mm.swp_flt.count"),
239 context->storage->InternString("mem.mm.swp_flt.max_lat"),
240 context->storage->InternString("mem.mm.swp_flt.avg_lat")),
241 MmEventCounterNames(
242 context->storage->InternString("mem.mm.kern_alloc.count"),
243 context->storage->InternString("mem.mm.kern_alloc.max_lat"),
244 context->storage->InternString("mem.mm.kern_alloc.avg_lat"))}};
245 }
246
ParseFtraceStats(ConstBytes blob)247 void FtraceParser::ParseFtraceStats(ConstBytes blob) {
248 protos::pbzero::FtraceStats::Decoder evt(blob.data, blob.size);
249 bool is_start =
250 evt.phase() == protos::pbzero::FtraceStats_Phase_START_OF_TRACE;
251 bool is_end = evt.phase() == protos::pbzero::FtraceStats_Phase_END_OF_TRACE;
252 if (!is_start && !is_end) {
253 PERFETTO_ELOG("Ignoring unknown ftrace stats phase %d", evt.phase());
254 return;
255 }
256 size_t phase = is_end ? 1 : 0;
257
258 // This code relies on the fact that each ftrace_cpu_XXX_end event is
259 // just after the corresponding ftrace_cpu_XXX_begin event.
260 static_assert(
261 stats::ftrace_cpu_read_events_end - stats::ftrace_cpu_read_events_begin ==
262 1 &&
263 stats::ftrace_cpu_entries_end - stats::ftrace_cpu_entries_begin == 1,
264 "ftrace_cpu_XXX stats definition are messed up");
265
266 auto* storage = context_->storage.get();
267 for (auto it = evt.cpu_stats(); it; ++it) {
268 protos::pbzero::FtraceCpuStats::Decoder cpu_stats(*it);
269 int cpu = static_cast<int>(cpu_stats.cpu());
270
271 int64_t entries = static_cast<int64_t>(cpu_stats.entries());
272 int64_t overrun = static_cast<int64_t>(cpu_stats.overrun());
273 int64_t commit_overrun = static_cast<int64_t>(cpu_stats.commit_overrun());
274 int64_t bytes_read = static_cast<int64_t>(cpu_stats.bytes_read());
275 int64_t dropped_events = static_cast<int64_t>(cpu_stats.dropped_events());
276 int64_t read_events = static_cast<int64_t>(cpu_stats.read_events());
277 int64_t now_ts = static_cast<int64_t>(cpu_stats.now_ts() * 1e9);
278
279 storage->SetIndexedStats(stats::ftrace_cpu_entries_begin + phase, cpu,
280 entries);
281 storage->SetIndexedStats(stats::ftrace_cpu_overrun_begin + phase, cpu,
282 overrun);
283 storage->SetIndexedStats(stats::ftrace_cpu_commit_overrun_begin + phase,
284 cpu, commit_overrun);
285 storage->SetIndexedStats(stats::ftrace_cpu_bytes_read_begin + phase, cpu,
286 bytes_read);
287 storage->SetIndexedStats(stats::ftrace_cpu_dropped_events_begin + phase,
288 cpu, dropped_events);
289 storage->SetIndexedStats(stats::ftrace_cpu_read_events_begin + phase, cpu,
290 read_events);
291 storage->SetIndexedStats(stats::ftrace_cpu_now_ts_begin + phase, cpu,
292 now_ts);
293
294 if (is_end) {
295 auto opt_entries_begin =
296 storage->GetIndexedStats(stats::ftrace_cpu_entries_begin, cpu);
297 if (opt_entries_begin) {
298 int64_t delta_entries = entries - opt_entries_begin.value();
299 storage->SetIndexedStats(stats::ftrace_cpu_entries_delta, cpu,
300 delta_entries);
301 }
302
303 auto opt_overrun_begin =
304 storage->GetIndexedStats(stats::ftrace_cpu_overrun_begin, cpu);
305 if (opt_overrun_begin) {
306 int64_t delta_overrun = overrun - opt_overrun_begin.value();
307 storage->SetIndexedStats(stats::ftrace_cpu_overrun_delta, cpu,
308 delta_overrun);
309 }
310
311 auto opt_commit_overrun_begin =
312 storage->GetIndexedStats(stats::ftrace_cpu_commit_overrun_begin, cpu);
313 if (opt_commit_overrun_begin) {
314 int64_t delta_commit_overrun =
315 commit_overrun - opt_commit_overrun_begin.value();
316 storage->SetIndexedStats(stats::ftrace_cpu_commit_overrun_delta, cpu,
317 delta_commit_overrun);
318 }
319
320 auto opt_bytes_read_begin =
321 storage->GetIndexedStats(stats::ftrace_cpu_bytes_read_begin, cpu);
322 if (opt_bytes_read_begin) {
323 int64_t delta_bytes_read = bytes_read - opt_bytes_read_begin.value();
324 storage->SetIndexedStats(stats::ftrace_cpu_bytes_read_delta, cpu,
325 delta_bytes_read);
326 }
327
328 auto opt_dropped_events_begin =
329 storage->GetIndexedStats(stats::ftrace_cpu_dropped_events_begin, cpu);
330 if (opt_dropped_events_begin) {
331 int64_t delta_dropped_events =
332 dropped_events - opt_dropped_events_begin.value();
333 storage->SetIndexedStats(stats::ftrace_cpu_dropped_events_delta, cpu,
334 delta_dropped_events);
335 }
336
337 auto opt_read_events_begin =
338 storage->GetIndexedStats(stats::ftrace_cpu_read_events_begin, cpu);
339 if (opt_read_events_begin) {
340 int64_t delta_read_events = read_events - opt_read_events_begin.value();
341 storage->SetIndexedStats(stats::ftrace_cpu_read_events_delta, cpu,
342 delta_read_events);
343 }
344 }
345
346 // oldest_event_ts can often be set to very high values, possibly because
347 // of wrapping. Ensure that we are not overflowing to avoid ubsan
348 // complaining.
349 double oldest_event_ts = cpu_stats.oldest_event_ts() * 1e9;
350 // NB: This comparison is correct only because of the >=, it would be
351 // incorrect with >. std::numeric_limits<int64_t>::max() converted to
352 // a double is the next value representable as a double that is *larger*
353 // than std::numeric_limits<int64_t>::max(). All values that are
354 // representable as doubles and < than that value are thus representable
355 // as int64_t.
356 if (oldest_event_ts >=
357 static_cast<double>(std::numeric_limits<int64_t>::max())) {
358 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
359 cpu, std::numeric_limits<int64_t>::max());
360 } else {
361 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
362 cpu, static_cast<int64_t>(oldest_event_ts));
363 }
364 }
365
366 // Compute atrace + ftrace setup errors. We do two things here:
367 // 1. We add up all the errors and put the counter in the stats table (which
368 // can hold only numerals). This will raise an orange flag in the UI.
369 // 2. We concatenate together all the errors in a string and put that in the
370 // medatata table.
371 // Both will be reported in the 'Info & stats' page in the UI.
372 if (is_start) {
373 std::string error_str;
374 for (auto it = evt.failed_ftrace_events(); it; ++it) {
375 storage->IncrementStats(stats::ftrace_setup_errors, 1);
376 error_str += "Ftrace event failed: " + it->as_std_string() + "\n";
377 }
378 for (auto it = evt.unknown_ftrace_events(); it; ++it) {
379 storage->IncrementStats(stats::ftrace_setup_errors, 1);
380 error_str += "Ftrace event unknown: " + it->as_std_string() + "\n";
381 }
382 if (evt.atrace_errors().size > 0) {
383 storage->IncrementStats(stats::ftrace_setup_errors, 1);
384 error_str += "Atrace failures: " + evt.atrace_errors().ToStdString();
385 }
386 auto error_str_id = storage->InternString(base::StringView(error_str));
387 context_->metadata_tracker->SetMetadata(metadata::ftrace_setup_errors,
388 Variadic::String(error_str_id));
389 }
390 }
391
392 PERFETTO_ALWAYS_INLINE
ParseFtraceEvent(uint32_t cpu,const TimestampedTracePiece & ttp)393 util::Status FtraceParser::ParseFtraceEvent(uint32_t cpu,
394 const TimestampedTracePiece& ttp) {
395 int64_t ts = ttp.timestamp;
396
397 // On the first ftrace packet, check the metadata table for the
398 // ts of the event which is specified in the config. If it exists we can use
399 // it to filter out ftrace packets which happen earlier than it.
400 if (PERFETTO_UNLIKELY(!has_seen_first_ftrace_packet_)) {
401 DropFtraceDataBefore drop_before = context_->config.drop_ftrace_data_before;
402 switch (drop_before) {
403 case DropFtraceDataBefore::kNoDrop: {
404 drop_ftrace_data_before_ts_ = 0;
405 break;
406 }
407 case DropFtraceDataBefore::kAllDataSourcesStarted:
408 case DropFtraceDataBefore::kTracingStarted: {
409 metadata::KeyId event_key =
410 drop_before == DropFtraceDataBefore::kAllDataSourcesStarted
411 ? metadata::all_data_source_started_ns
412 : metadata::tracing_started_ns;
413 const auto& metadata = context_->storage->metadata_table();
414 base::Optional<uint32_t> opt_row =
415 metadata.name().IndexOf(metadata::kNames[event_key]);
416 if (opt_row) {
417 drop_ftrace_data_before_ts_ = *metadata.int_value()[*opt_row];
418 }
419 break;
420 }
421 }
422 has_seen_first_ftrace_packet_ = true;
423 }
424
425 if (PERFETTO_UNLIKELY(ts < drop_ftrace_data_before_ts_)) {
426 context_->storage->IncrementStats(
427 stats::ftrace_packet_before_tracing_start);
428 return util::OkStatus();
429 }
430
431 using protos::pbzero::FtraceEvent;
432 SchedEventTracker* sched_tracker = SchedEventTracker::GetOrCreate(context_);
433
434 // Handle the (optional) alternative encoding format for sched_switch.
435 if (ttp.type == TimestampedTracePiece::Type::kInlineSchedSwitch) {
436 const auto& event = ttp.sched_switch;
437 sched_tracker->PushSchedSwitchCompact(cpu, ts, event.prev_state,
438 static_cast<uint32_t>(event.next_pid),
439 event.next_prio, event.next_comm);
440 return util::OkStatus();
441 }
442
443 // Handle the (optional) alternative encoding format for sched_waking.
444 if (ttp.type == TimestampedTracePiece::Type::kInlineSchedWaking) {
445 const auto& event = ttp.sched_waking;
446 sched_tracker->PushSchedWakingCompact(
447 cpu, ts, static_cast<uint32_t>(event.pid), event.target_cpu, event.prio,
448 event.comm);
449 return util::OkStatus();
450 }
451
452 PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kFtraceEvent);
453 const TraceBlobView& event = ttp.ftrace_event.event;
454 PacketSequenceStateGeneration* seq_state =
455 ttp.ftrace_event.sequence_state.get();
456 ProtoDecoder decoder(event.data(), event.length());
457 uint64_t raw_pid = 0;
458 if (auto pid_field = decoder.FindField(FtraceEvent::kPidFieldNumber)) {
459 raw_pid = pid_field.as_uint64();
460 } else {
461 return util::ErrStatus("Pid field not found in ftrace packet");
462 }
463 uint32_t pid = static_cast<uint32_t>(raw_pid);
464
465 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
466 bool is_metadata_field = fld.id() == FtraceEvent::kPidFieldNumber ||
467 fld.id() == FtraceEvent::kTimestampFieldNumber;
468 if (is_metadata_field)
469 continue;
470
471 ConstBytes data = fld.as_bytes();
472 if (fld.id() == FtraceEvent::kGenericFieldNumber) {
473 ParseGenericFtrace(ts, cpu, pid, data);
474 } else if (fld.id() != FtraceEvent::kSchedSwitchFieldNumber) {
475 // sched_switch parsing populates the raw table by itself
476 ParseTypedFtraceToRaw(fld.id(), ts, cpu, pid, data, seq_state);
477 }
478
479 switch (fld.id()) {
480 case FtraceEvent::kSchedSwitchFieldNumber: {
481 ParseSchedSwitch(cpu, ts, data);
482 break;
483 }
484 case FtraceEvent::kSchedWakeupFieldNumber: {
485 ParseSchedWakeup(ts, pid, data);
486 break;
487 }
488 case FtraceEvent::kSchedWakingFieldNumber: {
489 ParseSchedWaking(ts, pid, data);
490 break;
491 }
492 case FtraceEvent::kSchedProcessFreeFieldNumber: {
493 ParseSchedProcessFree(ts, data);
494 break;
495 }
496 case FtraceEvent::kCpuFrequencyFieldNumber: {
497 ParseCpuFreq(ts, data);
498 break;
499 }
500 case FtraceEvent::kGpuFrequencyFieldNumber: {
501 ParseGpuFreq(ts, data);
502 break;
503 }
504 case FtraceEvent::kCpuIdleFieldNumber: {
505 ParseCpuIdle(ts, data);
506 break;
507 }
508 case FtraceEvent::kPrintFieldNumber: {
509 ParsePrint(ts, pid, data);
510 break;
511 }
512 case FtraceEvent::kZeroFieldNumber: {
513 ParseZero(ts, pid, data);
514 break;
515 }
516 case FtraceEvent::kRssStatThrottledFieldNumber:
517 case FtraceEvent::kRssStatFieldNumber: {
518 rss_stat_tracker_.ParseRssStat(ts, fld.id(), pid, data);
519 break;
520 }
521 case FtraceEvent::kIonHeapGrowFieldNumber: {
522 ParseIonHeapGrowOrShrink(ts, pid, data, true);
523 break;
524 }
525 case FtraceEvent::kIonHeapShrinkFieldNumber: {
526 ParseIonHeapGrowOrShrink(ts, pid, data, false);
527 break;
528 }
529 case FtraceEvent::kIonStatFieldNumber: {
530 ParseIonStat(ts, pid, data);
531 break;
532 }
533 case FtraceEvent::kDmaHeapStatFieldNumber: {
534 ParseDmaHeapStat(ts, pid, data);
535 break;
536 }
537 case FtraceEvent::kSignalGenerateFieldNumber: {
538 ParseSignalGenerate(ts, data);
539 break;
540 }
541 case FtraceEvent::kSignalDeliverFieldNumber: {
542 ParseSignalDeliver(ts, pid, data);
543 break;
544 }
545 case FtraceEvent::kLowmemoryKillFieldNumber: {
546 ParseLowmemoryKill(ts, data);
547 break;
548 }
549 case FtraceEvent::kOomScoreAdjUpdateFieldNumber: {
550 ParseOOMScoreAdjUpdate(ts, data);
551 break;
552 }
553 case FtraceEvent::kMarkVictimFieldNumber: {
554 ParseOOMKill(ts, data);
555 break;
556 }
557 case FtraceEvent::kMmEventRecordFieldNumber: {
558 ParseMmEventRecord(ts, pid, data);
559 break;
560 }
561 case FtraceEvent::kSysEnterFieldNumber: {
562 ParseSysEvent(ts, pid, true, data);
563 break;
564 }
565 case FtraceEvent::kSysExitFieldNumber: {
566 ParseSysEvent(ts, pid, false, data);
567 break;
568 }
569 case FtraceEvent::kTaskNewtaskFieldNumber: {
570 ParseTaskNewTask(ts, pid, data);
571 break;
572 }
573 case FtraceEvent::kTaskRenameFieldNumber: {
574 ParseTaskRename(data);
575 break;
576 }
577 case FtraceEvent::kBinderTransactionFieldNumber: {
578 ParseBinderTransaction(ts, pid, data);
579 break;
580 }
581 case FtraceEvent::kBinderTransactionReceivedFieldNumber: {
582 ParseBinderTransactionReceived(ts, pid, data);
583 break;
584 }
585 case FtraceEvent::kBinderTransactionAllocBufFieldNumber: {
586 ParseBinderTransactionAllocBuf(ts, pid, data);
587 break;
588 }
589 case FtraceEvent::kBinderLockFieldNumber: {
590 ParseBinderLock(ts, pid, data);
591 break;
592 }
593 case FtraceEvent::kBinderUnlockFieldNumber: {
594 ParseBinderUnlock(ts, pid, data);
595 break;
596 }
597 case FtraceEvent::kBinderLockedFieldNumber: {
598 ParseBinderLocked(ts, pid, data);
599 break;
600 }
601 case FtraceEvent::kSdeTracingMarkWriteFieldNumber: {
602 ParseSdeTracingMarkWrite(ts, pid, data);
603 break;
604 }
605 case FtraceEvent::kClockSetRateFieldNumber: {
606 ParseClockSetRate(ts, data);
607 break;
608 }
609 case FtraceEvent::kClockEnableFieldNumber: {
610 ParseClockEnable(ts, data);
611 break;
612 }
613 case FtraceEvent::kClockDisableFieldNumber: {
614 ParseClockDisable(ts, data);
615 break;
616 }
617 case FtraceEvent::kScmCallStartFieldNumber: {
618 ParseScmCallStart(ts, pid, data);
619 break;
620 }
621 case FtraceEvent::kScmCallEndFieldNumber: {
622 ParseScmCallEnd(ts, pid, data);
623 break;
624 }
625 case FtraceEvent::kMmVmscanDirectReclaimBeginFieldNumber: {
626 ParseDirectReclaimBegin(ts, pid, data);
627 break;
628 }
629 case FtraceEvent::kMmVmscanDirectReclaimEndFieldNumber: {
630 ParseDirectReclaimEnd(ts, pid, data);
631 break;
632 }
633 case FtraceEvent::kWorkqueueExecuteStartFieldNumber: {
634 ParseWorkqueueExecuteStart(cpu, ts, pid, data, seq_state);
635 break;
636 }
637 case FtraceEvent::kWorkqueueExecuteEndFieldNumber: {
638 ParseWorkqueueExecuteEnd(ts, pid, data);
639 break;
640 }
641 case FtraceEvent::kIrqHandlerEntryFieldNumber: {
642 ParseIrqHandlerEntry(cpu, ts, data);
643 break;
644 }
645 case FtraceEvent::kIrqHandlerExitFieldNumber: {
646 ParseIrqHandlerExit(cpu, ts, data);
647 break;
648 }
649 case FtraceEvent::kSoftirqEntryFieldNumber: {
650 ParseSoftIrqEntry(cpu, ts, data);
651 break;
652 }
653 case FtraceEvent::kSoftirqExitFieldNumber: {
654 ParseSoftIrqExit(cpu, ts, data);
655 break;
656 }
657 case FtraceEvent::kGpuMemTotalFieldNumber: {
658 ParseGpuMemTotal(ts, data);
659 break;
660 }
661 case FtraceEvent::kThermalTemperatureFieldNumber: {
662 ParseThermalTemperature(ts, data);
663 break;
664 }
665 case FtraceEvent::kCdevUpdateFieldNumber: {
666 ParseCdevUpdate(ts, data);
667 break;
668 }
669 case FtraceEvent::kSchedBlockedReasonFieldNumber: {
670 ParseSchedBlockedReason(ts, data, seq_state);
671 break;
672 }
673 case FtraceEvent::kFastrpcDmaStatFieldNumber: {
674 ParseFastRpcDmaStat(ts, pid, data);
675 break;
676 }
677 case FtraceEvent::kG2dTracingMarkWriteFieldNumber: {
678 ParseG2dTracingMarkWrite(ts, pid, data);
679 break;
680 }
681 case FtraceEvent::kDpuTracingMarkWriteFieldNumber: {
682 ParseDpuTracingMarkWrite(ts, pid, data);
683 break;
684 }
685 case FtraceEvent::kMaliTracingMarkWriteFieldNumber: {
686 ParseMaliTracingMarkWrite(ts, pid, data);
687 break;
688 }
689 case FtraceEvent::kCpuhpPauseFieldNumber: {
690 ParseCpuhpPause(ts, pid, data);
691 break;
692 }
693 case FtraceEvent::kNetifReceiveSkbFieldNumber: {
694 ParseNetifReceiveSkb(cpu, ts, data);
695 break;
696 }
697 case FtraceEvent::kNetDevXmitFieldNumber: {
698 ParseNetDevXmit(cpu, ts, data);
699 break;
700 }
701 case FtraceEvent::kInetSockSetStateFieldNumber: {
702 ParseInetSockSetState(ts, pid, data);
703 break;
704 }
705 case FtraceEvent::kTcpRetransmitSkbFieldNumber: {
706 ParseTcpRetransmitSkb(ts, data);
707 break;
708 }
709 case FtraceEvent::kNapiGroReceiveEntryFieldNumber: {
710 ParseNapiGroReceiveEntry(cpu, ts, data);
711 break;
712 }
713 case FtraceEvent::kNapiGroReceiveExitFieldNumber: {
714 ParseNapiGroReceiveExit(cpu, ts, data);
715 break;
716 }
717 case FtraceEvent::kCpuFrequencyLimitsFieldNumber: {
718 ParseCpuFrequencyLimits(ts, data);
719 break;
720 }
721 case FtraceEvent::kKfreeSkbFieldNumber: {
722 ParseKfreeSkb(ts, data);
723 break;
724 }
725 case FtraceEvent::kCrosEcSensorhubDataFieldNumber: {
726 ParseCrosEcSensorhubData(ts, data);
727 break;
728 }
729 case FtraceEvent::kUfshcdCommandFieldNumber: {
730 ParseUfshcdCommand(ts, data);
731 break;
732 }
733 case FtraceEvent::kWakeupSourceActivateFieldNumber: {
734 ParseWakeSourceActivate(ts, data);
735 break;
736 }
737 case FtraceEvent::kWakeupSourceDeactivateFieldNumber: {
738 ParseWakeSourceDeactivate(ts, data);
739 break;
740 }
741 case FtraceEvent::kUfshcdClkGatingFieldNumber: {
742 ParseUfshcdClkGating(ts, data);
743 break;
744 }
745 case FtraceEvent::kSuspendResumeFieldNumber: {
746 ParseSuspendResume(ts, data);
747 break;
748 }
749 default:
750 break;
751 }
752 }
753
754 PERFETTO_DCHECK(!decoder.bytes_left());
755 return util::OkStatus();
756 }
757
ParseGenericFtrace(int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)758 void FtraceParser::ParseGenericFtrace(int64_t ts,
759 uint32_t cpu,
760 uint32_t tid,
761 ConstBytes blob) {
762 protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
763 StringId event_id = context_->storage->InternString(evt.event_name());
764 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
765 RawId id = context_->storage->mutable_raw_table()
766 ->Insert({ts, event_id, cpu, utid})
767 .id;
768 auto inserter = context_->args_tracker->AddArgsTo(id);
769
770 for (auto it = evt.field(); it; ++it) {
771 protos::pbzero::GenericFtraceEvent::Field::Decoder fld(*it);
772 auto field_name_id = context_->storage->InternString(fld.name());
773 if (fld.has_int_value()) {
774 inserter.AddArg(field_name_id, Variadic::Integer(fld.int_value()));
775 } else if (fld.has_uint_value()) {
776 inserter.AddArg(
777 field_name_id,
778 Variadic::Integer(static_cast<int64_t>(fld.uint_value())));
779 } else if (fld.has_str_value()) {
780 StringId str_value = context_->storage->InternString(fld.str_value());
781 inserter.AddArg(field_name_id, Variadic::String(str_value));
782 }
783 }
784 }
785
ParseTypedFtraceToRaw(uint32_t ftrace_id,int64_t timestamp,uint32_t cpu,uint32_t tid,ConstBytes blob,PacketSequenceStateGeneration * seq_state)786 void FtraceParser::ParseTypedFtraceToRaw(
787 uint32_t ftrace_id,
788 int64_t timestamp,
789 uint32_t cpu,
790 uint32_t tid,
791 ConstBytes blob,
792 PacketSequenceStateGeneration* seq_state) {
793 if (PERFETTO_UNLIKELY(!context_->config.ingest_ftrace_in_raw_table))
794 return;
795
796 ProtoDecoder decoder(blob.data, blob.size);
797 if (ftrace_id >= GetDescriptorsSize()) {
798 PERFETTO_DLOG("Event with id: %d does not exist and cannot be parsed.",
799 ftrace_id);
800 return;
801 }
802
803 MessageDescriptor* m = GetMessageDescriptorForId(ftrace_id);
804 const auto& message_strings = ftrace_message_strings_[ftrace_id];
805 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
806 RawId id =
807 context_->storage->mutable_raw_table()
808 ->Insert({timestamp, message_strings.message_name_id, cpu, utid})
809 .id;
810 auto inserter = context_->args_tracker->AddArgsTo(id);
811
812 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
813 uint16_t field_id = fld.id();
814 if (PERFETTO_UNLIKELY(field_id >= kMaxFtraceEventFields)) {
815 PERFETTO_DLOG(
816 "Skipping ftrace arg - proto field id is too large (%" PRIu16 ")",
817 field_id);
818 continue;
819 }
820
821 ProtoSchemaType type = m->fields[field_id].type;
822 StringId name_id = message_strings.field_name_ids[field_id];
823
824 // Check if this field represents a kernel function.
825 auto it = std::find_if(
826 kKernelFunctionFields.begin(), kKernelFunctionFields.end(),
827 [ftrace_id, field_id](const FtraceEventAndFieldId& ev) {
828 return ev.event_id == ftrace_id && ev.field_id == field_id;
829 });
830 if (it != kKernelFunctionFields.end()) {
831 PERFETTO_CHECK(type == ProtoSchemaType::kUint64);
832
833 auto* interned_string = seq_state->LookupInternedMessage<
834 protos::pbzero::InternedData::kKernelSymbolsFieldNumber,
835 protos::pbzero::InternedString>(fld.as_uint64());
836
837 // If we don't have the string for this field (can happen if
838 // symbolization wasn't enabled, if reading the symbols errored out or
839 // on legacy traces) then just add the field as a normal arg.
840 if (interned_string) {
841 protozero::ConstBytes str = interned_string->str();
842 StringId str_id = context_->storage->InternString(base::StringView(
843 reinterpret_cast<const char*>(str.data), str.size));
844 inserter.AddArg(name_id, Variadic::String(str_id));
845 continue;
846 }
847 }
848
849 switch (type) {
850 case ProtoSchemaType::kInt32:
851 case ProtoSchemaType::kInt64:
852 case ProtoSchemaType::kSfixed32:
853 case ProtoSchemaType::kSfixed64:
854 case ProtoSchemaType::kSint32:
855 case ProtoSchemaType::kSint64:
856 case ProtoSchemaType::kBool:
857 case ProtoSchemaType::kEnum: {
858 inserter.AddArg(name_id, Variadic::Integer(fld.as_int64()));
859 break;
860 }
861 case ProtoSchemaType::kUint32:
862 case ProtoSchemaType::kUint64:
863 case ProtoSchemaType::kFixed32:
864 case ProtoSchemaType::kFixed64: {
865 // Note that SQLite functions will still treat unsigned values
866 // as a signed 64 bit integers (but the translation back to ftrace
867 // refers to this storage directly).
868 inserter.AddArg(name_id, Variadic::UnsignedInteger(fld.as_uint64()));
869 break;
870 }
871 case ProtoSchemaType::kString:
872 case ProtoSchemaType::kBytes: {
873 StringId value = context_->storage->InternString(fld.as_string());
874 inserter.AddArg(name_id, Variadic::String(value));
875 break;
876 }
877 case ProtoSchemaType::kDouble: {
878 inserter.AddArg(name_id, Variadic::Real(fld.as_double()));
879 break;
880 }
881 case ProtoSchemaType::kFloat: {
882 inserter.AddArg(name_id,
883 Variadic::Real(static_cast<double>(fld.as_float())));
884 break;
885 }
886 case ProtoSchemaType::kUnknown:
887 case ProtoSchemaType::kGroup:
888 case ProtoSchemaType::kMessage:
889 PERFETTO_DLOG("Could not store %s as a field in args table.",
890 ProtoSchemaToString(type));
891 break;
892 }
893 }
894 }
895
896 PERFETTO_ALWAYS_INLINE
ParseSchedSwitch(uint32_t cpu,int64_t timestamp,ConstBytes blob)897 void FtraceParser::ParseSchedSwitch(uint32_t cpu,
898 int64_t timestamp,
899 ConstBytes blob) {
900 protos::pbzero::SchedSwitchFtraceEvent::Decoder ss(blob.data, blob.size);
901 uint32_t prev_pid = static_cast<uint32_t>(ss.prev_pid());
902 uint32_t next_pid = static_cast<uint32_t>(ss.next_pid());
903 SchedEventTracker::GetOrCreate(context_)->PushSchedSwitch(
904 cpu, timestamp, prev_pid, ss.prev_comm(), ss.prev_prio(), ss.prev_state(),
905 next_pid, ss.next_comm(), ss.next_prio());
906 }
907
ParseSchedWakeup(int64_t timestamp,uint32_t pid,ConstBytes blob)908 void FtraceParser::ParseSchedWakeup(int64_t timestamp,
909 uint32_t pid,
910 ConstBytes blob) {
911 protos::pbzero::SchedWakeupFtraceEvent::Decoder sw(blob.data, blob.size);
912 uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
913 StringId name_id = context_->storage->InternString(sw.comm());
914 auto wakee_utid = context_->process_tracker->UpdateThreadName(
915 wakee_pid, name_id, ThreadNamePriority::kFtrace);
916 InstantId id = context_->event_tracker->PushInstant(
917 timestamp, sched_wakeup_name_id_, wakee_utid, RefType::kRefUtid);
918
919 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
920 context_->args_tracker->AddArgsTo(id).AddArg(waker_utid_id_,
921 Variadic::UnsignedInteger(utid));
922 }
923
ParseSchedWaking(int64_t timestamp,uint32_t pid,ConstBytes blob)924 void FtraceParser::ParseSchedWaking(int64_t timestamp,
925 uint32_t pid,
926 ConstBytes blob) {
927 protos::pbzero::SchedWakingFtraceEvent::Decoder sw(blob.data, blob.size);
928 uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
929 StringId name_id = context_->storage->InternString(sw.comm());
930 auto wakee_utid = context_->process_tracker->UpdateThreadName(
931 wakee_pid, name_id, ThreadNamePriority::kFtrace);
932 InstantId id = context_->event_tracker->PushInstant(
933 timestamp, sched_waking_name_id_, wakee_utid, RefType::kRefUtid);
934
935 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
936 context_->args_tracker->AddArgsTo(id).AddArg(waker_utid_id_,
937 Variadic::UnsignedInteger(utid));
938 }
939
ParseSchedProcessFree(int64_t timestamp,ConstBytes blob)940 void FtraceParser::ParseSchedProcessFree(int64_t timestamp, ConstBytes blob) {
941 protos::pbzero::SchedProcessFreeFtraceEvent::Decoder ex(blob.data, blob.size);
942 uint32_t pid = static_cast<uint32_t>(ex.pid());
943 context_->process_tracker->EndThread(timestamp, pid);
944 }
945
ParseCpuFreq(int64_t timestamp,ConstBytes blob)946 void FtraceParser::ParseCpuFreq(int64_t timestamp, ConstBytes blob) {
947 protos::pbzero::CpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
948 uint32_t cpu = freq.cpu_id();
949 uint32_t new_freq = freq.state();
950 TrackId track =
951 context_->track_tracker->InternCpuCounterTrack(cpu_freq_name_id_, cpu);
952 context_->event_tracker->PushCounter(timestamp, new_freq, track);
953 }
954
ParseGpuFreq(int64_t timestamp,ConstBytes blob)955 void FtraceParser::ParseGpuFreq(int64_t timestamp, ConstBytes blob) {
956 protos::pbzero::GpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
957 uint32_t gpu = freq.gpu_id();
958 uint32_t new_freq = freq.state();
959 TrackId track =
960 context_->track_tracker->InternGpuCounterTrack(gpu_freq_name_id_, gpu);
961 context_->event_tracker->PushCounter(timestamp, new_freq, track);
962 }
963
ParseCpuIdle(int64_t timestamp,ConstBytes blob)964 void FtraceParser::ParseCpuIdle(int64_t timestamp, ConstBytes blob) {
965 protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob.data, blob.size);
966 uint32_t cpu = idle.cpu_id();
967 uint32_t new_state = idle.state();
968 TrackId track =
969 context_->track_tracker->InternCpuCounterTrack(cpu_idle_name_id_, cpu);
970 context_->event_tracker->PushCounter(timestamp, new_state, track);
971 }
972
ParsePrint(int64_t timestamp,uint32_t pid,ConstBytes blob)973 void FtraceParser::ParsePrint(int64_t timestamp,
974 uint32_t pid,
975 ConstBytes blob) {
976 protos::pbzero::PrintFtraceEvent::Decoder evt(blob.data, blob.size);
977 SystraceParser::GetOrCreate(context_)->ParsePrintEvent(timestamp, pid,
978 evt.buf());
979 }
980
ParseZero(int64_t timestamp,uint32_t pid,ConstBytes blob)981 void FtraceParser::ParseZero(int64_t timestamp, uint32_t pid, ConstBytes blob) {
982 protos::pbzero::ZeroFtraceEvent::Decoder evt(blob.data, blob.size);
983 uint32_t tgid = static_cast<uint32_t>(evt.pid());
984 SystraceParser::GetOrCreate(context_)->ParseZeroEvent(
985 timestamp, pid, evt.flag(), evt.name(), tgid, evt.value());
986 }
987
ParseSdeTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)988 void FtraceParser::ParseSdeTracingMarkWrite(int64_t timestamp,
989 uint32_t pid,
990 ConstBytes blob) {
991 protos::pbzero::SdeTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
992 blob.size);
993 if (!evt.has_trace_type() && !evt.has_trace_begin()) {
994 context_->storage->IncrementStats(stats::systrace_parse_failure);
995 return;
996 }
997
998 uint32_t tgid = static_cast<uint32_t>(evt.pid());
999 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
1000 timestamp, pid, static_cast<char>(evt.trace_type()), evt.trace_begin(),
1001 evt.trace_name(), tgid, evt.value());
1002 }
1003
ParseDpuTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)1004 void FtraceParser::ParseDpuTracingMarkWrite(int64_t timestamp,
1005 uint32_t pid,
1006 ConstBytes blob) {
1007 protos::pbzero::DpuTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
1008 blob.size);
1009 if (!evt.type()) {
1010 context_->storage->IncrementStats(stats::systrace_parse_failure);
1011 return;
1012 }
1013
1014 uint32_t tgid = static_cast<uint32_t>(evt.pid());
1015 // For kernel counter events, they will become thread counter tracks.
1016 // But, we want to use the pid field specified in the event as the thread ID
1017 // of the thread_counter_track instead of using the thread ID that emitted
1018 // the events. So here, we need to override pid = tgid.
1019 if (static_cast<char>(evt.type()) == 'C') {
1020 pid = tgid;
1021 }
1022 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
1023 timestamp, pid, static_cast<char>(evt.type()), false /*trace_begin*/,
1024 evt.name(), tgid, evt.value());
1025 }
1026
ParseG2dTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)1027 void FtraceParser::ParseG2dTracingMarkWrite(int64_t timestamp,
1028 uint32_t pid,
1029 ConstBytes blob) {
1030 protos::pbzero::G2dTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
1031 blob.size);
1032 if (!evt.type()) {
1033 context_->storage->IncrementStats(stats::systrace_parse_failure);
1034 return;
1035 }
1036
1037 uint32_t tgid = static_cast<uint32_t>(evt.pid());
1038 // For kernel counter events, they will become thread counter tracks.
1039 // But, we want to use the pid field specified in the event as the thread ID
1040 // of the thread_counter_track instead of using the thread ID that emitted
1041 // the events. So here, we need to override pid = tgid.
1042 if (static_cast<char>(evt.type()) == 'C') {
1043 pid = tgid;
1044 }
1045 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
1046 timestamp, pid, static_cast<char>(evt.type()), false /*trace_begin*/,
1047 evt.name(), tgid, evt.value());
1048 }
1049
ParseMaliTracingMarkWrite(int64_t timestamp,uint32_t pid,ConstBytes blob)1050 void FtraceParser::ParseMaliTracingMarkWrite(int64_t timestamp,
1051 uint32_t pid,
1052 ConstBytes blob) {
1053 protos::pbzero::MaliTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
1054 blob.size);
1055 if (!evt.type()) {
1056 context_->storage->IncrementStats(stats::systrace_parse_failure);
1057 return;
1058 }
1059
1060 uint32_t tgid = static_cast<uint32_t>(evt.pid());
1061 SystraceParser::GetOrCreate(context_)->ParseTracingMarkWrite(
1062 timestamp, pid, static_cast<char>(evt.type()), false /*trace_begin*/,
1063 evt.name(), tgid, evt.value());
1064 }
1065
1066 /** Parses ion heap events present in Pixel kernels. */
ParseIonHeapGrowOrShrink(int64_t timestamp,uint32_t pid,ConstBytes blob,bool grow)1067 void FtraceParser::ParseIonHeapGrowOrShrink(int64_t timestamp,
1068 uint32_t pid,
1069 ConstBytes blob,
1070 bool grow) {
1071 protos::pbzero::IonHeapGrowFtraceEvent::Decoder ion(blob.data, blob.size);
1072 int64_t change_bytes = static_cast<int64_t>(ion.len()) * (grow ? 1 : -1);
1073 // The total_allocated ftrace event reports the value before the
1074 // atomic_long_add / sub takes place.
1075 int64_t total_bytes = ion.total_allocated() + change_bytes;
1076 StringId global_name_id = ion_total_unknown_id_;
1077 StringId change_name_id = ion_change_unknown_id_;
1078
1079 if (ion.has_heap_name()) {
1080 base::StringView heap_name = ion.heap_name();
1081 base::StackString<255> ion_name("mem.ion.%.*s", int(heap_name.size()),
1082 heap_name.data());
1083 global_name_id = context_->storage->InternString(ion_name.string_view());
1084
1085 base::StackString<255> change_name("mem.ion_change.%.*s",
1086 int(heap_name.size()), heap_name.data());
1087 change_name_id = context_->storage->InternString(change_name.string_view());
1088 }
1089
1090 // Push the global counter.
1091 TrackId track =
1092 context_->track_tracker->InternGlobalCounterTrack(global_name_id);
1093 context_->event_tracker->PushCounter(timestamp,
1094 static_cast<double>(total_bytes), track);
1095
1096 // Push the change counter.
1097 // TODO(b/121331269): these should really be instant events.
1098 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1099 track =
1100 context_->track_tracker->InternThreadCounterTrack(change_name_id, utid);
1101 context_->event_tracker->PushCounter(
1102 timestamp, static_cast<double>(change_bytes), track);
1103
1104 // We are reusing the same function for ion_heap_grow and ion_heap_shrink.
1105 // It is fine as the arguments are the same, but we need to be sure that the
1106 // protobuf field id for both are the same.
1107 static_assert(
1108 static_cast<int>(
1109 protos::pbzero::IonHeapGrowFtraceEvent::kTotalAllocatedFieldNumber) ==
1110 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
1111 kTotalAllocatedFieldNumber) &&
1112 static_cast<int>(
1113 protos::pbzero::IonHeapGrowFtraceEvent::kLenFieldNumber) ==
1114 static_cast<int>(
1115 protos::pbzero::IonHeapShrinkFtraceEvent::kLenFieldNumber) &&
1116 static_cast<int>(
1117 protos::pbzero::IonHeapGrowFtraceEvent::kHeapNameFieldNumber) ==
1118 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
1119 kHeapNameFieldNumber),
1120 "ION field mismatch");
1121 }
1122
1123 /** Parses ion heap events (introduced in 4.19 kernels). */
ParseIonStat(int64_t timestamp,uint32_t pid,protozero::ConstBytes data)1124 void FtraceParser::ParseIonStat(int64_t timestamp,
1125 uint32_t pid,
1126 protozero::ConstBytes data) {
1127 protos::pbzero::IonStatFtraceEvent::Decoder ion(data.data, data.size);
1128 // Push the global counter.
1129 TrackId track =
1130 context_->track_tracker->InternGlobalCounterTrack(ion_total_id_);
1131 context_->event_tracker->PushCounter(
1132 timestamp, static_cast<double>(ion.total_allocated()), track);
1133
1134 // Push the change counter.
1135 // TODO(b/121331269): these should really be instant events.
1136 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1137 track =
1138 context_->track_tracker->InternThreadCounterTrack(ion_change_id_, utid);
1139 context_->event_tracker->PushCounter(timestamp,
1140 static_cast<double>(ion.len()), track);
1141
1142 // Global track for individual buffer tracking
1143 auto async_track =
1144 context_->async_track_set_tracker->InternGlobalTrackSet(ion_buffer_id_);
1145 if (ion.len() > 0) {
1146 TrackId start_id =
1147 context_->async_track_set_tracker->Begin(async_track, ion.buffer_id());
1148 std::string buf = std::to_string(ion.len() / 1024) + " kB";
1149 context_->slice_tracker->Begin(
1150 timestamp, start_id, kNullStringId,
1151 context_->storage->InternString(base::StringView(buf)));
1152 } else {
1153 TrackId end_id =
1154 context_->async_track_set_tracker->End(async_track, ion.buffer_id());
1155 context_->slice_tracker->End(timestamp, end_id);
1156 }
1157 }
1158
ParseDmaHeapStat(int64_t timestamp,uint32_t pid,protozero::ConstBytes data)1159 void FtraceParser::ParseDmaHeapStat(int64_t timestamp,
1160 uint32_t pid,
1161 protozero::ConstBytes data) {
1162 protos::pbzero::DmaHeapStatFtraceEvent::Decoder dma_heap(data.data,
1163 data.size);
1164 // Push the global counter.
1165 TrackId track =
1166 context_->track_tracker->InternGlobalCounterTrack(dma_heap_total_id_);
1167 context_->event_tracker->PushCounter(
1168 timestamp, static_cast<double>(dma_heap.total_allocated()), track);
1169
1170 // Push the change counter.
1171 // TODO(b/121331269): these should really be instant events.
1172 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1173 track = context_->track_tracker->InternThreadCounterTrack(dma_heap_change_id_,
1174 utid);
1175 context_->event_tracker->PushCounter(
1176 timestamp, static_cast<double>(dma_heap.len()), track);
1177
1178 // Global track for individual buffer tracking
1179 auto async_track =
1180 context_->async_track_set_tracker->InternGlobalTrackSet(dma_buffer_id_);
1181 if (dma_heap.len() > 0) {
1182 TrackId start_id = context_->async_track_set_tracker->Begin(
1183 async_track, static_cast<int64_t>(dma_heap.inode()));
1184 std::string buf = std::to_string(dma_heap.len() / 1024) + " kB";
1185 context_->slice_tracker->Begin(
1186 timestamp, start_id, kNullStringId,
1187 context_->storage->InternString(base::StringView(buf)));
1188 } else {
1189 TrackId end_id = context_->async_track_set_tracker->End(
1190 async_track, static_cast<int64_t>(dma_heap.inode()));
1191 context_->slice_tracker->End(timestamp, end_id);
1192 }
1193 }
1194
1195 // This event has both the pid of the thread that sent the signal and the
1196 // destination of the signal. Currently storing the pid of the destination.
ParseSignalGenerate(int64_t timestamp,ConstBytes blob)1197 void FtraceParser::ParseSignalGenerate(int64_t timestamp, ConstBytes blob) {
1198 protos::pbzero::SignalGenerateFtraceEvent::Decoder sig(blob.data, blob.size);
1199
1200 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
1201 static_cast<uint32_t>(sig.pid()));
1202 InstantId id = context_->event_tracker->PushInstant(
1203 timestamp, signal_generate_id_, utid, RefType::kRefUtid);
1204
1205 context_->args_tracker->AddArgsTo(id).AddArg(signal_name_id_,
1206 Variadic::Integer(sig.sig()));
1207 }
1208
ParseSignalDeliver(int64_t timestamp,uint32_t pid,ConstBytes blob)1209 void FtraceParser::ParseSignalDeliver(int64_t timestamp,
1210 uint32_t pid,
1211 ConstBytes blob) {
1212 protos::pbzero::SignalDeliverFtraceEvent::Decoder sig(blob.data, blob.size);
1213 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1214 InstantId id = context_->event_tracker->PushInstant(
1215 timestamp, signal_deliver_id_, utid, RefType::kRefUtid);
1216
1217 context_->args_tracker->AddArgsTo(id).AddArg(signal_name_id_,
1218 Variadic::Integer(sig.sig()));
1219 }
1220
ParseLowmemoryKill(int64_t timestamp,ConstBytes blob)1221 void FtraceParser::ParseLowmemoryKill(int64_t timestamp, ConstBytes blob) {
1222 // TODO(hjd): Store the pagecache_size, pagecache_limit and free fields
1223 // in an args table
1224 protos::pbzero::LowmemoryKillFtraceEvent::Decoder lmk(blob.data, blob.size);
1225
1226 // Store the pid of the event that is lmk-ed.
1227 auto pid = static_cast<uint32_t>(lmk.pid());
1228 auto opt_utid = context_->process_tracker->GetThreadOrNull(pid);
1229
1230 // Don't add LMK events for threads we've never seen before. This works
1231 // around the case where we get an LMK event after a thread has already been
1232 // killed.
1233 if (!opt_utid)
1234 return;
1235
1236 InstantId id = context_->event_tracker->PushInstant(
1237 timestamp, lmk_id_, opt_utid.value(), RefType::kRefUtid, true);
1238
1239 // Store the comm as an arg.
1240 auto comm_id = context_->storage->InternString(
1241 lmk.has_comm() ? lmk.comm() : base::StringView());
1242 context_->args_tracker->AddArgsTo(id).AddArg(comm_name_id_,
1243 Variadic::String(comm_id));
1244 }
1245
ParseOOMScoreAdjUpdate(int64_t timestamp,ConstBytes blob)1246 void FtraceParser::ParseOOMScoreAdjUpdate(int64_t timestamp, ConstBytes blob) {
1247 protos::pbzero::OomScoreAdjUpdateFtraceEvent::Decoder evt(blob.data,
1248 blob.size);
1249 // The int16_t static cast is because older version of the on-device tracer
1250 // had a bug on negative varint encoding (b/120618641).
1251 int16_t oom_adj = static_cast<int16_t>(evt.oom_score_adj());
1252 uint32_t tid = static_cast<uint32_t>(evt.pid());
1253 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
1254 context_->event_tracker->PushProcessCounterForThread(timestamp, oom_adj,
1255 oom_score_adj_id_, utid);
1256 }
1257
ParseOOMKill(int64_t timestamp,ConstBytes blob)1258 void FtraceParser::ParseOOMKill(int64_t timestamp, ConstBytes blob) {
1259 protos::pbzero::MarkVictimFtraceEvent::Decoder evt(blob.data, blob.size);
1260 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
1261 static_cast<uint32_t>(evt.pid()));
1262 context_->event_tracker->PushInstant(timestamp, oom_kill_id_, utid,
1263 RefType::kRefUtid, true);
1264 }
1265
ParseMmEventRecord(int64_t timestamp,uint32_t pid,ConstBytes blob)1266 void FtraceParser::ParseMmEventRecord(int64_t timestamp,
1267 uint32_t pid,
1268 ConstBytes blob) {
1269 protos::pbzero::MmEventRecordFtraceEvent::Decoder evt(blob.data, blob.size);
1270 uint32_t type = evt.type();
1271 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1272
1273 if (type >= mm_event_counter_names_.size()) {
1274 context_->storage->IncrementStats(stats::mm_unknown_type);
1275 return;
1276 }
1277
1278 const auto& counter_names = mm_event_counter_names_[type];
1279 context_->event_tracker->PushProcessCounterForThread(
1280 timestamp, evt.count(), counter_names.count, utid);
1281 context_->event_tracker->PushProcessCounterForThread(
1282 timestamp, evt.max_lat(), counter_names.max_lat, utid);
1283 context_->event_tracker->PushProcessCounterForThread(
1284 timestamp, evt.avg_lat(), counter_names.avg_lat, utid);
1285 }
1286
ParseSysEvent(int64_t timestamp,uint32_t pid,bool is_enter,ConstBytes blob)1287 void FtraceParser::ParseSysEvent(int64_t timestamp,
1288 uint32_t pid,
1289 bool is_enter,
1290 ConstBytes blob) {
1291 protos::pbzero::SysEnterFtraceEvent::Decoder evt(blob.data, blob.size);
1292 uint32_t syscall_num = static_cast<uint32_t>(evt.id());
1293 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1294
1295 SyscallTracker* syscall_tracker = SyscallTracker::GetOrCreate(context_);
1296 if (is_enter) {
1297 syscall_tracker->Enter(timestamp, utid, syscall_num);
1298 } else {
1299 syscall_tracker->Exit(timestamp, utid, syscall_num);
1300 }
1301
1302 // We are reusing the same function for sys_enter and sys_exit.
1303 // It is fine as the arguments are the same, but we need to be sure that the
1304 // protobuf field id for both are the same.
1305 static_assert(
1306 static_cast<int>(protos::pbzero::SysEnterFtraceEvent::kIdFieldNumber) ==
1307 static_cast<int>(protos::pbzero::SysExitFtraceEvent::kIdFieldNumber),
1308 "field mismatch");
1309 }
1310
ParseTaskNewTask(int64_t timestamp,uint32_t source_tid,ConstBytes blob)1311 void FtraceParser::ParseTaskNewTask(int64_t timestamp,
1312 uint32_t source_tid,
1313 ConstBytes blob) {
1314 protos::pbzero::TaskNewtaskFtraceEvent::Decoder evt(blob.data, blob.size);
1315 uint32_t clone_flags = static_cast<uint32_t>(evt.clone_flags());
1316 uint32_t new_tid = static_cast<uint32_t>(evt.pid());
1317 StringId new_comm = context_->storage->InternString(evt.comm());
1318 auto* proc_tracker = context_->process_tracker.get();
1319
1320 // task_newtask is raised both in the case of a new process creation (fork()
1321 // family) and thread creation (clone(CLONE_THREAD, ...)).
1322 static const uint32_t kCloneThread = 0x00010000; // From kernel's sched.h.
1323
1324 // If the process is a fork, start a new process except if the source tid is
1325 // kthreadd in which case just make it a new thread associated with
1326 // kthreadd.
1327 if ((clone_flags & kCloneThread) == 0 && source_tid != kKthreaddPid) {
1328 // This is a plain-old fork() or equivalent.
1329 proc_tracker->StartNewProcess(timestamp, source_tid, new_tid, new_comm,
1330 ThreadNamePriority::kFtrace);
1331 return;
1332 }
1333
1334 if (source_tid == kKthreaddPid) {
1335 context_->process_tracker->SetProcessMetadata(
1336 kKthreaddPid, base::nullopt, kKthreaddName, base::StringView());
1337 }
1338
1339 // This is a pthread_create or similar. Bind the two threads together, so
1340 // they get resolved to the same process.
1341 auto source_utid = proc_tracker->GetOrCreateThread(source_tid);
1342 auto new_utid = proc_tracker->StartNewThread(timestamp, new_tid);
1343 proc_tracker->UpdateThreadNameByUtid(new_utid, new_comm,
1344 ThreadNamePriority::kFtrace);
1345 proc_tracker->AssociateThreads(source_utid, new_utid);
1346 }
1347
ParseTaskRename(ConstBytes blob)1348 void FtraceParser::ParseTaskRename(ConstBytes blob) {
1349 protos::pbzero::TaskRenameFtraceEvent::Decoder evt(blob.data, blob.size);
1350 uint32_t tid = static_cast<uint32_t>(evt.pid());
1351 StringId comm = context_->storage->InternString(evt.newcomm());
1352 context_->process_tracker->UpdateThreadNameAndMaybeProcessName(
1353 tid, comm, ThreadNamePriority::kFtrace);
1354 }
1355
ParseBinderTransaction(int64_t timestamp,uint32_t pid,ConstBytes blob)1356 void FtraceParser::ParseBinderTransaction(int64_t timestamp,
1357 uint32_t pid,
1358 ConstBytes blob) {
1359 protos::pbzero::BinderTransactionFtraceEvent::Decoder evt(blob.data,
1360 blob.size);
1361 int32_t dest_node = static_cast<int32_t>(evt.target_node());
1362 uint32_t dest_tgid = static_cast<uint32_t>(evt.to_proc());
1363 uint32_t dest_tid = static_cast<uint32_t>(evt.to_thread());
1364 int32_t transaction_id = static_cast<int32_t>(evt.debug_id());
1365 bool is_reply = static_cast<int32_t>(evt.reply()) == 1;
1366 uint32_t flags = static_cast<uint32_t>(evt.flags());
1367 auto code_str = base::IntToHexString(evt.code()) + " Java Layer Dependent";
1368 StringId code = context_->storage->InternString(base::StringView(code_str));
1369 BinderTracker::GetOrCreate(context_)->Transaction(
1370 timestamp, pid, transaction_id, dest_node, dest_tgid, dest_tid, is_reply,
1371 flags, code);
1372 }
1373
ParseBinderTransactionReceived(int64_t timestamp,uint32_t pid,ConstBytes blob)1374 void FtraceParser::ParseBinderTransactionReceived(int64_t timestamp,
1375 uint32_t pid,
1376 ConstBytes blob) {
1377 protos::pbzero::BinderTransactionReceivedFtraceEvent::Decoder evt(blob.data,
1378 blob.size);
1379 int32_t transaction_id = static_cast<int32_t>(evt.debug_id());
1380 BinderTracker::GetOrCreate(context_)->TransactionReceived(timestamp, pid,
1381 transaction_id);
1382 }
1383
ParseBinderTransactionAllocBuf(int64_t timestamp,uint32_t pid,ConstBytes blob)1384 void FtraceParser::ParseBinderTransactionAllocBuf(int64_t timestamp,
1385 uint32_t pid,
1386 ConstBytes blob) {
1387 protos::pbzero::BinderTransactionAllocBufFtraceEvent::Decoder evt(blob.data,
1388 blob.size);
1389 uint64_t data_size = static_cast<uint64_t>(evt.data_size());
1390 uint64_t offsets_size = static_cast<uint64_t>(evt.offsets_size());
1391
1392 BinderTracker::GetOrCreate(context_)->TransactionAllocBuf(
1393 timestamp, pid, data_size, offsets_size);
1394 }
1395
ParseBinderLocked(int64_t timestamp,uint32_t pid,ConstBytes blob)1396 void FtraceParser::ParseBinderLocked(int64_t timestamp,
1397 uint32_t pid,
1398 ConstBytes blob) {
1399 protos::pbzero::BinderLockedFtraceEvent::Decoder evt(blob.data, blob.size);
1400 BinderTracker::GetOrCreate(context_)->Locked(timestamp, pid);
1401 }
1402
ParseBinderLock(int64_t timestamp,uint32_t pid,ConstBytes blob)1403 void FtraceParser::ParseBinderLock(int64_t timestamp,
1404 uint32_t pid,
1405 ConstBytes blob) {
1406 protos::pbzero::BinderLockFtraceEvent::Decoder evt(blob.data, blob.size);
1407 BinderTracker::GetOrCreate(context_)->Lock(timestamp, pid);
1408 }
1409
ParseBinderUnlock(int64_t timestamp,uint32_t pid,ConstBytes blob)1410 void FtraceParser::ParseBinderUnlock(int64_t timestamp,
1411 uint32_t pid,
1412 ConstBytes blob) {
1413 protos::pbzero::BinderUnlockFtraceEvent::Decoder evt(blob.data, blob.size);
1414 BinderTracker::GetOrCreate(context_)->Unlock(timestamp, pid);
1415 }
1416
ParseClockSetRate(int64_t timestamp,ConstBytes blob)1417 void FtraceParser::ParseClockSetRate(int64_t timestamp, ConstBytes blob) {
1418 protos::pbzero::ClockSetRateFtraceEvent::Decoder evt(blob.data, blob.size);
1419 static const char kSubtitle[] = "Frequency";
1420 ClockRate(timestamp, evt.name(), kSubtitle, evt.state());
1421 }
1422
ParseClockEnable(int64_t timestamp,ConstBytes blob)1423 void FtraceParser::ParseClockEnable(int64_t timestamp, ConstBytes blob) {
1424 protos::pbzero::ClockEnableFtraceEvent::Decoder evt(blob.data, blob.size);
1425 static const char kSubtitle[] = "State";
1426 ClockRate(timestamp, evt.name(), kSubtitle, evt.state());
1427 }
1428
ParseClockDisable(int64_t timestamp,ConstBytes blob)1429 void FtraceParser::ParseClockDisable(int64_t timestamp, ConstBytes blob) {
1430 protos::pbzero::ClockDisableFtraceEvent::Decoder evt(blob.data, blob.size);
1431 static const char kSubtitle[] = "State";
1432 ClockRate(timestamp, evt.name(), kSubtitle, evt.state());
1433 }
1434
ClockRate(int64_t timestamp,base::StringView clock_name,base::StringView subtitle,uint64_t rate)1435 void FtraceParser::ClockRate(int64_t timestamp,
1436 base::StringView clock_name,
1437 base::StringView subtitle,
1438 uint64_t rate) {
1439 base::StackString<255> counter_name("%.*s %.*s", int(clock_name.size()),
1440 clock_name.data(), int(subtitle.size()),
1441 subtitle.data());
1442 StringId name = context_->storage->InternString(counter_name.c_str());
1443 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1444 context_->event_tracker->PushCounter(timestamp, static_cast<double>(rate),
1445 track);
1446 }
1447
ParseScmCallStart(int64_t timestamp,uint32_t pid,ConstBytes blob)1448 void FtraceParser::ParseScmCallStart(int64_t timestamp,
1449 uint32_t pid,
1450 ConstBytes blob) {
1451 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1452 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
1453 protos::pbzero::ScmCallStartFtraceEvent::Decoder evt(blob.data, blob.size);
1454
1455 char str[64];
1456 sprintf(str, "scm id=%#" PRIx64, evt.x0());
1457 StringId name_id = context_->storage->InternString(str);
1458 context_->slice_tracker->Begin(timestamp, track_id, kNullStringId, name_id);
1459 }
1460
ParseScmCallEnd(int64_t timestamp,uint32_t pid,ConstBytes blob)1461 void FtraceParser::ParseScmCallEnd(int64_t timestamp,
1462 uint32_t pid,
1463 ConstBytes blob) {
1464 protos::pbzero::ScmCallEndFtraceEvent::Decoder evt(blob.data, blob.size);
1465 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1466 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
1467 context_->slice_tracker->End(timestamp, track_id);
1468 }
1469
ParseDirectReclaimBegin(int64_t timestamp,uint32_t pid,ConstBytes blob)1470 void FtraceParser::ParseDirectReclaimBegin(int64_t timestamp,
1471 uint32_t pid,
1472 ConstBytes blob) {
1473 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1474 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
1475 protos::pbzero::MmVmscanDirectReclaimBeginFtraceEvent::Decoder
1476 direct_reclaim_begin(blob.data, blob.size);
1477
1478 StringId name_id =
1479 context_->storage->InternString("mm_vmscan_direct_reclaim");
1480
1481 auto args_inserter = [this, &direct_reclaim_begin](
1482 ArgsTracker::BoundInserter* inserter) {
1483 inserter->AddArg(direct_reclaim_order_id_,
1484 Variadic::Integer(direct_reclaim_begin.order()));
1485 inserter->AddArg(direct_reclaim_may_writepage_id_,
1486 Variadic::Integer(direct_reclaim_begin.may_writepage()));
1487 inserter->AddArg(
1488 direct_reclaim_gfp_flags_id_,
1489 Variadic::UnsignedInteger(direct_reclaim_begin.gfp_flags()));
1490 };
1491 context_->slice_tracker->Begin(timestamp, track_id, kNullStringId, name_id,
1492 args_inserter);
1493 }
1494
ParseDirectReclaimEnd(int64_t timestamp,uint32_t pid,ConstBytes blob)1495 void FtraceParser::ParseDirectReclaimEnd(int64_t timestamp,
1496 uint32_t pid,
1497 ConstBytes blob) {
1498 protos::pbzero::ScmCallEndFtraceEvent::Decoder evt(blob.data, blob.size);
1499 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1500 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
1501 protos::pbzero::MmVmscanDirectReclaimEndFtraceEvent::Decoder
1502 direct_reclaim_end(blob.data, blob.size);
1503
1504 auto args_inserter =
1505 [this, &direct_reclaim_end](ArgsTracker::BoundInserter* inserter) {
1506 inserter->AddArg(
1507 direct_reclaim_nr_reclaimed_id_,
1508 Variadic::UnsignedInteger(direct_reclaim_end.nr_reclaimed()));
1509 };
1510 context_->slice_tracker->End(timestamp, track_id, kNullStringId,
1511 kNullStringId, args_inserter);
1512 }
1513
ParseWorkqueueExecuteStart(uint32_t cpu,int64_t timestamp,uint32_t pid,ConstBytes blob,PacketSequenceStateGeneration * seq_state)1514 void FtraceParser::ParseWorkqueueExecuteStart(
1515 uint32_t cpu,
1516 int64_t timestamp,
1517 uint32_t pid,
1518 ConstBytes blob,
1519 PacketSequenceStateGeneration* seq_state) {
1520 protos::pbzero::WorkqueueExecuteStartFtraceEvent::Decoder evt(blob.data,
1521 blob.size);
1522
1523 auto* interned_string = seq_state->LookupInternedMessage<
1524 protos::pbzero::InternedData::kKernelSymbolsFieldNumber,
1525 protos::pbzero::InternedString>(static_cast<uint32_t>(evt.function()));
1526 StringId name_id;
1527 if (interned_string) {
1528 protozero::ConstBytes str = interned_string->str();
1529 name_id = context_->storage->InternString(
1530 base::StringView(reinterpret_cast<const char*>(str.data), str.size));
1531 } else {
1532 base::StackString<255> slice_name("%#" PRIx64, evt.function());
1533 name_id = context_->storage->InternString(slice_name.string_view());
1534 }
1535
1536 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1537 TrackId track = context_->track_tracker->InternThreadTrack(utid);
1538
1539 auto args_inserter = [this, cpu](ArgsTracker::BoundInserter* inserter) {
1540 inserter->AddArg(cpu_id_, Variadic::Integer(cpu));
1541 };
1542 context_->slice_tracker->Begin(timestamp, track, workqueue_id_, name_id,
1543 args_inserter);
1544 }
1545
ParseWorkqueueExecuteEnd(int64_t timestamp,uint32_t pid,ConstBytes blob)1546 void FtraceParser::ParseWorkqueueExecuteEnd(int64_t timestamp,
1547 uint32_t pid,
1548 ConstBytes blob) {
1549 protos::pbzero::WorkqueueExecuteEndFtraceEvent::Decoder evt(blob.data,
1550 blob.size);
1551 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1552 TrackId track = context_->track_tracker->InternThreadTrack(utid);
1553 context_->slice_tracker->End(timestamp, track, workqueue_id_);
1554 }
1555
ParseIrqHandlerEntry(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1556 void FtraceParser::ParseIrqHandlerEntry(uint32_t cpu,
1557 int64_t timestamp,
1558 protozero::ConstBytes blob) {
1559 protos::pbzero::IrqHandlerEntryFtraceEvent::Decoder evt(blob.data, blob.size);
1560 base::StackString<255> track_name("Irq Cpu %d", cpu);
1561 StringId track_name_id =
1562 context_->storage->InternString(track_name.string_view());
1563
1564 base::StringView irq_name = evt.name();
1565 base::StackString<255> slice_name("IRQ (%.*s)", int(irq_name.size()),
1566 irq_name.data());
1567 StringId slice_name_id =
1568 context_->storage->InternString(slice_name.string_view());
1569 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1570 context_->slice_tracker->Begin(timestamp, track, irq_id_, slice_name_id);
1571 }
1572
ParseIrqHandlerExit(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1573 void FtraceParser::ParseIrqHandlerExit(uint32_t cpu,
1574 int64_t timestamp,
1575 protozero::ConstBytes blob) {
1576 protos::pbzero::IrqHandlerExitFtraceEvent::Decoder evt(blob.data, blob.size);
1577 base::StackString<255> track_name("Irq Cpu %d", cpu);
1578 StringId track_name_id =
1579 context_->storage->InternString(track_name.string_view());
1580 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1581
1582 base::StackString<255> status("%s", evt.ret() == 1 ? "handled" : "unhandled");
1583 StringId status_id = context_->storage->InternString(status.string_view());
1584 auto args_inserter = [this,
1585 &status_id](ArgsTracker::BoundInserter* inserter) {
1586 inserter->AddArg(ret_arg_id_, Variadic::String(status_id));
1587 };
1588 context_->slice_tracker->End(timestamp, track, irq_id_, {}, args_inserter);
1589 }
1590
ParseSoftIrqEntry(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1591 void FtraceParser::ParseSoftIrqEntry(uint32_t cpu,
1592 int64_t timestamp,
1593 protozero::ConstBytes blob) {
1594 protos::pbzero::SoftirqEntryFtraceEvent::Decoder evt(blob.data, blob.size);
1595 base::StackString<255> track_name("SoftIrq Cpu %d", cpu);
1596 StringId track_name_id =
1597 context_->storage->InternString(track_name.string_view());
1598 auto num_actions = sizeof(kActionNames) / sizeof(*kActionNames);
1599 if (evt.vec() >= num_actions) {
1600 PERFETTO_DFATAL("No action name at index %d for softirq event.", evt.vec());
1601 return;
1602 }
1603 base::StringView slice_name = kActionNames[evt.vec()];
1604 StringId slice_name_id = context_->storage->InternString(slice_name);
1605 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1606 context_->slice_tracker->Begin(timestamp, track, irq_id_, slice_name_id);
1607 }
1608
ParseSoftIrqExit(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1609 void FtraceParser::ParseSoftIrqExit(uint32_t cpu,
1610 int64_t timestamp,
1611 protozero::ConstBytes blob) {
1612 protos::pbzero::SoftirqExitFtraceEvent::Decoder evt(blob.data, blob.size);
1613 base::StackString<255> track_name("SoftIrq Cpu %d", cpu);
1614 StringId track_name_id =
1615 context_->storage->InternString(track_name.string_view());
1616 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1617 auto vec = evt.vec();
1618 auto args_inserter = [this, vec](ArgsTracker::BoundInserter* inserter) {
1619 inserter->AddArg(vec_arg_id_, Variadic::Integer(vec));
1620 };
1621 context_->slice_tracker->End(timestamp, track, irq_id_, {}, args_inserter);
1622 }
1623
ParseGpuMemTotal(int64_t timestamp,protozero::ConstBytes data)1624 void FtraceParser::ParseGpuMemTotal(int64_t timestamp,
1625 protozero::ConstBytes data) {
1626 protos::pbzero::GpuMemTotalFtraceEvent::Decoder gpu_mem_total(data.data,
1627 data.size);
1628
1629 TrackId track = kInvalidTrackId;
1630 const uint32_t pid = gpu_mem_total.pid();
1631 if (pid == 0) {
1632 // Pid 0 is used to indicate the global total
1633 track = context_->track_tracker->InternGlobalCounterTrack(
1634 gpu_mem_total_name_id_, gpu_mem_total_unit_id_,
1635 gpu_mem_total_global_desc_id_);
1636 } else {
1637 // It's possible for GpuMemTotal ftrace events to be emitted by kworker
1638 // threads *after* process death. In this case, we simply want to discard
1639 // the event as otherwise we would create fake processes which we
1640 // definitely want to avoid.
1641 // See b/192274404 for more info.
1642 base::Optional<UniqueTid> opt_utid =
1643 context_->process_tracker->GetThreadOrNull(pid);
1644 if (!opt_utid)
1645 return;
1646
1647 // If the thread does exist, the |pid| in gpu_mem_total events is always a
1648 // true process id (and not a thread id) so ensure there is an association
1649 // between the tid and pid.
1650 UniqueTid updated_utid = context_->process_tracker->UpdateThread(pid, pid);
1651 PERFETTO_DCHECK(updated_utid == *opt_utid);
1652
1653 // UpdateThread above should ensure this is always set.
1654 UniquePid upid = *context_->storage->thread_table().upid()[*opt_utid];
1655 PERFETTO_DCHECK(context_->storage->process_table().pid()[upid] == pid);
1656
1657 track = context_->track_tracker->InternProcessCounterTrack(
1658 gpu_mem_total_name_id_, upid, gpu_mem_total_unit_id_,
1659 gpu_mem_total_proc_desc_id_);
1660 }
1661 context_->event_tracker->PushCounter(
1662 timestamp, static_cast<double>(gpu_mem_total.size()), track);
1663 }
1664
ParseThermalTemperature(int64_t timestamp,protozero::ConstBytes blob)1665 void FtraceParser::ParseThermalTemperature(int64_t timestamp,
1666 protozero::ConstBytes blob) {
1667 protos::pbzero::ThermalTemperatureFtraceEvent::Decoder evt(blob.data,
1668 blob.size);
1669 base::StringView thermal_zone = evt.thermal_zone();
1670 base::StackString<255> counter_name(
1671 "%.*s Temperature", int(thermal_zone.size()), thermal_zone.data());
1672 StringId name = context_->storage->InternString(counter_name.string_view());
1673 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1674 context_->event_tracker->PushCounter(timestamp, evt.temp(), track);
1675 }
1676
ParseCdevUpdate(int64_t timestamp,protozero::ConstBytes blob)1677 void FtraceParser::ParseCdevUpdate(int64_t timestamp,
1678 protozero::ConstBytes blob) {
1679 protos::pbzero::CdevUpdateFtraceEvent::Decoder evt(blob.data, blob.size);
1680 base::StringView type = evt.type();
1681 base::StackString<255> counter_name("%.*s Cooling Device", int(type.size()),
1682 type.data());
1683 StringId name = context_->storage->InternString(counter_name.string_view());
1684 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1685 context_->event_tracker->PushCounter(
1686 timestamp, static_cast<double>(evt.target()), track);
1687 }
1688
ParseSchedBlockedReason(int64_t timestamp,protozero::ConstBytes blob,PacketSequenceStateGeneration * seq_state)1689 void FtraceParser::ParseSchedBlockedReason(
1690 int64_t timestamp,
1691 protozero::ConstBytes blob,
1692 PacketSequenceStateGeneration* seq_state) {
1693 protos::pbzero::SchedBlockedReasonFtraceEvent::Decoder evt(blob);
1694 uint32_t pid = static_cast<uint32_t>(evt.pid());
1695 auto utid = context_->process_tracker->GetOrCreateThread(pid);
1696 InstantId id = context_->event_tracker->PushInstant(
1697 timestamp, sched_blocked_reason_id_, utid, RefType::kRefUtid, false);
1698
1699 auto inserter = context_->args_tracker->AddArgsTo(id);
1700 inserter.AddArg(io_wait_id_, Variadic::Boolean(evt.io_wait()));
1701
1702 uint32_t caller_iid = static_cast<uint32_t>(evt.caller());
1703 auto* interned_string = seq_state->LookupInternedMessage<
1704 protos::pbzero::InternedData::kKernelSymbolsFieldNumber,
1705 protos::pbzero::InternedString>(caller_iid);
1706
1707 if (interned_string) {
1708 protozero::ConstBytes str = interned_string->str();
1709 StringId str_id = context_->storage->InternString(
1710 base::StringView(reinterpret_cast<const char*>(str.data), str.size));
1711 inserter.AddArg(function_id_, Variadic::String(str_id));
1712 }
1713 }
1714
ParseFastRpcDmaStat(int64_t timestamp,uint32_t pid,protozero::ConstBytes blob)1715 void FtraceParser::ParseFastRpcDmaStat(int64_t timestamp,
1716 uint32_t pid,
1717 protozero::ConstBytes blob) {
1718 protos::pbzero::FastrpcDmaStatFtraceEvent::Decoder evt(blob.data, blob.size);
1719
1720 StringId name;
1721 if (0 <= evt.cid() && evt.cid() < static_cast<int32_t>(kFastRpcCounterSize)) {
1722 name = fast_rpc_delta_names_[static_cast<size_t>(evt.cid())];
1723 } else {
1724 base::StackString<64> str("mem.fastrpc[%" PRId32 "]", evt.cid());
1725 name = context_->storage->InternString(str.string_view());
1726 }
1727
1728 StringId total_name;
1729 if (0 <= evt.cid() && evt.cid() < static_cast<int32_t>(kFastRpcCounterSize)) {
1730 total_name = fast_rpc_total_names_[static_cast<size_t>(evt.cid())];
1731 } else {
1732 base::StackString<64> str("mem.fastrpc[%" PRId32 "]", evt.cid());
1733 total_name = context_->storage->InternString(str.string_view());
1734 }
1735
1736 // Push the global counter.
1737 TrackId track = context_->track_tracker->InternGlobalCounterTrack(total_name);
1738 context_->event_tracker->PushCounter(
1739 timestamp, static_cast<double>(evt.total_allocated()), track);
1740
1741 // Push the change counter.
1742 // TODO(b/121331269): these should really be instant events.
1743 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
1744 TrackId delta_track =
1745 context_->track_tracker->InternThreadCounterTrack(name, utid);
1746 context_->event_tracker->PushCounter(
1747 timestamp, static_cast<double>(evt.len()), delta_track);
1748 }
1749
ParseCpuhpPause(int64_t,uint32_t,protozero::ConstBytes blob)1750 void FtraceParser::ParseCpuhpPause(int64_t,
1751 uint32_t,
1752 protozero::ConstBytes blob) {
1753 protos::pbzero::CpuhpPauseFtraceEvent::Decoder evt(blob.data, blob.size);
1754 // TODO(b/183110813): Parse and visualize this event.
1755 }
1756
ParseNetifReceiveSkb(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1757 void FtraceParser::ParseNetifReceiveSkb(uint32_t cpu,
1758 int64_t timestamp,
1759 protozero::ConstBytes blob) {
1760 protos::pbzero::NetifReceiveSkbFtraceEvent::Decoder evt(blob.data, blob.size);
1761 base::StringView net_device = evt.name();
1762 base::StackString<255> counter_name("%.*s Received KB",
1763 static_cast<int>(net_device.size()),
1764 net_device.data());
1765 StringId name = context_->storage->InternString(counter_name.string_view());
1766
1767 nic_received_bytes_[name] += evt.len();
1768
1769 uint64_t nic_received_kilobytes = nic_received_bytes_[name] / 1024;
1770 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1771 base::Optional<CounterId> id = context_->event_tracker->PushCounter(
1772 timestamp, static_cast<double>(nic_received_kilobytes), track);
1773 if (!id) {
1774 return;
1775 }
1776 // Store cpu & len as args for metrics computation
1777 StringId cpu_key = context_->storage->InternString("cpu");
1778 StringId len_key = context_->storage->InternString("len");
1779 context_->args_tracker->AddArgsTo(*id)
1780 .AddArg(cpu_key, Variadic::UnsignedInteger(cpu))
1781 .AddArg(len_key, Variadic::UnsignedInteger(evt.len()));
1782 }
1783
ParseNetDevXmit(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1784 void FtraceParser::ParseNetDevXmit(uint32_t cpu,
1785 int64_t timestamp,
1786 protozero::ConstBytes blob) {
1787 protos::pbzero::NetDevXmitFtraceEvent::Decoder evt(blob.data, blob.size);
1788 base::StringView net_device = evt.name();
1789 base::StackString<255> counter_name("%.*s Transmitted KB",
1790 static_cast<int>(net_device.size()),
1791 net_device.data());
1792 StringId name = context_->storage->InternString(counter_name.string_view());
1793
1794 // Make sure driver took care of packet.
1795 if (evt.rc() != 0) {
1796 return;
1797 }
1798 nic_transmitted_bytes_[name] += evt.len();
1799
1800 uint64_t nic_transmitted_kilobytes = nic_transmitted_bytes_[name] / 1024;
1801 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
1802 base::Optional<CounterId> id = context_->event_tracker->PushCounter(
1803 timestamp, static_cast<double>(nic_transmitted_kilobytes), track);
1804 if (!id) {
1805 return;
1806 }
1807 // Store cpu & len as args for metrics computation.
1808 context_->args_tracker->AddArgsTo(*id)
1809 .AddArg(cpu_id_, Variadic::UnsignedInteger(cpu))
1810 .AddArg(len_arg_id_, Variadic::UnsignedInteger(evt.len()));
1811 }
1812
ParseInetSockSetState(int64_t timestamp,uint32_t pid,protozero::ConstBytes blob)1813 void FtraceParser::ParseInetSockSetState(int64_t timestamp,
1814 uint32_t pid,
1815 protozero::ConstBytes blob) {
1816 protos::pbzero::InetSockSetStateFtraceEvent::Decoder evt(blob.data,
1817 blob.size);
1818
1819 // Skip non TCP protocol.
1820 if (evt.protocol() != kIpprotoTcp) {
1821 PERFETTO_ELOG("skip non tcp protocol");
1822 return;
1823 }
1824
1825 // Skip non IP protocol.
1826 if (evt.family() != kAfNet && evt.family() != kAfNet6) {
1827 PERFETTO_ELOG("skip non IP protocol");
1828 return;
1829 }
1830
1831 // Skip invalid TCP state.
1832 if (evt.newstate() >= TCP_MAX_STATES || evt.oldstate() >= TCP_MAX_STATES) {
1833 PERFETTO_ELOG("skip invalid tcp state");
1834 return;
1835 }
1836
1837 auto got = skaddr_to_stream_.find(evt.skaddr());
1838 if (got == skaddr_to_stream_.end()) {
1839 skaddr_to_stream_[evt.skaddr()] = ++num_of_tcp_stream_;
1840 }
1841 uint32_t stream = skaddr_to_stream_[evt.skaddr()];
1842 char stream_str[64];
1843 sprintf(stream_str, "TCP stream#%" PRIu32 "", stream);
1844 StringId stream_id = context_->storage->InternString(stream_str);
1845
1846 StringId slice_name_id;
1847 if (evt.newstate() == TCP_SYN_SENT) {
1848 base::StackString<32> str("%s(pid=%" PRIu32 ")",
1849 kTcpStateNames[evt.newstate()], pid);
1850 slice_name_id = context_->storage->InternString(str.string_view());
1851 } else if (evt.newstate() == TCP_ESTABLISHED) {
1852 base::StackString<64> str("%s(sport=%" PRIu32 ",dport=%" PRIu32 ")",
1853 kTcpStateNames[evt.newstate()], evt.sport(),
1854 evt.dport());
1855 slice_name_id = context_->storage->InternString(str.string_view());
1856 } else {
1857 base::StringView slice_name = kTcpStateNames[evt.newstate()];
1858 slice_name_id = context_->storage->InternString(slice_name);
1859 }
1860
1861 // Push to async task set tracker.
1862 auto async_track =
1863 context_->async_track_set_tracker->InternGlobalTrackSet(stream_id);
1864 TrackId end_id = context_->async_track_set_tracker->End(
1865 async_track, static_cast<int64_t>(evt.skaddr()));
1866 context_->slice_tracker->End(timestamp, end_id);
1867 TrackId start_id = context_->async_track_set_tracker->Begin(
1868 async_track, static_cast<int64_t>(evt.skaddr()));
1869 context_->slice_tracker->Begin(timestamp, start_id, tcp_state_id_,
1870 slice_name_id);
1871 }
1872
ParseTcpRetransmitSkb(int64_t timestamp,protozero::ConstBytes blob)1873 void FtraceParser::ParseTcpRetransmitSkb(int64_t timestamp,
1874 protozero::ConstBytes blob) {
1875 protos::pbzero::TcpRetransmitSkbFtraceEvent::Decoder evt(blob.data,
1876 blob.size);
1877
1878 // Push event as instant to async task set tracker.
1879 auto async_track = context_->async_track_set_tracker->InternGlobalTrackSet(
1880 tcp_retransmited_name_id_);
1881 base::StackString<64> str("sport=%" PRIu32 ",dport=%" PRIu32 "", evt.sport(),
1882 evt.dport());
1883 StringId slice_name_id = context_->storage->InternString(str.string_view());
1884 TrackId track_id =
1885 context_->async_track_set_tracker->Scoped(async_track, timestamp, 0);
1886 context_->slice_tracker->Scoped(timestamp, track_id, tcp_event_id_,
1887 slice_name_id, 0);
1888 }
1889
ParseNapiGroReceiveEntry(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1890 void FtraceParser::ParseNapiGroReceiveEntry(uint32_t cpu,
1891 int64_t timestamp,
1892 protozero::ConstBytes blob) {
1893 protos::pbzero::NapiGroReceiveEntryFtraceEvent::Decoder evt(blob.data,
1894 blob.size);
1895 base::StackString<255> track_name("Napi Gro Cpu %d", cpu);
1896 StringId track_name_id =
1897 context_->storage->InternString(track_name.string_view());
1898 base::StringView net_device = evt.name();
1899 StringId slice_name_id = context_->storage->InternString(net_device);
1900 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1901 auto len = evt.len();
1902 auto args_inserter = [this, len](ArgsTracker::BoundInserter* inserter) {
1903 inserter->AddArg(len_arg_id_, Variadic::Integer(len));
1904 };
1905 context_->slice_tracker->Begin(timestamp, track, napi_gro_id_, slice_name_id,
1906 args_inserter);
1907 }
1908
ParseNapiGroReceiveExit(uint32_t cpu,int64_t timestamp,protozero::ConstBytes blob)1909 void FtraceParser::ParseNapiGroReceiveExit(uint32_t cpu,
1910 int64_t timestamp,
1911 protozero::ConstBytes blob) {
1912 protos::pbzero::NapiGroReceiveExitFtraceEvent::Decoder evt(blob.data,
1913 blob.size);
1914 base::StackString<255> track_name("Napi Gro Cpu %d", cpu);
1915 StringId track_name_id =
1916 context_->storage->InternString(track_name.string_view());
1917 TrackId track = context_->track_tracker->InternCpuTrack(track_name_id, cpu);
1918 auto ret = evt.ret();
1919 auto args_inserter = [this, ret](ArgsTracker::BoundInserter* inserter) {
1920 inserter->AddArg(ret_arg_id_, Variadic::Integer(ret));
1921 };
1922 context_->slice_tracker->End(timestamp, track, napi_gro_id_, {},
1923 args_inserter);
1924 }
1925
ParseCpuFrequencyLimits(int64_t timestamp,protozero::ConstBytes blob)1926 void FtraceParser::ParseCpuFrequencyLimits(int64_t timestamp,
1927 protozero::ConstBytes blob) {
1928 protos::pbzero::CpuFrequencyLimitsFtraceEvent::Decoder evt(blob.data,
1929 blob.size);
1930 base::StackString<255> max_counter_name("Cpu %" PRIu32 " Max Freq Limit",
1931 evt.cpu_id());
1932 base::StackString<255> min_counter_name("Cpu %" PRIu32 " Min Freq Limit",
1933 evt.cpu_id());
1934 // Push max freq to global counter.
1935 StringId max_name = context_->storage->InternString(max_counter_name.c_str());
1936 TrackId max_track =
1937 context_->track_tracker->InternGlobalCounterTrack(max_name);
1938 context_->event_tracker->PushCounter(
1939 timestamp, static_cast<double>(evt.max_freq()), max_track);
1940
1941 // Push min freq to global counter.
1942 StringId min_name = context_->storage->InternString(min_counter_name.c_str());
1943 TrackId min_track =
1944 context_->track_tracker->InternGlobalCounterTrack(min_name);
1945 context_->event_tracker->PushCounter(
1946 timestamp, static_cast<double>(evt.min_freq()), min_track);
1947 }
1948
ParseKfreeSkb(int64_t timestamp,protozero::ConstBytes blob)1949 void FtraceParser::ParseKfreeSkb(int64_t timestamp,
1950 protozero::ConstBytes blob) {
1951 protos::pbzero::KfreeSkbFtraceEvent::Decoder evt(blob.data, blob.size);
1952
1953 // Skip non IP & IPV6 protocol.
1954 if (evt.protocol() != kEthPIp && evt.protocol() != kEthPIp6) {
1955 return;
1956 }
1957 num_of_kfree_skb_ip_prot += 1;
1958
1959 TrackId track =
1960 context_->track_tracker->InternGlobalCounterTrack(kfree_skb_name_id_);
1961 base::Optional<CounterId> id = context_->event_tracker->PushCounter(
1962 timestamp, static_cast<double>(num_of_kfree_skb_ip_prot), track);
1963 if (!id) {
1964 return;
1965 }
1966 base::StackString<255> prot("%s", evt.protocol() == kEthPIp ? "IP" : "IPV6");
1967 StringId prot_id = context_->storage->InternString(prot.string_view());
1968 // Store protocol as args for metrics computation.
1969 context_->args_tracker->AddArgsTo(*id).AddArg(
1970 protocol_arg_id_, Variadic::String(prot_id));
1971 }
1972
ParseCrosEcSensorhubData(int64_t timestamp,protozero::ConstBytes blob)1973 void FtraceParser::ParseCrosEcSensorhubData(int64_t timestamp,
1974 protozero::ConstBytes blob) {
1975 protos::pbzero::CrosEcSensorhubDataFtraceEvent::Decoder evt(blob.data,
1976 blob.size);
1977
1978 // Push the global counter.
1979 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
1980 context_->storage->InternString(
1981 base::StringView("cros_ec.cros_ec_sensorhub_data." +
1982 std::to_string(evt.ec_sensor_num()))));
1983
1984 auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
1985 inserter->AddArg(cros_ec_arg_num_id_,
1986 Variadic::Integer(evt.ec_sensor_num()));
1987 inserter->AddArg(
1988 cros_ec_arg_ec_id_,
1989 Variadic::Integer(evt.fifo_timestamp() - evt.current_timestamp()));
1990 inserter->AddArg(cros_ec_arg_sample_ts_id_,
1991 Variadic::Integer(evt.current_timestamp()));
1992 };
1993
1994 context_->event_tracker->PushCounter(
1995 timestamp,
1996 static_cast<double>(evt.current_time() - evt.current_timestamp()), track,
1997 args_inserter);
1998 }
1999
ParseUfshcdClkGating(int64_t timestamp,protozero::ConstBytes blob)2000 void FtraceParser::ParseUfshcdClkGating(int64_t timestamp,
2001 protozero::ConstBytes blob) {
2002 protos::pbzero::UfshcdClkGatingFtraceEvent::Decoder evt(blob.data, blob.size);
2003 int32_t clk_state = 0;
2004
2005 switch (evt.state()) {
2006 case 1:
2007 // Change ON state to 3
2008 clk_state = 3;
2009 break;
2010 case 2:
2011 // Change REQ_OFF state to 1
2012 clk_state = 1;
2013 break;
2014 case 3:
2015 // Change REQ_ON state to 2
2016 clk_state = 2;
2017 break;
2018 }
2019 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
2020 ufs_clkgating_id_);
2021 context_->event_tracker->PushCounter(timestamp, static_cast<double>(clk_state),
2022 track);
2023 }
2024
ParseUfshcdCommand(int64_t timestamp,protozero::ConstBytes blob)2025 void FtraceParser::ParseUfshcdCommand(int64_t timestamp,
2026 protozero::ConstBytes blob) {
2027 protos::pbzero::UfshcdCommandFtraceEvent::Decoder evt(blob.data, blob.size);
2028 uint32_t num = evt.doorbell() > 0 ?
2029 static_cast<uint32_t>(PERFETTO_POPCOUNT(evt.doorbell())) :
2030 (evt.str_t() == 1 ? 0 : 1);
2031
2032 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
2033 ufs_command_count_id_);
2034 context_->event_tracker->PushCounter(timestamp, static_cast<double>(num),
2035 track);
2036 }
2037
ParseWakeSourceActivate(int64_t timestamp,protozero::ConstBytes blob)2038 void FtraceParser::ParseWakeSourceActivate(int64_t timestamp,
2039 protozero::ConstBytes blob) {
2040 protos::pbzero::WakeupSourceActivateFtraceEvent::Decoder evt(blob.data,
2041 blob.size);
2042 std::string event_name = evt.name().ToStdString();
2043
2044 uint32_t count = active_wakelock_to_count_[event_name];
2045
2046 active_wakelock_to_count_[event_name] += 1;
2047
2048 // There is already an active track with this name, don't create another.
2049 if (count > 0) {
2050 return;
2051 }
2052
2053 base::StackString<32> str("Wakelock(%s)", event_name.c_str());
2054 StringId stream_id = context_->storage->InternString(str.string_view());
2055
2056 auto async_track =
2057 context_->async_track_set_tracker->InternGlobalTrackSet(stream_id);
2058
2059 TrackId start_id = context_->async_track_set_tracker->Begin(async_track, 0);
2060
2061 context_->slice_tracker->Begin(timestamp, start_id, kNullStringId, stream_id);
2062 }
2063
ParseWakeSourceDeactivate(int64_t timestamp,protozero::ConstBytes blob)2064 void FtraceParser::ParseWakeSourceDeactivate(int64_t timestamp,
2065 protozero::ConstBytes blob) {
2066 protos::pbzero::WakeupSourceDeactivateFtraceEvent::Decoder evt(blob.data,
2067 blob.size);
2068
2069 std::string event_name = evt.name().ToStdString();
2070 uint32_t count = active_wakelock_to_count_[event_name];
2071 active_wakelock_to_count_[event_name] = count > 0 ? count - 1 : 0;
2072 if (count != 1) {
2073 return;
2074 }
2075
2076 base::StackString<32> str("Wakelock(%s)", event_name.c_str());
2077 StringId stream_id = context_->storage->InternString(str.string_view());
2078 auto async_track =
2079 context_->async_track_set_tracker->InternGlobalTrackSet(stream_id);
2080
2081 TrackId end_id = context_->async_track_set_tracker->End(async_track, 0);
2082 context_->slice_tracker->End(timestamp, end_id);
2083 }
2084
ParseSuspendResume(int64_t timestamp,protozero::ConstBytes blob)2085 void FtraceParser::ParseSuspendResume(int64_t timestamp,
2086 protozero::ConstBytes blob) {
2087 protos::pbzero::SuspendResumeFtraceEvent::Decoder evt(blob.data, blob.size);
2088
2089 auto async_track = context_->async_track_set_tracker->InternGlobalTrackSet(
2090 suspend_resume_name_id_);
2091
2092 base::StackString<64> str("%s(%" PRIu32 ")",
2093 evt.action().ToStdString().c_str(), evt.val());
2094 StringId slice_name_id = context_->storage->InternString(str.string_view());
2095
2096 if (evt.start()) {
2097 TrackId start_id = context_->async_track_set_tracker->Begin(
2098 async_track, static_cast<int64_t>(evt.val()));
2099 context_->slice_tracker->Begin(timestamp, start_id, suspend_resume_name_id_,
2100 slice_name_id);
2101 } else {
2102 TrackId end_id = context_->async_track_set_tracker->End(
2103 async_track, static_cast<int64_t>(evt.val()));
2104 context_->slice_tracker->End(timestamp, end_id);
2105 }
2106 }
2107
2108 } // namespace trace_processor
2109 } // namespace perfetto
2110