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