1 /*
2 * Copyright (C) 2018 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/args_table.h"
18
19 #include "src/trace_processor/sqlite_utils.h"
20
21 namespace perfetto {
22 namespace trace_processor {
23
ArgsTable(sqlite3 *,const TraceStorage * storage)24 ArgsTable::ArgsTable(sqlite3*, const TraceStorage* storage)
25 : storage_(storage) {}
26
RegisterTable(sqlite3 * db,const TraceStorage * storage)27 void ArgsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
28 Table::Register<ArgsTable>(db, storage, "args");
29 }
30
CreateStorageSchema()31 StorageSchema ArgsTable::CreateStorageSchema() {
32 const auto& args = storage_->args();
33 return StorageSchema::Builder()
34 .AddNumericColumn("arg_set_id", &args.set_ids())
35 .AddStringColumn("flat_key", &args.flat_keys(), &storage_->string_pool())
36 .AddStringColumn("key", &args.keys(), &storage_->string_pool())
37 .AddColumn<ValueColumn>("int_value", VariadicType::kInt, storage_)
38 .AddColumn<ValueColumn>("string_value", VariadicType::kString, storage_)
39 .AddColumn<ValueColumn>("real_value", VariadicType::kReal, storage_)
40 .Build({"arg_set_id", "key"});
41 }
42
RowCount()43 uint32_t ArgsTable::RowCount() {
44 return static_cast<uint32_t>(storage_->args().args_count());
45 }
46
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)47 int ArgsTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
48 // In the case of an id equality filter, we can do a very efficient lookup.
49 if (qc.constraints().size() == 1) {
50 auto id = static_cast<int>(schema().ColumnIndexFromName("arg_set_id"));
51 const auto& cs = qc.constraints().back();
52 if (cs.iColumn == id && sqlite_utils::IsOpEq(cs.op)) {
53 info->estimated_cost = 1;
54 return SQLITE_OK;
55 }
56 }
57
58 // Otherwise, just give the worst case scenario.
59 info->estimated_cost = static_cast<uint32_t>(storage_->args().args_count());
60 return SQLITE_OK;
61 }
62
ValueColumn(std::string col_name,VariadicType type,const TraceStorage * storage)63 ArgsTable::ValueColumn::ValueColumn(std::string col_name,
64 VariadicType type,
65 const TraceStorage* storage)
66 : StorageColumn(col_name, false /* hidden */),
67 type_(type),
68 storage_(storage) {}
69
ReportResult(sqlite3_context * ctx,uint32_t row) const70 void ArgsTable::ValueColumn::ReportResult(sqlite3_context* ctx,
71 uint32_t row) const {
72 const auto& value = storage_->args().arg_values()[row];
73 if (value.type != type_) {
74 sqlite3_result_null(ctx);
75 return;
76 }
77
78 switch (type_) {
79 case VariadicType::kInt:
80 sqlite_utils::ReportSqliteResult(ctx, value.int_value);
81 break;
82 case VariadicType::kReal:
83 sqlite_utils::ReportSqliteResult(ctx, value.real_value);
84 break;
85 case VariadicType::kString: {
86 const char* str = storage_->GetString(value.string_value).c_str();
87 sqlite3_result_text(ctx, str, -1, sqlite_utils::kSqliteStatic);
88 break;
89 }
90 }
91 }
92
BoundFilter(int,sqlite3_value *) const93 ArgsTable::ValueColumn::Bounds ArgsTable::ValueColumn::BoundFilter(
94 int,
95 sqlite3_value*) const {
96 return Bounds{};
97 }
98
Filter(int op,sqlite3_value * value,FilteredRowIndex * index) const99 void ArgsTable::ValueColumn::Filter(int op,
100 sqlite3_value* value,
101 FilteredRowIndex* index) const {
102 switch (type_) {
103 case VariadicType::kInt: {
104 bool op_is_null = sqlite_utils::IsOpIsNull(op);
105 auto predicate = sqlite_utils::CreateNumericPredicate<int64_t>(op, value);
106 index->FilterRows(
107 [this, predicate, op_is_null](uint32_t row) PERFETTO_ALWAYS_INLINE {
108 const auto& arg = storage_->args().arg_values()[row];
109 return arg.type == type_ ? predicate(arg.int_value) : op_is_null;
110 });
111 break;
112 }
113 case VariadicType::kReal: {
114 bool op_is_null = sqlite_utils::IsOpIsNull(op);
115 auto predicate = sqlite_utils::CreateNumericPredicate<double>(op, value);
116 index->FilterRows(
117 [this, predicate, op_is_null](uint32_t row) PERFETTO_ALWAYS_INLINE {
118 const auto& arg = storage_->args().arg_values()[row];
119 return arg.type == type_ ? predicate(arg.real_value) : op_is_null;
120 });
121 break;
122 }
123 case VariadicType::kString: {
124 auto predicate = sqlite_utils::CreateStringPredicate(op, value);
125 index->FilterRows([this,
126 &predicate](uint32_t row) PERFETTO_ALWAYS_INLINE {
127 const auto& arg = storage_->args().arg_values()[row];
128 return arg.type == type_
129 ? predicate(storage_->GetString(arg.string_value).c_str())
130 : predicate(nullptr);
131 });
132 break;
133 }
134 }
135 }
136
Sort(const QueryConstraints::OrderBy & ob) const137 ArgsTable::ValueColumn::Comparator ArgsTable::ValueColumn::Sort(
138 const QueryConstraints::OrderBy& ob) const {
139 if (ob.desc) {
140 return [this](uint32_t f, uint32_t s) { return -CompareRefsAsc(f, s); };
141 }
142 return [this](uint32_t f, uint32_t s) { return CompareRefsAsc(f, s); };
143 }
144
CompareRefsAsc(uint32_t f,uint32_t s) const145 int ArgsTable::ValueColumn::CompareRefsAsc(uint32_t f, uint32_t s) const {
146 const auto& arg_f = storage_->args().arg_values()[f];
147 const auto& arg_s = storage_->args().arg_values()[s];
148
149 if (arg_f.type == type_ && arg_s.type == type_) {
150 switch (type_) {
151 case VariadicType::kInt:
152 return sqlite_utils::CompareValuesAsc(arg_f.int_value, arg_s.int_value);
153 case VariadicType::kReal:
154 return sqlite_utils::CompareValuesAsc(arg_f.real_value,
155 arg_s.real_value);
156 case VariadicType::kString: {
157 const auto& f_str = storage_->GetString(arg_f.string_value);
158 const auto& s_str = storage_->GetString(arg_s.string_value);
159 return sqlite_utils::CompareValuesAsc(f_str, s_str);
160 }
161 }
162 } else if (arg_s.type == type_) {
163 return -1;
164 } else if (arg_f.type == type_) {
165 return 1;
166 }
167 return 0;
168 }
169
170 } // namespace trace_processor
171 } // namespace perfetto
172