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