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