• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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