Home | History | Annotate | Download | only in trace_processor
      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