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