Home | History | Annotate | Download | only in trace_processor
      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