• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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/prelude/functions/to_ftrace.h"
18 
19 #include "perfetto/base/compiler.h"
20 #include "perfetto/base/status.h"
21 #include "perfetto/ext/base/string_utils.h"
22 #include "perfetto/trace_processor/basic_types.h"
23 #include "src/trace_processor/importers/common/system_info_tracker.h"
24 #include "src/trace_processor/importers/ftrace/ftrace_descriptors.h"
25 #include "src/trace_processor/sqlite/sqlite_utils.h"
26 #include "src/trace_processor/types/gfp_flags.h"
27 #include "src/trace_processor/types/softirq_action.h"
28 #include "src/trace_processor/types/task_state.h"
29 #include "src/trace_processor/types/variadic.h"
30 
31 #include "protos/perfetto/trace/ftrace/binder.pbzero.h"
32 #include "protos/perfetto/trace/ftrace/cgroup.pbzero.h"
33 #include "protos/perfetto/trace/ftrace/clk.pbzero.h"
34 #include "protos/perfetto/trace/ftrace/dpu.pbzero.h"
35 #include "protos/perfetto/trace/ftrace/filemap.pbzero.h"
36 #include "protos/perfetto/trace/ftrace/ftrace.pbzero.h"
37 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
38 #include "protos/perfetto/trace/ftrace/g2d.pbzero.h"
39 #include "protos/perfetto/trace/ftrace/irq.pbzero.h"
40 #include "protos/perfetto/trace/ftrace/mdss.pbzero.h"
41 #include "protos/perfetto/trace/ftrace/power.pbzero.h"
42 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
43 #include "protos/perfetto/trace/ftrace/workqueue.pbzero.h"
44 
45 namespace perfetto {
46 namespace trace_processor {
47 
48 namespace {
49 
50 struct FtraceTime {
FtraceTimeperfetto::trace_processor::__anon89cfd0d50111::FtraceTime51   FtraceTime(int64_t ns)
52       : secs(ns / 1000000000LL), micros((ns - secs * 1000000000LL) / 1000) {}
53 
54   const int64_t secs;
55   const int64_t micros;
56 };
57 
58 class ArgsSerializer {
59  public:
60   ArgsSerializer(TraceProcessorContext*,
61                  ArgSetId arg_set_id,
62                  NullTermStringView event_name,
63                  std::vector<std::optional<uint32_t>>* field_id_to_arg_index,
64                  base::StringWriter*);
65 
66   void SerializeArgs();
67 
68  private:
69   using ValueWriter = std::function<void(const Variadic&)>;
70   using SerializerValueWriter = void (ArgsSerializer::*)(const Variadic&);
71 
72   // Arg writing functions.
WriteArgForField(uint32_t field_id,ValueWriter writer)73   void WriteArgForField(uint32_t field_id, ValueWriter writer) {
74     std::optional<uint32_t> row = FieldIdToRow(field_id);
75     if (!row)
76       return;
77     WriteArgAtRow(*row, writer);
78   }
WriteArgForField(uint32_t field_id,base::StringView key,ValueWriter writer)79   void WriteArgForField(uint32_t field_id,
80                         base::StringView key,
81                         ValueWriter writer) {
82     std::optional<uint32_t> row = FieldIdToRow(field_id);
83     if (!row)
84       return;
85     WriteArg(key, storage_->GetArgValue(*row), writer);
86   }
WriteArgAtRow(uint32_t arg_row,ValueWriter writer)87   void WriteArgAtRow(uint32_t arg_row, ValueWriter writer) {
88     const auto& args = storage_->arg_table();
89     const auto& key = storage_->GetString(args.key()[arg_row]);
90     WriteArg(key, storage_->GetArgValue(arg_row), writer);
91   }
92   void WriteArg(base::StringView key, Variadic value, ValueWriter writer);
93 
94   // Value writing functions.
WriteValueForField(uint32_t field_id,ValueWriter writer)95   void WriteValueForField(uint32_t field_id, ValueWriter writer) {
96     std::optional<uint32_t> row = FieldIdToRow(field_id);
97     if (!row)
98       return;
99     writer(storage_->GetArgValue(*row));
100   }
WriteKernelFnValue(const Variadic & value)101   void WriteKernelFnValue(const Variadic& value) {
102     if (value.type == Variadic::Type::kUint) {
103       writer_->AppendHexInt(value.uint_value);
104     } else if (value.type == Variadic::Type::kString) {
105       WriteValue(value);
106     } else {
107       PERFETTO_DFATAL("Invalid field type %d", static_cast<int>(value.type));
108     }
109   }
110   void WriteValue(const Variadic& variadic);
111 
112   // The default value writer which uses the |WriteValue| function.
DVW()113   ValueWriter DVW() { return Wrap(&ArgsSerializer::WriteValue); }
Wrap(SerializerValueWriter writer)114   ValueWriter Wrap(SerializerValueWriter writer) {
115     return [this, writer](const Variadic& v) { (this->*writer)(v); };
116   }
117 
118   // Converts a field id to a row in the args table.
FieldIdToRow(uint32_t field_id)119   std::optional<uint32_t> FieldIdToRow(uint32_t field_id) {
120     PERFETTO_DCHECK(field_id > 0);
121     PERFETTO_DCHECK(field_id < field_id_to_arg_index_->size());
122     std::optional<uint32_t> index_in_arg_set =
123         (*field_id_to_arg_index_)[field_id];
124     return index_in_arg_set.has_value()
125                ? std::make_optional(start_row_ + *index_in_arg_set)
126                : std::nullopt;
127   }
128 
129   const TraceStorage* storage_ = nullptr;
130   TraceProcessorContext* context_ = nullptr;
131   ArgSetId arg_set_id_ = kInvalidArgSetId;
132   NullTermStringView event_name_;
133   std::vector<std::optional<uint32_t>>* field_id_to_arg_index_;
134 
135   RowMap row_map_;
136   uint32_t start_row_ = 0;
137 
138   base::StringWriter* writer_ = nullptr;
139 };
140 
ArgsSerializer(TraceProcessorContext * context,ArgSetId arg_set_id,NullTermStringView event_name,std::vector<std::optional<uint32_t>> * field_id_to_arg_index,base::StringWriter * writer)141 ArgsSerializer::ArgsSerializer(
142     TraceProcessorContext* context,
143     ArgSetId arg_set_id,
144     NullTermStringView event_name,
145     std::vector<std::optional<uint32_t>>* field_id_to_arg_index,
146     base::StringWriter* writer)
147     : context_(context),
148       arg_set_id_(arg_set_id),
149       event_name_(event_name),
150       field_id_to_arg_index_(field_id_to_arg_index),
151       writer_(writer) {
152   storage_ = context_->storage.get();
153   const auto& args = storage_->arg_table();
154   const auto& set_ids = args.arg_set_id();
155 
156   // We assume that the row map is a contiguous range (which is always the case
157   // because arg_set_ids are contiguous by definition).
158   row_map_ = args.FilterToRowMap({set_ids.eq(arg_set_id_)});
159   start_row_ = row_map_.empty() ? 0 : row_map_.Get(0);
160 
161   // If the vector already has entries, we've previously cached the mapping
162   // from field id to arg index.
163   if (!field_id_to_arg_index->empty())
164     return;
165 
166   auto* descriptor = GetMessageDescriptorForName(event_name);
167   if (!descriptor) {
168     // If we don't have a descriptor, this event must be a generic ftrace event.
169     // As we can't possibly have any special handling for generic events, just
170     // add a row to the vector (for the invalid field id 0) to remove future
171     // lookups for this event name.
172     field_id_to_arg_index->resize(1);
173     return;
174   }
175 
176   // If we have a descriptor, try and create the mapping from proto field id
177   // to the index in the arg set.
178   size_t max = descriptor->max_field_id;
179 
180   // We need to reserve an index for the invalid field id 0.
181   field_id_to_arg_index_->resize(max + 1);
182 
183   // Go through each field id and find the entry in the args table for that
184   for (uint32_t i = 1; i <= max; ++i) {
185     for (auto it = row_map_.IterateRows(); it; it.Next()) {
186       base::StringView key = args.key().GetString(it.index());
187       if (key == descriptor->fields[i].name) {
188         (*field_id_to_arg_index)[i] = it.row();
189         break;
190       }
191     }
192   }
193 }
194 
SerializeArgs()195 void ArgsSerializer::SerializeArgs() {
196   if (row_map_.empty())
197     return;
198 
199   if (event_name_ == "sched_switch") {
200     using SS = protos::pbzero::SchedSwitchFtraceEvent;
201 
202     WriteArgForField(SS::kPrevCommFieldNumber, DVW());
203     WriteArgForField(SS::kPrevPidFieldNumber, DVW());
204     WriteArgForField(SS::kPrevPrioFieldNumber, DVW());
205     WriteArgForField(SS::kPrevStateFieldNumber, [this](const Variadic& value) {
206       PERFETTO_DCHECK(value.type == Variadic::Type::kInt);
207       auto state = static_cast<uint16_t>(value.int_value);
208       std::optional<VersionNumber> kernel_version =
209           SystemInfoTracker::GetOrCreate(context_)->GetKernelVersion();
210       writer_->AppendString(
211           ftrace_utils::TaskState::FromRawPrevState(state, kernel_version)
212               .ToString('|')
213               .data());
214     });
215     writer_->AppendLiteral(" ==>");
216     WriteArgForField(SS::kNextCommFieldNumber, DVW());
217     WriteArgForField(SS::kNextPidFieldNumber, DVW());
218     WriteArgForField(SS::kNextPrioFieldNumber, DVW());
219     return;
220   } else if (event_name_ == "sched_wakeup") {
221     using SW = protos::pbzero::SchedWakeupFtraceEvent;
222     WriteArgForField(SW::kCommFieldNumber, DVW());
223     WriteArgForField(SW::kPidFieldNumber, DVW());
224     WriteArgForField(SW::kPrioFieldNumber, DVW());
225     WriteArgForField(SW::kTargetCpuFieldNumber, [this](const Variadic& value) {
226       PERFETTO_DCHECK(value.type == Variadic::Type::kInt);
227       writer_->AppendPaddedInt<'0', 3>(value.int_value);
228     });
229     return;
230   } else if (event_name_ == "clock_set_rate") {
231     using CSR = protos::pbzero::ClockSetRateFtraceEvent;
232     writer_->AppendLiteral(" ");
233     WriteValueForField(CSR::kNameFieldNumber, DVW());
234     WriteArgForField(CSR::kStateFieldNumber, DVW());
235     WriteArgForField(CSR::kCpuIdFieldNumber, DVW());
236     return;
237   } else if (event_name_ == "clk_set_rate") {
238     using CSR = protos::pbzero::ClkSetRateFtraceEvent;
239     writer_->AppendLiteral(" ");
240     WriteValueForField(CSR::kNameFieldNumber, DVW());
241     writer_->AppendLiteral(" ");
242     WriteValueForField(CSR::kRateFieldNumber, DVW());
243     return;
244   } else if (event_name_ == "clock_enable") {
245     using CE = protos::pbzero::ClockEnableFtraceEvent;
246     WriteValueForField(CE::kNameFieldNumber, DVW());
247     WriteArgForField(CE::kStateFieldNumber, DVW());
248     WriteArgForField(CE::kCpuIdFieldNumber, DVW());
249     return;
250   } else if (event_name_ == "clock_disable") {
251     using CD = protos::pbzero::ClockDisableFtraceEvent;
252     WriteValueForField(CD::kNameFieldNumber, DVW());
253     WriteArgForField(CD::kStateFieldNumber, DVW());
254     WriteArgForField(CD::kCpuIdFieldNumber, DVW());
255     return;
256   } else if (event_name_ == "binder_transaction") {
257     using BT = protos::pbzero::BinderTransactionFtraceEvent;
258     writer_->AppendString(" transaction=");
259     WriteValueForField(BT::kDebugIdFieldNumber, [this](const Variadic& value) {
260       PERFETTO_DCHECK(value.type == Variadic::Type::kInt);
261       writer_->AppendUnsignedInt(static_cast<uint32_t>(value.int_value));
262     });
263 
264     writer_->AppendString(" dest_node=");
265     WriteValueForField(
266         BT::kTargetNodeFieldNumber, [this](const Variadic& value) {
267           PERFETTO_DCHECK(value.type == Variadic::Type::kInt);
268           writer_->AppendUnsignedInt(static_cast<uint32_t>(value.int_value));
269         });
270 
271     writer_->AppendString(" dest_proc=");
272     WriteValueForField(BT::kToProcFieldNumber, DVW());
273 
274     writer_->AppendString(" dest_thread=");
275     WriteValueForField(BT::kToThreadFieldNumber, DVW());
276 
277     writer_->AppendString(" reply=");
278     WriteValueForField(BT::kReplyFieldNumber, DVW());
279 
280     writer_->AppendString(" flags=0x");
281     WriteValueForField(BT::kFlagsFieldNumber, [this](const Variadic& value) {
282       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
283       writer_->AppendHexInt(value.uint_value);
284     });
285 
286     writer_->AppendString(" code=0x");
287     WriteValueForField(BT::kCodeFieldNumber, [this](const Variadic& value) {
288       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
289       writer_->AppendHexInt(value.uint_value);
290     });
291     return;
292   } else if (event_name_ == "binder_transaction_alloc_buf") {
293     using BTAB = protos::pbzero::BinderTransactionAllocBufFtraceEvent;
294     writer_->AppendString(" transaction=");
295     WriteValueForField(
296         BTAB::kDebugIdFieldNumber, [this](const Variadic& value) {
297           PERFETTO_DCHECK(value.type == Variadic::Type::kInt);
298           writer_->AppendUnsignedInt(static_cast<uint32_t>(value.int_value));
299         });
300     WriteArgForField(BTAB::kDataSizeFieldNumber, DVW());
301     WriteArgForField(BTAB::kOffsetsSizeFieldNumber, DVW());
302     return;
303   } else if (event_name_ == "binder_transaction_received") {
304     using BTR = protos::pbzero::BinderTransactionReceivedFtraceEvent;
305     writer_->AppendString(" transaction=");
306     WriteValueForField(BTR::kDebugIdFieldNumber, [this](const Variadic& value) {
307       PERFETTO_DCHECK(value.type == Variadic::Type::kInt);
308       writer_->AppendUnsignedInt(static_cast<uint32_t>(value.int_value));
309     });
310     return;
311   } else if (event_name_ == "mm_filemap_add_to_page_cache") {
312     using MFA = protos::pbzero::MmFilemapAddToPageCacheFtraceEvent;
313     writer_->AppendString(" dev ");
314     WriteValueForField(MFA::kSDevFieldNumber, [this](const Variadic& value) {
315       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
316       writer_->AppendUnsignedInt(value.uint_value >> 20);
317     });
318     writer_->AppendString(":");
319     WriteValueForField(MFA::kSDevFieldNumber, [this](const Variadic& value) {
320       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
321       writer_->AppendUnsignedInt(value.uint_value & ((1 << 20) - 1));
322     });
323     writer_->AppendString(" ino ");
324     WriteValueForField(MFA::kIInoFieldNumber, [this](const Variadic& value) {
325       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
326       writer_->AppendHexInt(value.uint_value);
327     });
328     writer_->AppendString(" page=0000000000000000");
329     writer_->AppendString(" pfn=");
330     WriteValueForField(MFA::kPfnFieldNumber, DVW());
331     writer_->AppendString(" ofs=");
332     WriteValueForField(MFA::kIndexFieldNumber, [this](const Variadic& value) {
333       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
334       writer_->AppendUnsignedInt(value.uint_value << 12);
335     });
336     return;
337   } else if (event_name_ == "print") {
338     using P = protos::pbzero::PrintFtraceEvent;
339 
340     writer_->AppendChar(' ');
341     WriteValueForField(P::kBufFieldNumber, [this](const Variadic& value) {
342       PERFETTO_DCHECK(value.type == Variadic::Type::kString);
343 
344       NullTermStringView str = storage_->GetString(value.string_value);
345       // If the last character is a newline in a print, just drop it.
346       auto chars_to_print = !str.empty() && str.c_str()[str.size() - 1] == '\n'
347                                 ? str.size() - 1
348                                 : str.size();
349       writer_->AppendString(str.c_str(), chars_to_print);
350     });
351     return;
352   } else if (event_name_ == "sched_blocked_reason") {
353     using SBR = protos::pbzero::SchedBlockedReasonFtraceEvent;
354     WriteArgForField(SBR::kPidFieldNumber, DVW());
355     WriteArgForField(SBR::kIoWaitFieldNumber, DVW());
356     WriteArgForField(SBR::kCallerFieldNumber,
357                      Wrap(&ArgsSerializer::WriteKernelFnValue));
358     return;
359   } else if (event_name_ == "workqueue_activate_work") {
360     using WAW = protos::pbzero::WorkqueueActivateWorkFtraceEvent;
361     writer_->AppendString(" work struct ");
362     WriteValueForField(WAW::kWorkFieldNumber, [this](const Variadic& value) {
363       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
364       writer_->AppendHexInt(value.uint_value);
365     });
366     return;
367   } else if (event_name_ == "workqueue_execute_start") {
368     using WES = protos::pbzero::WorkqueueExecuteStartFtraceEvent;
369     writer_->AppendString(" work struct ");
370     WriteValueForField(WES::kWorkFieldNumber, [this](const Variadic& value) {
371       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
372       writer_->AppendHexInt(value.uint_value);
373     });
374     writer_->AppendString(": function ");
375     WriteValueForField(WES::kFunctionFieldNumber,
376                        Wrap(&ArgsSerializer::WriteKernelFnValue));
377     return;
378   } else if (event_name_ == "workqueue_execute_end") {
379     using WE = protos::pbzero::WorkqueueExecuteEndFtraceEvent;
380     writer_->AppendString(" work struct ");
381     WriteValueForField(WE::kWorkFieldNumber, [this](const Variadic& value) {
382       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
383       writer_->AppendHexInt(value.uint_value);
384     });
385     return;
386   } else if (event_name_ == "workqueue_queue_work") {
387     using WQW = protos::pbzero::WorkqueueQueueWorkFtraceEvent;
388     writer_->AppendString(" work struct=");
389     WriteValueForField(WQW::kWorkFieldNumber, [this](const Variadic& value) {
390       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
391       writer_->AppendHexInt(value.uint_value);
392     });
393     WriteArgForField(WQW::kFunctionFieldNumber,
394                      Wrap(&ArgsSerializer::WriteKernelFnValue));
395     WriteArgForField(WQW::kWorkqueueFieldNumber, [this](const Variadic& value) {
396       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
397       writer_->AppendHexInt(value.uint_value);
398     });
399     WriteValueForField(WQW::kReqCpuFieldNumber, DVW());
400     WriteValueForField(WQW::kCpuFieldNumber, DVW());
401     return;
402   } else if (event_name_ == "irq_handler_entry") {
403     using IEN = protos::pbzero::IrqHandlerEntryFtraceEvent;
404     WriteArgForField(IEN::kIrqFieldNumber, DVW());
405     WriteArgForField(IEN::kNameFieldNumber, DVW());
406     return;
407   } else if (event_name_ == "irq_handler_exit") {
408     using IEX = protos::pbzero::IrqHandlerExitFtraceEvent;
409     WriteArgForField(IEX::kIrqFieldNumber, DVW());
410     writer_->AppendString(" ret=");
411     WriteValueForField(IEX::kRetFieldNumber, [this](const Variadic& value) {
412       PERFETTO_DCHECK(value.type == Variadic::Type::kInt);
413       writer_->AppendString(value.int_value ? "handled" : "unhandled");
414     });
415     return;
416   } else if (event_name_ == "softirq_entry") {
417     using SIE = protos::pbzero::SoftirqEntryFtraceEvent;
418     WriteArgForField(SIE::kVecFieldNumber, DVW());
419     writer_->AppendString(" [action=");
420     WriteValueForField(SIE::kVecFieldNumber, [this](const Variadic& value) {
421       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
422       writer_->AppendString(kActionNames[value.uint_value]);
423     });
424     writer_->AppendString("]");
425     return;
426   } else if (event_name_ == "softirq_exit") {
427     using SIX = protos::pbzero::SoftirqExitFtraceEvent;
428     WriteArgForField(SIX::kVecFieldNumber, DVW());
429     writer_->AppendString(" [action=");
430     WriteValueForField(SIX::kVecFieldNumber, [this](const Variadic& value) {
431       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
432       writer_->AppendString(kActionNames[value.uint_value]);
433     });
434     writer_->AppendString("]");
435     return;
436   } else if (event_name_ == "tracing_mark_write") {
437     using TMW = protos::pbzero::TracingMarkWriteFtraceEvent;
438     WriteValueForField(TMW::kTraceBeginFieldNumber,
439                        [this](const Variadic& value) {
440                          PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
441                          writer_->AppendChar(value.uint_value ? 'B' : 'E');
442                        });
443     writer_->AppendString("|");
444     WriteValueForField(TMW::kPidFieldNumber, DVW());
445     writer_->AppendString("|");
446     WriteValueForField(TMW::kTraceNameFieldNumber, DVW());
447     return;
448   } else if (event_name_ == "dpu_tracing_mark_write") {
449     using TMW = protos::pbzero::DpuTracingMarkWriteFtraceEvent;
450     WriteValueForField(TMW::kTypeFieldNumber, [this](const Variadic& value) {
451       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
452       writer_->AppendChar(static_cast<char>(value.uint_value));
453     });
454     writer_->AppendString("|");
455     WriteValueForField(TMW::kPidFieldNumber, DVW());
456     writer_->AppendString("|");
457     WriteValueForField(TMW::kNameFieldNumber, DVW());
458     writer_->AppendString("|");
459     WriteValueForField(TMW::kValueFieldNumber, DVW());
460     return;
461   } else if (event_name_ == "g2d_tracing_mark_write") {
462     using TMW = protos::pbzero::G2dTracingMarkWriteFtraceEvent;
463     WriteValueForField(TMW::kTypeFieldNumber, [this](const Variadic& value) {
464       PERFETTO_DCHECK(value.type == Variadic::Type::kUint);
465       writer_->AppendChar(static_cast<char>(value.uint_value));
466     });
467     writer_->AppendString("|");
468     WriteValueForField(TMW::kPidFieldNumber, DVW());
469     writer_->AppendString("|");
470     WriteValueForField(TMW::kNameFieldNumber, DVW());
471     writer_->AppendString("|");
472     WriteValueForField(TMW::kValueFieldNumber, DVW());
473     return;
474   } else if (event_name_ == "cgroup_attach_task") {
475     using CAT = protos::pbzero::CgroupAttachTaskFtraceEvent;
476     WriteArgForField(CAT::kDstRootFieldNumber, DVW());
477     WriteArgForField(CAT::kDstIdFieldNumber, DVW());
478     WriteArgForField(CAT::kCnameFieldNumber, "cgroup", DVW());
479     WriteArgForField(CAT::kDstLevelFieldNumber, DVW());
480     WriteArgForField(CAT::kDstPathFieldNumber, DVW());
481     WriteArgForField(CAT::kPidFieldNumber, DVW());
482     WriteArgForField(CAT::kCommFieldNumber, DVW());
483     return;
484   }
485   for (auto it = row_map_.IterateRows(); it; it.Next()) {
486     WriteArgAtRow(it.index(), DVW());
487   }
488 }
489 
WriteArg(base::StringView key,Variadic value,ValueWriter writer)490 void ArgsSerializer::WriteArg(base::StringView key,
491                               Variadic value,
492                               ValueWriter writer) {
493   writer_->AppendChar(' ');
494   writer_->AppendString(key.data(), key.size());
495   writer_->AppendChar('=');
496 
497   if (key == "gfp_flags") {
498     auto kernel_version =
499         SystemInfoTracker::GetOrCreate(context_)->GetKernelVersion();
500     WriteGfpFlag(value.uint_value, kernel_version, writer_);
501     return;
502   }
503   writer(value);
504 }
505 
WriteValue(const Variadic & value)506 void ArgsSerializer::WriteValue(const Variadic& value) {
507   switch (value.type) {
508     case Variadic::kInt:
509       writer_->AppendInt(value.int_value);
510       break;
511     case Variadic::kUint:
512       writer_->AppendUnsignedInt(value.uint_value);
513       break;
514     case Variadic::kString: {
515       const auto& str = storage_->GetString(value.string_value);
516       writer_->AppendString(str.c_str(), str.size());
517       break;
518     }
519     case Variadic::kReal:
520       writer_->AppendDouble(value.real_value);
521       break;
522     case Variadic::kPointer:
523       writer_->AppendUnsignedInt(value.pointer_value);
524       break;
525     case Variadic::kBool:
526       writer_->AppendBool(value.bool_value);
527       break;
528     case Variadic::kJson: {
529       const auto& str = storage_->GetString(value.json_value);
530       writer_->AppendString(str.c_str(), str.size());
531       break;
532     }
533     case Variadic::kNull:
534       writer_->AppendLiteral("[NULL]");
535       break;
536   }
537 }
538 
539 }  // namespace
540 
Run(Context * context,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors & destructors)541 base::Status ToFtrace::Run(Context* context,
542                            size_t argc,
543                            sqlite3_value** argv,
544                            SqlValue& out,
545                            Destructors& destructors) {
546   if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
547     return base::ErrStatus("Usage: to_ftrace(id)");
548   }
549   uint32_t row = static_cast<uint32_t>(sqlite3_value_int64(argv[0]));
550 
551   auto str = context->serializer.SerializeToString(row);
552   if (str.get() == nullptr) {
553     return base::ErrStatus("to_ftrace: Cannot serialize row id %u", row);
554   }
555 
556   out = SqlValue::String(str.release());
557   destructors.string_destructor = str.get_deleter();
558   return base::OkStatus();
559 }
560 
SystraceSerializer(TraceProcessorContext * context)561 SystraceSerializer::SystraceSerializer(TraceProcessorContext* context)
562     : context_(context) {
563   storage_ = context_->storage.get();
564 }
565 
SerializeToString(uint32_t raw_row)566 SystraceSerializer::ScopedCString SystraceSerializer::SerializeToString(
567     uint32_t raw_row) {
568   const auto& raw = storage_->raw_table();
569 
570   char line[4096];
571   base::StringWriter writer(line, sizeof(line));
572 
573   StringId event_name_id = raw.name()[raw_row];
574   NullTermStringView event_name = storage_->GetString(event_name_id);
575   if (event_name.StartsWith("chrome_event.") ||
576       event_name.StartsWith("track_event.")) {
577     return ScopedCString(nullptr, nullptr);
578   }
579 
580   SerializePrefix(raw_row, &writer);
581 
582   writer.AppendChar(' ');
583   if (event_name == "print" || event_name == "g2d_tracing_mark_write" ||
584       event_name == "dpu_tracing_mark_write") {
585     writer.AppendString("tracing_mark_write");
586   } else {
587     writer.AppendString(event_name.c_str(), event_name.size());
588   }
589   writer.AppendChar(':');
590 
591   ArgsSerializer serializer(context_, raw.arg_set_id()[raw_row], event_name,
592                             &proto_id_to_arg_index_by_event_[event_name_id],
593                             &writer);
594   serializer.SerializeArgs();
595 
596   return ScopedCString(writer.CreateStringCopy(), free);
597 }
598 
SerializePrefix(uint32_t raw_row,base::StringWriter * writer)599 void SystraceSerializer::SerializePrefix(uint32_t raw_row,
600                                          base::StringWriter* writer) {
601   const auto& raw = storage_->raw_table();
602 
603   int64_t ts = raw.ts()[raw_row];
604   uint32_t cpu = raw.cpu()[raw_row];
605 
606   UniqueTid utid = raw.utid()[raw_row];
607   uint32_t tid = storage_->thread_table().tid()[utid];
608 
609   uint32_t tgid = 0;
610   auto opt_upid = storage_->thread_table().upid()[utid];
611   if (opt_upid.has_value()) {
612     tgid = storage_->process_table().pid()[*opt_upid];
613   }
614   auto name = storage_->thread_table().name().GetString(utid);
615 
616   FtraceTime ftrace_time(ts);
617   if (tid == 0) {
618     name = "<idle>";
619   } else if (name.empty()) {
620     name = "<unknown>";
621   }
622 
623   int64_t padding = 16 - static_cast<int64_t>(name.size());
624   if (padding > 0) {
625     writer->AppendChar(' ', static_cast<size_t>(padding));
626   }
627   for (size_t i = 0; i < name.size(); ++i) {
628     char c = name.data()[i];
629     writer->AppendChar(c == '-' ? '_' : c);
630   }
631   writer->AppendChar('-');
632 
633   size_t pre_pid_pos = writer->pos();
634   writer->AppendInt(tid);
635   size_t pid_chars = writer->pos() - pre_pid_pos;
636   if (PERFETTO_LIKELY(pid_chars < 5)) {
637     writer->AppendChar(' ', 5 - pid_chars);
638   }
639 
640   writer->AppendLiteral(" (");
641   if (tgid == 0) {
642     writer->AppendLiteral("-----");
643   } else {
644     writer->AppendPaddedInt<' ', 5>(tgid);
645   }
646   writer->AppendLiteral(") [");
647   writer->AppendPaddedInt<'0', 3>(cpu);
648   writer->AppendLiteral("] .... ");
649 
650   writer->AppendInt(ftrace_time.secs);
651   writer->AppendChar('.');
652   writer->AppendPaddedInt<'0', 6>(ftrace_time.micros);
653   writer->AppendChar(':');
654 }
655 
656 }  // namespace trace_processor
657 }  // namespace perfetto
658