• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ThreadTable(sqlite3 *,const TraceStorage * storage)32 ThreadTable::ThreadTable(sqlite3*, const TraceStorage* storage)
33     : storage_(storage) {}
34 
RegisterTable(sqlite3 * db,const TraceStorage * storage)35 void ThreadTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
36   Table::Register<ThreadTable>(db, storage, "thread");
37 }
38 
Init(int,const char * const *)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 
CreateCursor()51 std::unique_ptr<Table::Cursor> ThreadTable::CreateCursor() {
52   return std::unique_ptr<Table::Cursor>(new Cursor(this));
53 }
54 
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)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 
Cursor(ThreadTable * table)69 ThreadTable::Cursor::Cursor(ThreadTable* table)
70     : Table::Cursor(table), storage_(table->storage_), table_(table) {}
71 
Filter(const QueryConstraints & qc,sqlite3_value ** argv)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 
Column(sqlite3_context * context,int N)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 
Next()147 int ThreadTable::Cursor::Next() {
148   if (desc) {
149     --current;
150   } else {
151     ++current;
152   }
153   return SQLITE_OK;
154 }
155 
Eof()156 int ThreadTable::Cursor::Eof() {
157   return desc ? current < min : current > max;
158 }
159 }  // namespace trace_processor
160 }  // namespace perfetto
161