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/raw_table.h"
18
19 #include <inttypes.h>
20
21 #include "src/trace_processor/ftrace_descriptors.h"
22 #include "src/trace_processor/sqlite_utils.h"
23
24 #include "perfetto/trace/ftrace/binder.pbzero.h"
25 #include "perfetto/trace/ftrace/clk.pbzero.h"
26 #include "perfetto/trace/ftrace/ftrace.pbzero.h"
27 #include "perfetto/trace/ftrace/ftrace_event.pbzero.h"
28 #include "perfetto/trace/ftrace/sched.pbzero.h"
29
30 namespace perfetto {
31 namespace trace_processor {
32
RawTable(sqlite3 * db,const TraceStorage * storage)33 RawTable::RawTable(sqlite3* db, const TraceStorage* storage)
34 : storage_(storage) {
35 auto fn = [](sqlite3_context* ctx, int argc, sqlite3_value** argv) {
36 auto* thiz = static_cast<RawTable*>(sqlite3_user_data(ctx));
37 thiz->ToSystrace(ctx, argc, argv);
38 };
39 sqlite3_create_function(db, "to_ftrace", 1,
40 SQLITE_UTF8 | SQLITE_DETERMINISTIC, this, fn, nullptr,
41 nullptr);
42 }
43
RegisterTable(sqlite3 * db,const TraceStorage * storage)44 void RawTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
45 Table::Register<RawTable>(db, storage, "raw");
46 }
47
CreateStorageSchema()48 StorageSchema RawTable::CreateStorageSchema() {
49 const auto& raw = storage_->raw_events();
50 return StorageSchema::Builder()
51 .AddGenericNumericColumn("id", RowIdAccessor(TableId::kRawEvents))
52 .AddOrderedNumericColumn("ts", &raw.timestamps())
53 .AddStringColumn("name", &raw.name_ids(), &storage_->string_pool())
54 .AddNumericColumn("cpu", &raw.cpus())
55 .AddNumericColumn("utid", &raw.utids())
56 .AddNumericColumn("arg_set_id", &raw.arg_set_ids())
57 .Build({"name", "ts"});
58 }
59
RowCount()60 uint32_t RawTable::RowCount() {
61 return static_cast<uint32_t>(storage_->raw_events().raw_event_count());
62 }
63
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)64 int RawTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
65 info->estimated_cost = RowCount();
66
67 // Only the string columns are handled by SQLite
68 info->order_by_consumed = true;
69 size_t name_index = schema().ColumnIndexFromName("name");
70 for (size_t i = 0; i < qc.constraints().size(); i++) {
71 info->omit[i] = qc.constraints()[i].iColumn != static_cast<int>(name_index);
72 }
73
74 return SQLITE_OK;
75 }
76
FormatSystraceArgs(NullTermStringView event_name,ArgSetId arg_set_id,base::StringWriter * writer)77 void RawTable::FormatSystraceArgs(NullTermStringView event_name,
78 ArgSetId arg_set_id,
79 base::StringWriter* writer) {
80 const auto& set_ids = storage_->args().set_ids();
81 auto lb = std::lower_bound(set_ids.begin(), set_ids.end(), arg_set_id);
82 auto ub = std::find(lb, set_ids.end(), arg_set_id + 1);
83
84 auto start_row = static_cast<uint32_t>(std::distance(set_ids.begin(), lb));
85
86 using Variadic = TraceStorage::Args::Variadic;
87 using ValueWriter = std::function<void(const Variadic&)>;
88 auto write_value = [this, writer](const Variadic& value) {
89 switch (value.type) {
90 case TraceStorage::Args::Variadic::kInt:
91 writer->AppendInt(value.int_value);
92 break;
93 case TraceStorage::Args::Variadic::kReal:
94 writer->AppendDouble(value.real_value);
95 break;
96 case TraceStorage::Args::Variadic::kString: {
97 const auto& str = storage_->GetString(value.string_value);
98 writer->AppendString(str.c_str(), str.size());
99 }
100 }
101 };
102 auto write_value_at_index = [this, start_row](uint32_t arg_idx,
103 ValueWriter value_fn) {
104 value_fn(storage_->args().arg_values()[start_row + arg_idx]);
105 };
106 auto write_arg = [this, writer, start_row](uint32_t arg_idx,
107 ValueWriter value_fn) {
108 uint32_t arg_row = start_row + arg_idx;
109 const auto& args = storage_->args();
110 const auto& key = storage_->GetString(args.keys()[arg_row]);
111 const auto& value = args.arg_values()[arg_row];
112
113 writer->AppendChar(' ');
114 writer->AppendString(key.c_str(), key.size());
115 writer->AppendChar('=');
116 value_fn(value);
117 };
118
119 if (event_name == "sched_switch") {
120 using SS = protos::pbzero::SchedSwitchFtraceEvent;
121 write_arg(SS::kPrevCommFieldNumber - 1, write_value);
122 write_arg(SS::kPrevPidFieldNumber - 1, write_value);
123 write_arg(SS::kPrevPrioFieldNumber - 1, write_value);
124 write_arg(SS::kPrevStateFieldNumber - 1, [writer](const Variadic& value) {
125 auto state = static_cast<uint16_t>(value.int_value);
126 writer->AppendString(ftrace_utils::TaskState(state).ToString().data());
127 });
128 writer->AppendLiteral(" ==>");
129 write_arg(SS::kNextCommFieldNumber - 1, write_value);
130 write_arg(SS::kNextPidFieldNumber - 1, write_value);
131 write_arg(SS::kNextPrioFieldNumber - 1, write_value);
132 return;
133 } else if (event_name == "sched_wakeup") {
134 using SW = protos::pbzero::SchedWakeupFtraceEvent;
135 write_arg(SW::kCommFieldNumber - 1, write_value);
136 write_arg(SW::kPidFieldNumber - 1, write_value);
137 write_arg(SW::kPrioFieldNumber - 1, write_value);
138 write_arg(SW::kTargetCpuFieldNumber - 1, [writer](const Variadic& value) {
139 writer->AppendPaddedInt<'0', 3>(value.int_value);
140 });
141 return;
142 } else if (event_name == "clock_set_rate") {
143 // TODO(lalitm): this is a big hack but the best way to do this now.
144 // Doing this requires overhauling how we deal with args by pushing them all
145 // to an array and then reading back from that array.
146
147 // We use the string "todo" as the name to stay consistent with old
148 // trace_to_text print code.
149 writer->AppendString(" todo");
150 write_arg(0 /* state */, write_value);
151 write_arg(1 /* cpu_id */, write_value);
152 return;
153 } else if (event_name == "clk_set_rate") {
154 using CSR = protos::pbzero::ClkSetRateFtraceEvent;
155 writer->AppendLiteral(" ");
156 write_value_at_index(CSR::kNameFieldNumber - 1, write_value);
157 writer->AppendLiteral(" ");
158 write_value_at_index(CSR::kRateFieldNumber - 1, write_value);
159 return;
160 } else if (event_name == "binder_transaction") {
161 using BT = protos::pbzero::BinderTransactionFtraceEvent;
162 writer->AppendString(" transaction=");
163 write_value_at_index(BT::kDebugIdFieldNumber - 1, write_value);
164 writer->AppendString(" dest_node=");
165 write_value_at_index(BT::kTargetNodeFieldNumber - 1, write_value);
166 writer->AppendString(" dest_proc=");
167 write_value_at_index(BT::kToProcFieldNumber - 1, write_value);
168 writer->AppendString(" dest_thread=");
169 write_value_at_index(BT::kToThreadFieldNumber - 1, write_value);
170 write_arg(BT::kReplyFieldNumber - 1, write_value);
171 writer->AppendString(" flags=0x");
172 write_value_at_index(
173 BT::kFlagsFieldNumber - 1, [writer](const Variadic& value) {
174 writer->AppendHexInt(static_cast<uint32_t>(value.int_value));
175 });
176 writer->AppendString(" code=0x");
177 write_value_at_index(
178 BT::kCodeFieldNumber - 1, [writer](const Variadic& value) {
179 writer->AppendHexInt(static_cast<uint32_t>(value.int_value));
180 });
181 return;
182 } else if (event_name == "binder_transaction_alloc_buf") {
183 using BTAB = protos::pbzero::BinderTransactionAllocBufFtraceEvent;
184 writer->AppendString(" transaction=");
185 write_value_at_index(BTAB::kDebugIdFieldNumber - 1, write_value);
186 write_arg(BTAB::kDataSizeFieldNumber - 1, write_value);
187 write_arg(BTAB::kOffsetsSizeFieldNumber - 1, write_value);
188 return;
189 } else if (event_name == "binder_transaction_received") {
190 using BTR = protos::pbzero::BinderTransactionReceivedFtraceEvent;
191 writer->AppendString(" transaction=");
192 write_value_at_index(BTR::kDebugIdFieldNumber - 1, write_value);
193 return;
194 } else if (event_name == "print") {
195 using P = protos::pbzero::PrintFtraceEvent;
196
197 uint32_t arg_row = start_row + P::kBufFieldNumber - 1;
198 const auto& args = storage_->args();
199 const auto& value = args.arg_values()[arg_row];
200 const auto& str = storage_->GetString(value.string_value);
201 // If the last character is a newline in a print, just drop it.
202 auto chars_to_print = !str.empty() && str.c_str()[str.size() - 1] == '\n'
203 ? str.size() - 1
204 : str.size();
205 writer->AppendChar(' ');
206 writer->AppendString(str.c_str(), chars_to_print);
207 return;
208 }
209
210 uint32_t arg = 0;
211 for (auto it = lb; it != ub; it++) {
212 write_arg(arg++, write_value);
213 }
214 }
215
ToSystrace(sqlite3_context * ctx,int argc,sqlite3_value ** argv)216 void RawTable::ToSystrace(sqlite3_context* ctx,
217 int argc,
218 sqlite3_value** argv) {
219 if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
220 sqlite3_result_error(ctx, "Usage: to_ftrace(id)", -1);
221 return;
222 }
223 RowId row_id = sqlite3_value_int64(argv[0]);
224 auto pair = TraceStorage::ParseRowId(row_id);
225 PERFETTO_DCHECK(pair.first == TableId::kRawEvents);
226 auto row = pair.second;
227
228 const auto& raw_evts = storage_->raw_events();
229
230 UniqueTid utid = raw_evts.utids()[row];
231 const auto& thread = storage_->GetThread(utid);
232 uint32_t tgid = 0;
233 if (thread.upid.has_value()) {
234 tgid = storage_->GetProcess(thread.upid.value()).pid;
235 }
236 const auto& name = storage_->GetString(thread.name_id);
237
238 char line[4096];
239 base::StringWriter writer(line, sizeof(line));
240
241 ftrace_utils::FormatSystracePrefix(raw_evts.timestamps()[row],
242 raw_evts.cpus()[row], thread.tid, tgid,
243 base::StringView(name), &writer);
244
245 const auto& event_name = storage_->GetString(raw_evts.name_ids()[row]);
246 writer.AppendChar(' ');
247 if (event_name == "print") {
248 writer.AppendString("tracing_mark_write");
249 } else {
250 writer.AppendString(event_name.c_str(), event_name.size());
251 }
252 writer.AppendChar(':');
253
254 FormatSystraceArgs(event_name, raw_evts.arg_set_ids()[row], &writer);
255 sqlite3_result_text(ctx, writer.CreateStringCopy(), -1, free);
256 }
257
258 } // namespace trace_processor
259 } // namespace perfetto
260