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