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