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/thread_table.h" 18 19 #include "perfetto/base/logging.h" 20 #include "src/trace_processor/query_constraints.h" 21 #include "src/trace_processor/sqlite_utils.h" 22 23 namespace perfetto { 24 namespace trace_processor { 25 26 namespace { 27 28 using namespace sqlite_utils; 29 30 } // namespace 31 32 ThreadTable::ThreadTable(sqlite3*, const TraceStorage* storage) 33 : storage_(storage) {} 34 35 void ThreadTable::RegisterTable(sqlite3* db, const TraceStorage* storage) { 36 Table::Register<ThreadTable>(db, storage, "thread"); 37 } 38 39 base::Optional<Table::Schema> ThreadTable::Init(int, const char* const*) { 40 return Schema( 41 { 42 Table::Column(Column::kUtid, "utid", ColumnType::kInt), 43 Table::Column(Column::kUpid, "upid", ColumnType::kInt), 44 Table::Column(Column::kName, "name", ColumnType::kString), 45 Table::Column(Column::kTid, "tid", ColumnType::kInt), 46 Table::Column(Column::kStartTs, "start_ts", ColumnType::kLong), 47 }, 48 {Column::kUtid}); 49 } 50 51 std::unique_ptr<Table::Cursor> ThreadTable::CreateCursor() { 52 return std::unique_ptr<Table::Cursor>(new Cursor(this)); 53 } 54 55 int ThreadTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) { 56 info->estimated_cost = static_cast<uint32_t>(storage_->thread_count()); 57 58 // If the query has a constraint on the |utid| field, return a reduced cost 59 // because we can do that filter efficiently. 60 const auto& constraints = qc.constraints(); 61 for (const auto& cs : qc.constraints()) { 62 if (cs.iColumn == Column::kUtid) { 63 info->estimated_cost = IsOpEq(constraints.front().op) ? 1 : 10; 64 } 65 } 66 return SQLITE_OK; 67 } 68 69 ThreadTable::Cursor::Cursor(ThreadTable* table) 70 : Table::Cursor(table), storage_(table->storage_), table_(table) {} 71 72 int ThreadTable::Cursor::Filter(const QueryConstraints& qc, 73 sqlite3_value** argv) { 74 *this = Cursor(table_); 75 76 min = 0; 77 max = static_cast<uint32_t>(storage_->thread_count()) - 1; 78 desc = false; 79 current = min; 80 for (size_t j = 0; j < qc.constraints().size(); j++) { 81 const auto& cs = qc.constraints()[j]; 82 if (cs.iColumn == Column::kUtid) { 83 UniqueTid constraint_utid = 84 static_cast<UniqueTid>(sqlite3_value_int(argv[j])); 85 // Filter the range of utids that we are interested in, based on the 86 // constraints in the query. Everything between min and max (inclusive) 87 // will be returned. 88 if (IsOpEq(cs.op)) { 89 min = constraint_utid; 90 max = constraint_utid; 91 } else if (IsOpGe(cs.op) || IsOpGt(cs.op)) { 92 min = IsOpGt(cs.op) ? constraint_utid + 1 : constraint_utid; 93 } else if (IsOpLe(cs.op) || IsOpLt(cs.op)) { 94 max = IsOpLt(cs.op) ? constraint_utid - 1 : constraint_utid; 95 } 96 } 97 } 98 for (const auto& ob : qc.order_by()) { 99 if (ob.iColumn == Column::kUtid) { 100 desc = ob.desc; 101 current = desc ? max : min; 102 } 103 } 104 return SQLITE_OK; 105 } 106 107 int ThreadTable::Cursor::Column(sqlite3_context* context, int N) { 108 const auto& thread = storage_->GetThread(current); 109 switch (N) { 110 case Column::kUtid: { 111 sqlite3_result_int64(context, current); 112 break; 113 } 114 case Column::kUpid: { 115 if (thread.upid.has_value()) { 116 sqlite3_result_int64(context, thread.upid.value()); 117 } else { 118 sqlite3_result_null(context); 119 } 120 break; 121 } 122 case Column::kName: { 123 const auto& name = storage_->GetString(thread.name_id); 124 sqlite3_result_text(context, name.c_str(), -1, kSqliteStatic); 125 break; 126 } 127 case Column::kTid: { 128 sqlite3_result_int64(context, thread.tid); 129 break; 130 } 131 case Column::kStartTs: { 132 if (thread.start_ns != 0) { 133 sqlite3_result_int64(context, thread.start_ns); 134 } else { 135 sqlite3_result_null(context); 136 } 137 break; 138 } 139 default: { 140 PERFETTO_FATAL("Unknown column %d", N); 141 break; 142 } 143 } 144 return SQLITE_OK; 145 } 146 147 int ThreadTable::Cursor::Next() { 148 if (desc) { 149 --current; 150 } else { 151 ++current; 152 } 153 return SQLITE_OK; 154 } 155 156 int ThreadTable::Cursor::Eof() { 157 return desc ? current < min : current > max; 158 } 159 } // namespace trace_processor 160 } // namespace perfetto 161