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
ProcessTable(sqlite3 *,const TraceStorage * storage)32 ProcessTable::ProcessTable(sqlite3*, const TraceStorage* storage)
33 : storage_(storage) {}
34
RegisterTable(sqlite3 * db,const TraceStorage * storage)35 void ProcessTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
36 Table::Register<ProcessTable>(db, storage, "process");
37 }
38
Init(int,const char * const *)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
CreateCursor()50 std::unique_ptr<Table::Cursor> ProcessTable::CreateCursor() {
51 return std::unique_ptr<Table::Cursor>(new Cursor(this));
52 }
53
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)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
Cursor(ProcessTable * table)67 ProcessTable::Cursor::Cursor(ProcessTable* table)
68 : Table::Cursor(table), storage_(table->storage_) {}
69
Filter(const QueryConstraints & qc,sqlite3_value ** argv)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
Column(sqlite3_context * context,int N)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
Next()136 int ProcessTable::Cursor::Next() {
137 if (desc) {
138 --current;
139 } else {
140 ++current;
141 }
142 return SQLITE_OK;
143 }
144
Eof()145 int ProcessTable::Cursor::Eof() {
146 return desc ? current < min : current > max;
147 }
148
149 } // namespace trace_processor
150 } // namespace perfetto
151