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 24 ArgsTable::ArgsTable(sqlite3*, const TraceStorage* storage) 25 : storage_(storage) {} 26 27 void ArgsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) { 28 Table::Register<ArgsTable>(db, storage, "args"); 29 } 30 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 43 uint32_t ArgsTable::RowCount() { 44 return static_cast<uint32_t>(storage_->args().args_count()); 45 } 46 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 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 70 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 93 ArgsTable::ValueColumn::Bounds ArgsTable::ValueColumn::BoundFilter( 94 int, 95 sqlite3_value*) const { 96 return Bounds{}; 97 } 98 99 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 137 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 145 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