blob: 7f013f68d2c6b1ce0cd6eaa17f1b60d8388b307f [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/args_table.h"
#include "src/trace_processor/sqlite_utils.h"
namespace perfetto {
namespace trace_processor {
ArgsTable::ArgsTable(sqlite3*, const TraceStorage* storage)
: storage_(storage) {}
void ArgsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
Table::Register<ArgsTable>(db, storage, "args");
}
StorageSchema ArgsTable::CreateStorageSchema() {
const auto& args = storage_->args();
return StorageSchema::Builder()
.AddColumn<IdColumn>("id", storage_, &args.ids())
.AddStringColumn("flat_key", &args.flat_keys(), &storage_->string_pool())
.AddStringColumn("key", &args.keys(), &storage_->string_pool())
.AddColumn<ValueColumn>("int_value", VariadicType::kInt, storage_)
.AddColumn<ValueColumn>("string_value", VariadicType::kString, storage_)
.AddColumn<ValueColumn>("real_value", VariadicType::kReal, storage_)
.Build({"id", "key"});
}
std::unique_ptr<Table::Cursor> ArgsTable::CreateCursor(
const QueryConstraints& qc,
sqlite3_value** argv) {
uint32_t count = static_cast<uint32_t>(storage_->args().args_count());
auto it = CreateBestRowIteratorForGenericSchema(count, qc, argv);
return std::unique_ptr<Cursor>(
new Cursor(std::move(it), schema_.mutable_columns()));
}
int ArgsTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
// In the case of an id equality filter, we can do a very efficient lookup.
if (qc.constraints().size() == 1) {
auto id = static_cast<int>(schema_.ColumnIndexFromName("id"));
const auto& cs = qc.constraints().back();
if (cs.iColumn == id && sqlite_utils::IsOpEq(cs.op)) {
info->estimated_cost = 1;
return SQLITE_OK;
}
}
// Otherwise, just give the worst case scenario.
info->estimated_cost = static_cast<uint32_t>(storage_->args().args_count());
return SQLITE_OK;
}
ArgsTable::IdColumn::IdColumn(std::string col_name,
const TraceStorage* storage,
const std::deque<RowId>* ids)
: NumericColumn(col_name, ids, false, false), storage_(storage) {}
void ArgsTable::IdColumn::Filter(int op,
sqlite3_value* value,
FilteredRowIndex* index) const {
if (!sqlite_utils::IsOpEq(op)) {
NumericColumn::Filter(op, value, index);
return;
}
auto id = sqlite_utils::ExtractSqliteValue<RowId>(value);
const auto& args_for_id = storage_->args().args_for_id();
auto it_pair = args_for_id.equal_range(id);
auto size = static_cast<size_t>(std::distance(it_pair.first, it_pair.second));
std::vector<uint32_t> rows(size);
size_t i = 0;
for (auto it = it_pair.first; it != it_pair.second; it++) {
rows[i++] = it->second;
}
index->IntersectRows(std::move(rows));
}
ArgsTable::ValueColumn::ValueColumn(std::string col_name,
VariadicType type,
const TraceStorage* storage)
: StorageColumn(col_name, false /* hidden */),
type_(type),
storage_(storage) {}
void ArgsTable::ValueColumn::ReportResult(sqlite3_context* ctx,
uint32_t row) const {
const auto& value = storage_->args().arg_values()[row];
if (value.type != type_) {
sqlite3_result_null(ctx);
return;
}
switch (type_) {
case VariadicType::kInt:
sqlite_utils::ReportSqliteResult(ctx, value.int_value);
break;
case VariadicType::kReal:
sqlite_utils::ReportSqliteResult(ctx, value.real_value);
break;
case VariadicType::kString: {
const char* str = storage_->GetString(value.string_value).c_str();
sqlite3_result_text(ctx, str, -1, sqlite_utils::kSqliteStatic);
break;
}
}
}
ArgsTable::ValueColumn::Bounds ArgsTable::ValueColumn::BoundFilter(
int,
sqlite3_value*) const {
return Bounds{};
}
void ArgsTable::ValueColumn::Filter(int op,
sqlite3_value* value,
FilteredRowIndex* index) const {
switch (type_) {
case VariadicType::kInt: {
auto predicate = sqlite_utils::CreatePredicate<int64_t>(op, value);
index->FilterRows([this, &predicate](uint32_t row) {
const auto& arg = storage_->args().arg_values()[row];
return arg.type == type_ ? predicate(arg.int_value)
: predicate(base::nullopt);
});
break;
}
case VariadicType::kReal: {
auto predicate = sqlite_utils::CreatePredicate<double>(op, value);
index->FilterRows([this, &predicate](uint32_t row) {
const auto& arg = storage_->args().arg_values()[row];
return arg.type == type_ ? predicate(arg.real_value)
: predicate(base::nullopt);
});
break;
}
case VariadicType::kString: {
auto predicate = sqlite_utils::CreatePredicate<std::string>(op, value);
index->FilterRows([this, &predicate](uint32_t row) {
const auto& arg = storage_->args().arg_values()[row];
const auto& str = storage_->GetString(arg.string_value);
return arg.type == type_ ? predicate(str) : predicate(base::nullopt);
});
break;
}
}
}
ArgsTable::ValueColumn::Comparator ArgsTable::ValueColumn::Sort(
const QueryConstraints::OrderBy& ob) const {
if (ob.desc) {
return [this](uint32_t f, uint32_t s) { return -CompareRefsAsc(f, s); };
}
return [this](uint32_t f, uint32_t s) { return CompareRefsAsc(f, s); };
}
int ArgsTable::ValueColumn::CompareRefsAsc(uint32_t f, uint32_t s) const {
const auto& arg_f = storage_->args().arg_values()[f];
const auto& arg_s = storage_->args().arg_values()[s];
if (arg_f.type == type_ && arg_s.type == type_) {
switch (type_) {
case VariadicType::kInt:
return sqlite_utils::CompareValuesAsc(arg_f.int_value, arg_s.int_value);
case VariadicType::kReal:
return sqlite_utils::CompareValuesAsc(arg_f.real_value,
arg_s.real_value);
case VariadicType::kString: {
const auto& f_str = storage_->GetString(arg_f.string_value);
const auto& s_str = storage_->GetString(arg_s.string_value);
return sqlite_utils::CompareValuesAsc(f_str, s_str);
}
}
} else if (arg_s.type == type_) {
return -1;
} else if (arg_f.type == type_) {
return 1;
}
return 0;
}
} // namespace trace_processor
} // namespace perfetto