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