/* * 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/thread_table.h" #include "perfetto/base/logging.h" #include "src/trace_processor/query_constraints.h" #include "src/trace_processor/sqlite_utils.h" namespace perfetto { namespace trace_processor { namespace { using namespace sqlite_utils; } // namespace ThreadTable::ThreadTable(sqlite3*, const TraceStorage* storage) : storage_(storage) {} void ThreadTable::RegisterTable(sqlite3* db, const TraceStorage* storage) { Table::Register(db, storage, "thread"); } base::Optional ThreadTable::Init(int, const char* const*) { return Schema( { Table::Column(Column::kUtid, "utid", ColumnType::kInt), Table::Column(Column::kUpid, "upid", ColumnType::kInt), Table::Column(Column::kName, "name", ColumnType::kString), Table::Column(Column::kTid, "tid", ColumnType::kInt), Table::Column(Column::kStartTs, "start_ts", ColumnType::kLong), }, {Column::kUtid}); } std::unique_ptr ThreadTable::CreateCursor() { return std::unique_ptr(new Cursor(this)); } int ThreadTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) { info->estimated_cost = static_cast(storage_->thread_count()); // If the query has a constraint on the |utid| field, return a reduced cost // because we can do that filter efficiently. const auto& constraints = qc.constraints(); for (const auto& cs : qc.constraints()) { if (cs.iColumn == Column::kUtid) { info->estimated_cost = IsOpEq(constraints.front().op) ? 1 : 10; } } return SQLITE_OK; } ThreadTable::Cursor::Cursor(ThreadTable* table) : Table::Cursor(table), storage_(table->storage_), table_(table) {} int ThreadTable::Cursor::Filter(const QueryConstraints& qc, sqlite3_value** argv) { *this = Cursor(table_); min = 0; max = static_cast(storage_->thread_count()) - 1; desc = false; current = min; for (size_t j = 0; j < qc.constraints().size(); j++) { const auto& cs = qc.constraints()[j]; if (cs.iColumn == Column::kUtid) { UniqueTid constraint_utid = static_cast(sqlite3_value_int(argv[j])); // Filter the range of utids that we are interested in, based on the // constraints in the query. Everything between min and max (inclusive) // will be returned. if (IsOpEq(cs.op)) { min = constraint_utid; max = constraint_utid; } else if (IsOpGe(cs.op) || IsOpGt(cs.op)) { min = IsOpGt(cs.op) ? constraint_utid + 1 : constraint_utid; } else if (IsOpLe(cs.op) || IsOpLt(cs.op)) { max = IsOpLt(cs.op) ? constraint_utid - 1 : constraint_utid; } } } for (const auto& ob : qc.order_by()) { if (ob.iColumn == Column::kUtid) { desc = ob.desc; current = desc ? max : min; } } return SQLITE_OK; } int ThreadTable::Cursor::Column(sqlite3_context* context, int N) { const auto& thread = storage_->GetThread(current); switch (N) { case Column::kUtid: { sqlite3_result_int64(context, current); break; } case Column::kUpid: { if (thread.upid.has_value()) { sqlite3_result_int64(context, thread.upid.value()); } else { sqlite3_result_null(context); } break; } case Column::kName: { const auto& name = storage_->GetString(thread.name_id); sqlite3_result_text(context, name.c_str(), -1, kSqliteStatic); break; } case Column::kTid: { sqlite3_result_int64(context, thread.tid); break; } case Column::kStartTs: { if (thread.start_ns != 0) { sqlite3_result_int64(context, thread.start_ns); } else { sqlite3_result_null(context); } break; } default: { PERFETTO_FATAL("Unknown column %d", N); break; } } return SQLITE_OK; } int ThreadTable::Cursor::Next() { if (desc) { --current; } else { ++current; } return SQLITE_OK; } int ThreadTable::Cursor::Eof() { return desc ? current < min : current > max; } } // namespace trace_processor } // namespace perfetto