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/syscalls/syscall_tracker.h"
25 #include "src/trace_processor/importers/systrace/systrace_parser.h"
26 #include "src/trace_processor/storage/stats.h"
27 #include "src/trace_processor/storage/trace_storage.h"
28
29 #include "protos/perfetto/trace/ftrace/binder.pbzero.h"
30 #include "protos/perfetto/trace/ftrace/ftrace.pbzero.h"
31 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
32 #include "protos/perfetto/trace/ftrace/ftrace_stats.pbzero.h"
33 #include "protos/perfetto/trace/ftrace/generic.pbzero.h"
34 #include "protos/perfetto/trace/ftrace/ion.pbzero.h"
35 #include "protos/perfetto/trace/ftrace/kmem.pbzero.h"
36 #include "protos/perfetto/trace/ftrace/lowmemorykiller.pbzero.h"
37 #include "protos/perfetto/trace/ftrace/mm_event.pbzero.h"
38 #include "protos/perfetto/trace/ftrace/oom.pbzero.h"
39 #include "protos/perfetto/trace/ftrace/power.pbzero.h"
40 #include "protos/perfetto/trace/ftrace/raw_syscalls.pbzero.h"
41 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
42 #include "protos/perfetto/trace/ftrace/sde.pbzero.h"
43 #include "protos/perfetto/trace/ftrace/signal.pbzero.h"
44 #include "protos/perfetto/trace/ftrace/systrace.pbzero.h"
45 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
46
47 namespace perfetto {
48 namespace trace_processor {
49
50 namespace {
51
52 using protozero::ConstBytes;
53 using protozero::ProtoDecoder;
54
55 // kthreadd is the parent process for all kernel threads and always has
56 // pid == 2 on Linux and Android.
57 const uint32_t kKthreaddPid = 2;
58 const char kKthreaddName[] = "kthreadd";
59
60 } // namespace
61
FtraceParser(TraceProcessorContext * context)62 FtraceParser::FtraceParser(TraceProcessorContext* context)
63 : context_(context),
64 rss_stat_tracker_(context),
65 sched_wakeup_name_id_(context->storage->InternString("sched_wakeup")),
66 sched_waking_name_id_(context->storage->InternString("sched_waking")),
67 cpu_freq_name_id_(context->storage->InternString("cpufreq")),
68 gpu_freq_name_id_(context->storage->InternString("gpufreq")),
69 cpu_idle_name_id_(context->storage->InternString("cpuidle")),
70 ion_total_id_(context->storage->InternString("mem.ion")),
71 ion_change_id_(context->storage->InternString("mem.ion_change")),
72 ion_total_unknown_id_(context->storage->InternString("mem.ion.unknown")),
73 ion_change_unknown_id_(
74 context->storage->InternString("mem.ion_change.unknown")),
75 signal_generate_id_(context->storage->InternString("signal_generate")),
76 signal_deliver_id_(context->storage->InternString("signal_deliver")),
77 oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
78 lmk_id_(context->storage->InternString("mem.lmk")),
79 comm_name_id_(context->storage->InternString("comm")),
80 signal_name_id_(context_->storage->InternString("signal.sig")),
81 oom_kill_id_(context_->storage->InternString("mem.oom_kill")) {
82 // Build the lookup table for the strings inside ftrace events (e.g. the
83 // name of ftrace event fields and the names of their args).
84 for (size_t i = 0; i < GetDescriptorsSize(); i++) {
85 auto* descriptor = GetMessageDescriptorForId(i);
86 if (!descriptor->name) {
87 ftrace_message_strings_.emplace_back();
88 continue;
89 }
90
91 FtraceMessageStrings ftrace_strings;
92 ftrace_strings.message_name_id =
93 context->storage->InternString(descriptor->name);
94
95 for (size_t fid = 0; fid <= descriptor->max_field_id; fid++) {
96 const auto& field = descriptor->fields[fid];
97 if (!field.name)
98 continue;
99 ftrace_strings.field_name_ids[fid] =
100 context->storage->InternString(field.name);
101 }
102 ftrace_message_strings_.emplace_back(ftrace_strings);
103 }
104
105 mm_event_counter_names_ = {
106 {MmEventCounterNames(
107 context->storage->InternString("mem.mm.min_flt.count"),
108 context->storage->InternString("mem.mm.min_flt.max_lat"),
109 context->storage->InternString("mem.mm.min_flt.avg_lat")),
110 MmEventCounterNames(
111 context->storage->InternString("mem.mm.maj_flt.count"),
112 context->storage->InternString("mem.mm.maj_flt.max_lat"),
113 context->storage->InternString("mem.mm.maj_flt.avg_lat")),
114 MmEventCounterNames(
115 context->storage->InternString("mem.mm.read_io.count"),
116 context->storage->InternString("mem.mm.read_io.max_lat"),
117 context->storage->InternString("mem.mm.read_io.avg_lat")),
118 MmEventCounterNames(
119 context->storage->InternString("mem.mm.compaction.count"),
120 context->storage->InternString("mem.mm.compaction.max_lat"),
121 context->storage->InternString("mem.mm.compaction.avg_lat")),
122 MmEventCounterNames(
123 context->storage->InternString("mem.mm.reclaim.count"),
124 context->storage->InternString("mem.mm.reclaim.max_lat"),
125 context->storage->InternString("mem.mm.reclaim.avg_lat")),
126 MmEventCounterNames(
127 context->storage->InternString("mem.mm.swp_flt.count"),
128 context->storage->InternString("mem.mm.swp_flt.max_lat"),
129 context->storage->InternString("mem.mm.swp_flt.avg_lat")),
130 MmEventCounterNames(
131 context->storage->InternString("mem.mm.kern_alloc.count"),
132 context->storage->InternString("mem.mm.kern_alloc.max_lat"),
133 context->storage->InternString("mem.mm.kern_alloc.avg_lat"))}};
134 }
135
ParseFtraceStats(ConstBytes blob)136 void FtraceParser::ParseFtraceStats(ConstBytes blob) {
137 protos::pbzero::FtraceStats::Decoder evt(blob.data, blob.size);
138 size_t phase =
139 evt.phase() == protos::pbzero::FtraceStats_Phase_END_OF_TRACE ? 1 : 0;
140
141 // This code relies on the fact that each ftrace_cpu_XXX_end event is
142 // just after the corresponding ftrace_cpu_XXX_begin event.
143 static_assert(
144 stats::ftrace_cpu_read_events_end - stats::ftrace_cpu_read_events_begin ==
145 1 &&
146 stats::ftrace_cpu_entries_end - stats::ftrace_cpu_entries_begin == 1,
147 "ftrace_cpu_XXX stats definition are messed up");
148
149 auto* storage = context_->storage.get();
150 for (auto it = evt.cpu_stats(); it; ++it) {
151 protos::pbzero::FtraceCpuStats::Decoder cpu_stats(*it);
152 int cpu = static_cast<int>(cpu_stats.cpu());
153 storage->SetIndexedStats(stats::ftrace_cpu_entries_begin + phase, cpu,
154 static_cast<int64_t>(cpu_stats.entries()));
155 storage->SetIndexedStats(stats::ftrace_cpu_overrun_begin + phase, cpu,
156 static_cast<int64_t>(cpu_stats.overrun()));
157 storage->SetIndexedStats(stats::ftrace_cpu_commit_overrun_begin + phase,
158 cpu,
159 static_cast<int64_t>(cpu_stats.commit_overrun()));
160 storage->SetIndexedStats(stats::ftrace_cpu_bytes_read_begin + phase, cpu,
161 static_cast<int64_t>(cpu_stats.bytes_read()));
162
163 // oldest_event_ts can often be set to very high values, possibly because
164 // of wrapping. Ensure that we are not overflowing to avoid ubsan
165 // complaining.
166 double oldest_event_ts = cpu_stats.oldest_event_ts() * 1e9;
167 if (oldest_event_ts >= std::numeric_limits<int64_t>::max()) {
168 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
169 cpu, std::numeric_limits<int64_t>::max());
170 } else {
171 storage->SetIndexedStats(stats::ftrace_cpu_oldest_event_ts_begin + phase,
172 cpu, static_cast<int64_t>(oldest_event_ts));
173 }
174
175 storage->SetIndexedStats(stats::ftrace_cpu_now_ts_begin + phase, cpu,
176 static_cast<int64_t>(cpu_stats.now_ts() * 1e9));
177 storage->SetIndexedStats(stats::ftrace_cpu_dropped_events_begin + phase,
178 cpu,
179 static_cast<int64_t>(cpu_stats.dropped_events()));
180 storage->SetIndexedStats(stats::ftrace_cpu_read_events_begin + phase, cpu,
181 static_cast<int64_t>(cpu_stats.read_events()));
182 }
183 }
184
185 PERFETTO_ALWAYS_INLINE
ParseFtraceEvent(uint32_t cpu,const TimestampedTracePiece & ttp)186 util::Status FtraceParser::ParseFtraceEvent(uint32_t cpu,
187 const TimestampedTracePiece& ttp) {
188 using protos::pbzero::FtraceEvent;
189 int64_t ts = ttp.timestamp;
190 SchedEventTracker* sched_tracker = SchedEventTracker::GetOrCreate(context_);
191
192 // Handle the (optional) alternative encoding format for sched_switch.
193 if (ttp.type == TimestampedTracePiece::Type::kInlineSchedSwitch) {
194 const auto& event = ttp.sched_switch;
195 sched_tracker->PushSchedSwitchCompact(cpu, ts, event.prev_state,
196 static_cast<uint32_t>(event.next_pid),
197 event.next_prio, event.next_comm);
198 return util::OkStatus();
199 }
200
201 // Handle the (optional) alternative encoding format for sched_waking.
202 if (ttp.type == TimestampedTracePiece::Type::kInlineSchedWaking) {
203 const auto& event = ttp.sched_waking;
204 sched_tracker->PushSchedWakingCompact(
205 cpu, ts, static_cast<uint32_t>(event.pid), event.target_cpu, event.prio,
206 event.comm);
207 return util::OkStatus();
208 }
209
210 PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kFtraceEvent);
211 const TraceBlobView& event = ttp.ftrace_event;
212 ProtoDecoder decoder(event.data(), event.length());
213 uint64_t raw_pid = 0;
214 if (auto pid_field = decoder.FindField(FtraceEvent::kPidFieldNumber)) {
215 raw_pid = pid_field.as_uint64();
216 } else {
217 return util::ErrStatus("Pid field not found in ftrace packet");
218 }
219 uint32_t pid = static_cast<uint32_t>(raw_pid);
220
221 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
222 bool is_metadata_field = fld.id() == FtraceEvent::kPidFieldNumber ||
223 fld.id() == FtraceEvent::kTimestampFieldNumber;
224 if (is_metadata_field)
225 continue;
226
227 ConstBytes data = fld.as_bytes();
228 if (fld.id() == FtraceEvent::kGenericFieldNumber) {
229 ParseGenericFtrace(ts, cpu, pid, data);
230 } else if (fld.id() != FtraceEvent::kSchedSwitchFieldNumber) {
231 // sched_switch parsing populates the raw table by itself
232 ParseTypedFtraceToRaw(fld.id(), ts, cpu, pid, data);
233 }
234
235 switch (fld.id()) {
236 case FtraceEvent::kSchedSwitchFieldNumber: {
237 ParseSchedSwitch(cpu, ts, data);
238 break;
239 }
240 case FtraceEvent::kSchedWakeupFieldNumber: {
241 ParseSchedWakeup(ts, data);
242 break;
243 }
244 case FtraceEvent::kSchedWakingFieldNumber: {
245 ParseSchedWaking(ts, data);
246 break;
247 }
248 case FtraceEvent::kSchedProcessFreeFieldNumber: {
249 ParseSchedProcessFree(ts, data);
250 break;
251 }
252 case FtraceEvent::kCpuFrequencyFieldNumber: {
253 ParseCpuFreq(ts, data);
254 break;
255 }
256 case FtraceEvent::kGpuFrequencyFieldNumber: {
257 ParseGpuFreq(ts, data);
258 break;
259 }
260 case FtraceEvent::kCpuIdleFieldNumber: {
261 ParseCpuIdle(ts, data);
262 break;
263 }
264 case FtraceEvent::kPrintFieldNumber: {
265 ParsePrint(ts, pid, data);
266 break;
267 }
268 case FtraceEvent::kZeroFieldNumber: {
269 ParseZero(ts, pid, data);
270 break;
271 }
272 case FtraceEvent::kRssStatFieldNumber: {
273 rss_stat_tracker_.ParseRssStat(ts, pid, data);
274 break;
275 }
276 case FtraceEvent::kIonHeapGrowFieldNumber: {
277 ParseIonHeapGrowOrShrink(ts, pid, data, true);
278 break;
279 }
280 case FtraceEvent::kIonHeapShrinkFieldNumber: {
281 ParseIonHeapGrowOrShrink(ts, pid, data, false);
282 break;
283 }
284 case FtraceEvent::kIonStatFieldNumber: {
285 ParseIonStat(ts, pid, data);
286 break;
287 }
288 case FtraceEvent::kSignalGenerateFieldNumber: {
289 ParseSignalGenerate(ts, data);
290 break;
291 }
292 case FtraceEvent::kSignalDeliverFieldNumber: {
293 ParseSignalDeliver(ts, pid, data);
294 break;
295 }
296 case FtraceEvent::kLowmemoryKillFieldNumber: {
297 ParseLowmemoryKill(ts, data);
298 break;
299 }
300 case FtraceEvent::kOomScoreAdjUpdateFieldNumber: {
301 ParseOOMScoreAdjUpdate(ts, data);
302 break;
303 }
304 case FtraceEvent::kMarkVictimFieldNumber: {
305 ParseOOMKill(ts, data);
306 break;
307 }
308 case FtraceEvent::kMmEventRecordFieldNumber: {
309 ParseMmEventRecord(ts, pid, data);
310 break;
311 }
312 case FtraceEvent::kSysEnterFieldNumber: {
313 ParseSysEvent(ts, pid, true, data);
314 break;
315 }
316 case FtraceEvent::kSysExitFieldNumber: {
317 ParseSysEvent(ts, pid, false, data);
318 break;
319 }
320 case FtraceEvent::kTaskNewtaskFieldNumber: {
321 ParseTaskNewTask(ts, pid, data);
322 break;
323 }
324 case FtraceEvent::kTaskRenameFieldNumber: {
325 ParseTaskRename(data);
326 break;
327 }
328 case FtraceEvent::kBinderTransactionFieldNumber: {
329 ParseBinderTransaction(ts, pid, data);
330 break;
331 }
332 case FtraceEvent::kBinderTransactionReceivedFieldNumber: {
333 ParseBinderTransactionReceived(ts, pid, data);
334 break;
335 }
336 case FtraceEvent::kBinderTransactionAllocBufFieldNumber: {
337 ParseBinderTransactionAllocBuf(ts, pid, data);
338 break;
339 }
340 case FtraceEvent::kBinderLockFieldNumber: {
341 ParseBinderLock(ts, pid, data);
342 break;
343 }
344 case FtraceEvent::kBinderUnlockFieldNumber: {
345 ParseBinderUnlock(ts, pid, data);
346 break;
347 }
348 case FtraceEvent::kBinderLockedFieldNumber: {
349 ParseBinderLocked(ts, pid, data);
350 break;
351 }
352 case FtraceEvent::kSdeTracingMarkWriteFieldNumber: {
353 ParseSdeTracingMarkWrite(ts, pid, data);
354 break;
355 }
356 default:
357 break;
358 }
359 }
360
361 PERFETTO_DCHECK(!decoder.bytes_left());
362 return util::OkStatus();
363 }
364
ParseGenericFtrace(int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)365 void FtraceParser::ParseGenericFtrace(int64_t ts,
366 uint32_t cpu,
367 uint32_t tid,
368 ConstBytes blob) {
369 protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
370 StringId event_id = context_->storage->InternString(evt.event_name());
371 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
372 RawId id = context_->storage->mutable_raw_table()
373 ->Insert({ts, event_id, cpu, utid})
374 .id;
375 auto inserter = context_->args_tracker->AddArgsTo(id);
376
377 for (auto it = evt.field(); it; ++it) {
378 protos::pbzero::GenericFtraceEvent::Field::Decoder fld(*it);
379 auto field_name_id = context_->storage->InternString(fld.name());
380 if (fld.has_int_value()) {
381 inserter.AddArg(field_name_id, Variadic::Integer(fld.int_value()));
382 } else if (fld.has_uint_value()) {
383 inserter.AddArg(
384 field_name_id,
385 Variadic::Integer(static_cast<int64_t>(fld.uint_value())));
386 } else if (fld.has_str_value()) {
387 StringId str_value = context_->storage->InternString(fld.str_value());
388 inserter.AddArg(field_name_id, Variadic::String(str_value));
389 }
390 }
391 }
392
ParseTypedFtraceToRaw(uint32_t ftrace_id,int64_t ts,uint32_t cpu,uint32_t tid,ConstBytes blob)393 void FtraceParser::ParseTypedFtraceToRaw(uint32_t ftrace_id,
394 int64_t ts,
395 uint32_t cpu,
396 uint32_t tid,
397 ConstBytes blob) {
398 if (PERFETTO_UNLIKELY(!context_->config.ingest_ftrace_in_raw_table))
399 return;
400
401 ProtoDecoder decoder(blob.data, blob.size);
402 if (ftrace_id >= GetDescriptorsSize()) {
403 PERFETTO_DLOG("Event with id: %d does not exist and cannot be parsed.",
404 ftrace_id);
405 return;
406 }
407
408 MessageDescriptor* m = GetMessageDescriptorForId(ftrace_id);
409 const auto& message_strings = ftrace_message_strings_[ftrace_id];
410 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
411 RawId id = context_->storage->mutable_raw_table()
412 ->Insert({ts, message_strings.message_name_id, cpu, utid})
413 .id;
414 auto inserter = context_->args_tracker->AddArgsTo(id);
415
416 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
417 if (PERFETTO_UNLIKELY(fld.id() >= kMaxFtraceEventFields)) {
418 PERFETTO_DLOG(
419 "Skipping ftrace arg - proto field id is too large (%" PRIu16 ")",
420 fld.id());
421 continue;
422 }
423 ProtoSchemaType type = m->fields[fld.id()].type;
424 StringId name_id = message_strings.field_name_ids[fld.id()];
425 switch (type) {
426 case ProtoSchemaType::kInt32:
427 case ProtoSchemaType::kInt64:
428 case ProtoSchemaType::kSfixed32:
429 case ProtoSchemaType::kSfixed64:
430 case ProtoSchemaType::kSint32:
431 case ProtoSchemaType::kSint64:
432 case ProtoSchemaType::kBool:
433 case ProtoSchemaType::kEnum: {
434 inserter.AddArg(name_id, Variadic::Integer(fld.as_int64()));
435 break;
436 }
437 case ProtoSchemaType::kUint32:
438 case ProtoSchemaType::kUint64:
439 case ProtoSchemaType::kFixed32:
440 case ProtoSchemaType::kFixed64: {
441 // Note that SQLite functions will still treat unsigned values
442 // as a signed 64 bit integers (but the translation back to ftrace
443 // refers to this storage directly).
444 inserter.AddArg(name_id, Variadic::UnsignedInteger(fld.as_uint64()));
445 break;
446 }
447 case ProtoSchemaType::kString:
448 case ProtoSchemaType::kBytes: {
449 StringId value = context_->storage->InternString(fld.as_string());
450 inserter.AddArg(name_id, Variadic::String(value));
451 break;
452 }
453 case ProtoSchemaType::kDouble: {
454 inserter.AddArg(name_id, Variadic::Real(fld.as_double()));
455 break;
456 }
457 case ProtoSchemaType::kFloat: {
458 inserter.AddArg(name_id,
459 Variadic::Real(static_cast<double>(fld.as_float())));
460 break;
461 }
462 case ProtoSchemaType::kUnknown:
463 case ProtoSchemaType::kGroup:
464 case ProtoSchemaType::kMessage:
465 PERFETTO_DLOG("Could not store %s as a field in args table.",
466 ProtoSchemaToString(type));
467 break;
468 }
469 }
470 }
471
472 PERFETTO_ALWAYS_INLINE
ParseSchedSwitch(uint32_t cpu,int64_t ts,ConstBytes blob)473 void FtraceParser::ParseSchedSwitch(uint32_t cpu, int64_t ts, ConstBytes blob) {
474 protos::pbzero::SchedSwitchFtraceEvent::Decoder ss(blob.data, blob.size);
475 uint32_t prev_pid = static_cast<uint32_t>(ss.prev_pid());
476 uint32_t next_pid = static_cast<uint32_t>(ss.next_pid());
477 SchedEventTracker::GetOrCreate(context_)->PushSchedSwitch(
478 cpu, ts, prev_pid, ss.prev_comm(), ss.prev_prio(), ss.prev_state(),
479 next_pid, ss.next_comm(), ss.next_prio());
480 }
481
ParseSchedWakeup(int64_t ts,ConstBytes blob)482 void FtraceParser::ParseSchedWakeup(int64_t ts, ConstBytes blob) {
483 protos::pbzero::SchedWakeupFtraceEvent::Decoder sw(blob.data, blob.size);
484 uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
485 StringId name_id = context_->storage->InternString(sw.comm());
486 auto utid = context_->process_tracker->UpdateThreadName(wakee_pid, name_id);
487 context_->event_tracker->PushInstant(ts, sched_wakeup_name_id_, utid,
488 RefType::kRefUtid);
489 }
490
ParseSchedWaking(int64_t ts,ConstBytes blob)491 void FtraceParser::ParseSchedWaking(int64_t ts, ConstBytes blob) {
492 protos::pbzero::SchedWakingFtraceEvent::Decoder sw(blob.data, blob.size);
493 uint32_t wakee_pid = static_cast<uint32_t>(sw.pid());
494 StringId name_id = context_->storage->InternString(sw.comm());
495 auto utid = context_->process_tracker->UpdateThreadName(wakee_pid, name_id);
496 context_->event_tracker->PushInstant(ts, sched_waking_name_id_, utid,
497 RefType::kRefUtid);
498 }
499
ParseSchedProcessFree(int64_t ts,ConstBytes blob)500 void FtraceParser::ParseSchedProcessFree(int64_t ts, ConstBytes blob) {
501 protos::pbzero::SchedProcessFreeFtraceEvent::Decoder ex(blob.data, blob.size);
502 uint32_t pid = static_cast<uint32_t>(ex.pid());
503 context_->process_tracker->EndThread(ts, pid);
504 }
505
ParseCpuFreq(int64_t ts,ConstBytes blob)506 void FtraceParser::ParseCpuFreq(int64_t ts, ConstBytes blob) {
507 protos::pbzero::CpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
508 uint32_t cpu = freq.cpu_id();
509 uint32_t new_freq = freq.state();
510 TrackId track =
511 context_->track_tracker->InternCpuCounterTrack(cpu_freq_name_id_, cpu);
512 context_->event_tracker->PushCounter(ts, new_freq, track);
513 }
514
ParseGpuFreq(int64_t ts,ConstBytes blob)515 void FtraceParser::ParseGpuFreq(int64_t ts, ConstBytes blob) {
516 protos::pbzero::GpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
517 uint32_t gpu = freq.gpu_id();
518 uint32_t new_freq = freq.state();
519 TrackId track =
520 context_->track_tracker->InternGpuCounterTrack(gpu_freq_name_id_, gpu);
521 context_->event_tracker->PushCounter(ts, new_freq, track);
522 }
523
ParseCpuIdle(int64_t ts,ConstBytes blob)524 void FtraceParser::ParseCpuIdle(int64_t ts, ConstBytes blob) {
525 protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob.data, blob.size);
526 uint32_t cpu = idle.cpu_id();
527 uint32_t new_state = idle.state();
528 TrackId track =
529 context_->track_tracker->InternCpuCounterTrack(cpu_idle_name_id_, cpu);
530 context_->event_tracker->PushCounter(ts, new_state, track);
531 }
532
ParsePrint(int64_t ts,uint32_t pid,ConstBytes blob)533 void FtraceParser::ParsePrint(int64_t ts, uint32_t pid, ConstBytes blob) {
534 protos::pbzero::PrintFtraceEvent::Decoder evt(blob.data, blob.size);
535 SystraceParser::GetOrCreate(context_)->ParsePrintEvent(ts, pid, evt.buf());
536 }
537
ParseZero(int64_t ts,uint32_t pid,ConstBytes blob)538 void FtraceParser::ParseZero(int64_t ts, uint32_t pid, ConstBytes blob) {
539 protos::pbzero::ZeroFtraceEvent::Decoder evt(blob.data, blob.size);
540 uint32_t tgid = static_cast<uint32_t>(evt.pid());
541 SystraceParser::GetOrCreate(context_)->ParseZeroEvent(
542 ts, pid, evt.flag(), evt.name(), tgid, evt.value());
543 }
544
ParseSdeTracingMarkWrite(int64_t ts,uint32_t pid,ConstBytes blob)545 void FtraceParser::ParseSdeTracingMarkWrite(int64_t ts,
546 uint32_t pid,
547 ConstBytes blob) {
548 protos::pbzero::SdeTracingMarkWriteFtraceEvent::Decoder evt(blob.data,
549 blob.size);
550 if (!evt.has_trace_type() && !evt.has_trace_begin()) {
551 context_->storage->IncrementStats(stats::systrace_parse_failure);
552 return;
553 }
554
555 uint32_t tgid = static_cast<uint32_t>(evt.pid());
556 SystraceParser::GetOrCreate(context_)->ParseSdeTracingMarkWrite(
557 ts, pid, static_cast<char>(evt.trace_type()), evt.trace_begin(),
558 evt.trace_name(), tgid, evt.value());
559 }
560
561 /** Parses ion heap events present in Pixel kernels. */
ParseIonHeapGrowOrShrink(int64_t ts,uint32_t pid,ConstBytes blob,bool grow)562 void FtraceParser::ParseIonHeapGrowOrShrink(int64_t ts,
563 uint32_t pid,
564 ConstBytes blob,
565 bool grow) {
566 protos::pbzero::IonHeapGrowFtraceEvent::Decoder ion(blob.data, blob.size);
567 int64_t change_bytes = static_cast<int64_t>(ion.len()) * (grow ? 1 : -1);
568 // The total_allocated ftrace event reports the value before the
569 // atomic_long_add / sub takes place.
570 int64_t total_bytes = ion.total_allocated() + change_bytes;
571 StringId global_name_id = ion_total_unknown_id_;
572 StringId change_name_id = ion_change_unknown_id_;
573
574 if (ion.has_heap_name()) {
575 char counter_name[255];
576 base::StringView heap_name = ion.heap_name();
577 snprintf(counter_name, sizeof(counter_name), "mem.ion.%.*s",
578 int(heap_name.size()), heap_name.data());
579 global_name_id = context_->storage->InternString(counter_name);
580 snprintf(counter_name, sizeof(counter_name), "mem.ion_change.%.*s",
581 int(heap_name.size()), heap_name.data());
582 change_name_id = context_->storage->InternString(counter_name);
583 }
584
585 // Push the global counter.
586 TrackId track =
587 context_->track_tracker->InternGlobalCounterTrack(global_name_id);
588 context_->event_tracker->PushCounter(ts, total_bytes, track);
589
590 // Push the change counter.
591 // TODO(b/121331269): these should really be instant events.
592 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
593 track =
594 context_->track_tracker->InternThreadCounterTrack(change_name_id, utid);
595 context_->event_tracker->PushCounter(ts, change_bytes, track);
596
597 // We are reusing the same function for ion_heap_grow and ion_heap_shrink.
598 // It is fine as the arguments are the same, but we need to be sure that the
599 // protobuf field id for both are the same.
600 static_assert(
601 static_cast<int>(
602 protos::pbzero::IonHeapGrowFtraceEvent::kTotalAllocatedFieldNumber) ==
603 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
604 kTotalAllocatedFieldNumber) &&
605 static_cast<int>(
606 protos::pbzero::IonHeapGrowFtraceEvent::kLenFieldNumber) ==
607 static_cast<int>(
608 protos::pbzero::IonHeapShrinkFtraceEvent::kLenFieldNumber) &&
609 static_cast<int>(
610 protos::pbzero::IonHeapGrowFtraceEvent::kHeapNameFieldNumber) ==
611 static_cast<int>(protos::pbzero::IonHeapShrinkFtraceEvent::
612 kHeapNameFieldNumber),
613 "ION field mismatch");
614 }
615
616 /** Parses ion heap events (introduced in 4.19 kernels). */
ParseIonStat(int64_t ts,uint32_t pid,protozero::ConstBytes data)617 void FtraceParser::ParseIonStat(int64_t ts,
618 uint32_t pid,
619 protozero::ConstBytes data) {
620 protos::pbzero::IonStatFtraceEvent::Decoder ion(data.data, data.size);
621 // Push the global counter.
622 TrackId track =
623 context_->track_tracker->InternGlobalCounterTrack(ion_total_id_);
624 context_->event_tracker->PushCounter(ts, ion.total_allocated(), track);
625
626 // Push the change counter.
627 // TODO(b/121331269): these should really be instant events.
628 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
629 track =
630 context_->track_tracker->InternThreadCounterTrack(ion_change_id_, utid);
631 context_->event_tracker->PushCounter(ts, ion.len(), track);
632 }
633
634 // This event has both the pid of the thread that sent the signal and the
635 // destination of the signal. Currently storing the pid of the destination.
ParseSignalGenerate(int64_t ts,ConstBytes blob)636 void FtraceParser::ParseSignalGenerate(int64_t ts, ConstBytes blob) {
637 protos::pbzero::SignalGenerateFtraceEvent::Decoder sig(blob.data, blob.size);
638
639 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
640 static_cast<uint32_t>(sig.pid()));
641 InstantId id = context_->event_tracker->PushInstant(ts, signal_generate_id_,
642 utid, RefType::kRefUtid);
643
644 context_->args_tracker->AddArgsTo(id).AddArg(signal_name_id_,
645 Variadic::Integer(sig.sig()));
646 }
647
ParseSignalDeliver(int64_t ts,uint32_t pid,ConstBytes blob)648 void FtraceParser::ParseSignalDeliver(int64_t ts,
649 uint32_t pid,
650 ConstBytes blob) {
651 protos::pbzero::SignalDeliverFtraceEvent::Decoder sig(blob.data, blob.size);
652 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
653 InstantId id = context_->event_tracker->PushInstant(ts, signal_deliver_id_,
654 utid, RefType::kRefUtid);
655
656 context_->args_tracker->AddArgsTo(id).AddArg(signal_name_id_,
657 Variadic::Integer(sig.sig()));
658 }
659
ParseLowmemoryKill(int64_t ts,ConstBytes blob)660 void FtraceParser::ParseLowmemoryKill(int64_t ts, ConstBytes blob) {
661 // TODO(taylori): Store the pagecache_size, pagecache_limit and free fields
662 // in an args table
663 protos::pbzero::LowmemoryKillFtraceEvent::Decoder lmk(blob.data, blob.size);
664
665 // Store the pid of the event that is lmk-ed.
666 auto pid = static_cast<uint32_t>(lmk.pid());
667 auto opt_utid = context_->process_tracker->GetThreadOrNull(pid);
668
669 // Don't add LMK events for threads we've never seen before. This works around
670 // the case where we get an LMK event after a thread has already been killed.
671 if (!opt_utid)
672 return;
673
674 InstantId id = context_->event_tracker->PushInstant(
675 ts, lmk_id_, opt_utid.value(), RefType::kRefUtid, true);
676
677 // Store the comm as an arg.
678 auto comm_id = context_->storage->InternString(
679 lmk.has_comm() ? lmk.comm() : base::StringView());
680 context_->args_tracker->AddArgsTo(id).AddArg(comm_name_id_,
681 Variadic::String(comm_id));
682 }
683
ParseOOMScoreAdjUpdate(int64_t ts,ConstBytes blob)684 void FtraceParser::ParseOOMScoreAdjUpdate(int64_t ts, ConstBytes blob) {
685 protos::pbzero::OomScoreAdjUpdateFtraceEvent::Decoder evt(blob.data,
686 blob.size);
687 // The int16_t static cast is because older version of the on-device tracer
688 // had a bug on negative varint encoding (b/120618641).
689 int16_t oom_adj = static_cast<int16_t>(evt.oom_score_adj());
690 uint32_t tid = static_cast<uint32_t>(evt.pid());
691 UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
692 context_->event_tracker->PushProcessCounterForThread(ts, oom_adj,
693 oom_score_adj_id_, utid);
694 }
695
ParseOOMKill(int64_t ts,ConstBytes blob)696 void FtraceParser::ParseOOMKill(int64_t ts, ConstBytes blob) {
697 protos::pbzero::MarkVictimFtraceEvent::Decoder evt(blob.data, blob.size);
698 UniqueTid utid = context_->process_tracker->GetOrCreateThread(
699 static_cast<uint32_t>(evt.pid()));
700 context_->event_tracker->PushInstant(ts, oom_kill_id_, utid,
701 RefType::kRefUtid, true);
702 }
703
ParseMmEventRecord(int64_t ts,uint32_t pid,ConstBytes blob)704 void FtraceParser::ParseMmEventRecord(int64_t ts,
705 uint32_t pid,
706 ConstBytes blob) {
707 protos::pbzero::MmEventRecordFtraceEvent::Decoder evt(blob.data, blob.size);
708 uint32_t type = evt.type();
709 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
710
711 if (type >= mm_event_counter_names_.size()) {
712 context_->storage->IncrementStats(stats::mm_unknown_type);
713 return;
714 }
715
716 const auto& counter_names = mm_event_counter_names_[type];
717 context_->event_tracker->PushProcessCounterForThread(
718 ts, evt.count(), counter_names.count, utid);
719 context_->event_tracker->PushProcessCounterForThread(
720 ts, evt.max_lat(), counter_names.max_lat, utid);
721 context_->event_tracker->PushProcessCounterForThread(
722 ts, evt.avg_lat(), counter_names.avg_lat, utid);
723 }
724
ParseSysEvent(int64_t ts,uint32_t pid,bool is_enter,ConstBytes blob)725 void FtraceParser::ParseSysEvent(int64_t ts,
726 uint32_t pid,
727 bool is_enter,
728 ConstBytes blob) {
729 protos::pbzero::SysEnterFtraceEvent::Decoder evt(blob.data, blob.size);
730 uint32_t syscall_num = static_cast<uint32_t>(evt.id());
731 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
732
733 SyscallTracker* syscall_tracker = SyscallTracker::GetOrCreate(context_);
734 if (is_enter) {
735 syscall_tracker->Enter(ts, utid, syscall_num);
736 } else {
737 syscall_tracker->Exit(ts, utid, syscall_num);
738 }
739
740 // We are reusing the same function for sys_enter and sys_exit.
741 // It is fine as the arguments are the same, but we need to be sure that the
742 // protobuf field id for both are the same.
743 static_assert(
744 static_cast<int>(protos::pbzero::SysEnterFtraceEvent::kIdFieldNumber) ==
745 static_cast<int>(protos::pbzero::SysExitFtraceEvent::kIdFieldNumber),
746 "field mismatch");
747 }
748
ParseTaskNewTask(int64_t ts,uint32_t source_tid,ConstBytes blob)749 void FtraceParser::ParseTaskNewTask(int64_t ts,
750 uint32_t source_tid,
751 ConstBytes blob) {
752 protos::pbzero::TaskNewtaskFtraceEvent::Decoder evt(blob.data, blob.size);
753 uint32_t clone_flags = static_cast<uint32_t>(evt.clone_flags());
754 uint32_t new_tid = static_cast<uint32_t>(evt.pid());
755 StringId new_comm = context_->storage->InternString(evt.comm());
756 auto* proc_tracker = context_->process_tracker.get();
757
758 // task_newtask is raised both in the case of a new process creation (fork()
759 // family) and thread creation (clone(CLONE_THREAD, ...)).
760 static const uint32_t kCloneThread = 0x00010000; // From kernel's sched.h.
761
762 // If the process is a fork, start a new process except if the source tid is
763 // kthreadd in which case just make it a new thread associated with kthreadd.
764 if ((clone_flags & kCloneThread) == 0 && source_tid != kKthreaddPid) {
765 // This is a plain-old fork() or equivalent.
766 proc_tracker->StartNewProcess(ts, source_tid, new_tid, new_comm);
767 return;
768 }
769
770 if (source_tid == kKthreaddPid) {
771 context_->process_tracker->SetProcessMetadata(kKthreaddPid, base::nullopt,
772 kKthreaddName);
773 }
774
775 // This is a pthread_create or similar. Bind the two threads together, so
776 // they get resolved to the same process.
777 auto source_utid = proc_tracker->GetOrCreateThread(source_tid);
778 auto new_utid = proc_tracker->StartNewThread(ts, new_tid, new_comm);
779 proc_tracker->AssociateThreads(source_utid, new_utid);
780 }
781
ParseTaskRename(ConstBytes blob)782 void FtraceParser::ParseTaskRename(ConstBytes blob) {
783 protos::pbzero::TaskRenameFtraceEvent::Decoder evt(blob.data, blob.size);
784 uint32_t tid = static_cast<uint32_t>(evt.pid());
785 StringId comm = context_->storage->InternString(evt.newcomm());
786 context_->process_tracker->UpdateThreadName(tid, comm);
787 context_->process_tracker->UpdateProcessNameFromThreadName(tid, comm);
788 }
789
ParseBinderTransaction(int64_t timestamp,uint32_t pid,ConstBytes blob)790 void FtraceParser::ParseBinderTransaction(int64_t timestamp,
791 uint32_t pid,
792 ConstBytes blob) {
793 protos::pbzero::BinderTransactionFtraceEvent::Decoder evt(blob.data,
794 blob.size);
795 int32_t dest_node = static_cast<int32_t>(evt.target_node());
796 int32_t dest_tgid = static_cast<int32_t>(evt.to_proc());
797 int32_t dest_tid = static_cast<int32_t>(evt.to_thread());
798 int32_t transaction_id = static_cast<int32_t>(evt.debug_id());
799 bool is_reply = static_cast<int32_t>(evt.reply()) == 1;
800 uint32_t flags = static_cast<uint32_t>(evt.flags());
801 auto code_str = base::IntToHexString(evt.code()) + " Java Layer Dependent";
802 StringId code = context_->storage->InternString(base::StringView(code_str));
803 BinderTracker::GetOrCreate(context_)->Transaction(
804 timestamp, pid, transaction_id, dest_node, dest_tgid, dest_tid, is_reply,
805 flags, code);
806 }
807
ParseBinderTransactionReceived(int64_t timestamp,uint32_t pid,ConstBytes blob)808 void FtraceParser::ParseBinderTransactionReceived(int64_t timestamp,
809 uint32_t pid,
810 ConstBytes blob) {
811 protos::pbzero::BinderTransactionReceivedFtraceEvent::Decoder evt(blob.data,
812 blob.size);
813 int32_t transaction_id = static_cast<int32_t>(evt.debug_id());
814 BinderTracker::GetOrCreate(context_)->TransactionReceived(timestamp, pid,
815 transaction_id);
816 }
817
ParseBinderTransactionAllocBuf(int64_t timestamp,uint32_t pid,ConstBytes blob)818 void FtraceParser::ParseBinderTransactionAllocBuf(int64_t timestamp,
819 uint32_t pid,
820 ConstBytes blob) {
821 protos::pbzero::BinderTransactionAllocBufFtraceEvent::Decoder evt(blob.data,
822 blob.size);
823 uint64_t data_size = static_cast<uint64_t>(evt.data_size());
824 uint64_t offsets_size = static_cast<uint64_t>(evt.offsets_size());
825
826 BinderTracker::GetOrCreate(context_)->TransactionAllocBuf(
827 timestamp, pid, data_size, offsets_size);
828 }
829
ParseBinderLocked(int64_t timestamp,uint32_t pid,ConstBytes blob)830 void FtraceParser::ParseBinderLocked(int64_t timestamp,
831 uint32_t pid,
832 ConstBytes blob) {
833 protos::pbzero::BinderLockedFtraceEvent::Decoder evt(blob.data, blob.size);
834 BinderTracker::GetOrCreate(context_)->Locked(timestamp, pid);
835 }
836
ParseBinderLock(int64_t timestamp,uint32_t pid,ConstBytes blob)837 void FtraceParser::ParseBinderLock(int64_t timestamp,
838 uint32_t pid,
839 ConstBytes blob) {
840 protos::pbzero::BinderLockFtraceEvent::Decoder evt(blob.data, blob.size);
841 BinderTracker::GetOrCreate(context_)->Lock(timestamp, pid);
842 }
843
ParseBinderUnlock(int64_t timestamp,uint32_t pid,ConstBytes blob)844 void FtraceParser::ParseBinderUnlock(int64_t timestamp,
845 uint32_t pid,
846 ConstBytes blob) {
847 protos::pbzero::BinderUnlockFtraceEvent::Decoder evt(blob.data, blob.size);
848 BinderTracker::GetOrCreate(context_)->Unlock(timestamp, pid);
849 }
850
851 } // namespace trace_processor
852 } // namespace perfetto
853