• 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/window_operator_table.h"
18 
19 #include "src/trace_processor/sqlite_utils.h"
20 
21 namespace perfetto {
22 namespace trace_processor {
23 
24 namespace {
25 using namespace sqlite_utils;
26 }  // namespace
27 
WindowOperatorTable(sqlite3 *,const TraceStorage *)28 WindowOperatorTable::WindowOperatorTable(sqlite3*, const TraceStorage*) {}
29 
RegisterTable(sqlite3 * db,const TraceStorage * storage)30 void WindowOperatorTable::RegisterTable(sqlite3* db,
31                                         const TraceStorage* storage) {
32   Table::Register<WindowOperatorTable>(db, storage, "window", true);
33 }
34 
Init(int,const char * const *)35 base::Optional<Table::Schema> WindowOperatorTable::Init(int,
36                                                         const char* const*) {
37   const bool kHidden = true;
38   return Schema(
39       {
40           // These are the operator columns:
41           Table::Column(Column::kRowId, "rowid", ColumnType::kLong, kHidden),
42           Table::Column(Column::kQuantum, "quantum", ColumnType::kLong,
43                         kHidden),
44           Table::Column(Column::kWindowStart, "window_start", ColumnType::kLong,
45                         kHidden),
46           Table::Column(Column::kWindowDur, "window_dur", ColumnType::kLong,
47                         kHidden),
48           // These are the ouput columns:
49           Table::Column(Column::kTs, "ts", ColumnType::kLong),
50           Table::Column(Column::kDuration, "dur", ColumnType::kLong),
51           Table::Column(Column::kQuantumTs, "quantum_ts", ColumnType::kLong),
52       },
53       {Column::kRowId});
54 }
55 
CreateCursor()56 std::unique_ptr<Table::Cursor> WindowOperatorTable::CreateCursor() {
57   return std::unique_ptr<Table::Cursor>(new Cursor(this));
58 }
59 
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)60 int WindowOperatorTable::BestIndex(const QueryConstraints& qc,
61                                    BestIndexInfo* info) {
62   // Remove ordering on timestamp if it is the only ordering as we are already
63   // sorted on TS. This makes span joining significantly faster.
64   if (qc.order_by().size() == 1 && qc.order_by()[0].iColumn == Column::kTs &&
65       !qc.order_by()[0].desc) {
66     info->order_by_consumed = true;
67   }
68   return SQLITE_OK;
69 }
70 
Update(int argc,sqlite3_value ** argv,sqlite3_int64 *)71 int WindowOperatorTable::Update(int argc,
72                                 sqlite3_value** argv,
73                                 sqlite3_int64*) {
74   // We only support updates to ts and dur. Disallow deletes (argc == 1) and
75   // inserts (argv[0] == null).
76   if (argc < 2 || sqlite3_value_type(argv[0]) == SQLITE_NULL)
77     return SQLITE_READONLY;
78 
79   int64_t new_quantum = sqlite3_value_int64(argv[3]);
80   int64_t new_start = sqlite3_value_int64(argv[4]);
81   int64_t new_dur = sqlite3_value_int64(argv[5]);
82   if (new_dur == 0) {
83     auto* err = sqlite3_mprintf("Cannot set duration of window table to zero.");
84     SetErrorMessage(err);
85     return SQLITE_ERROR;
86   }
87 
88   quantum_ = new_quantum;
89   window_start_ = new_start;
90   window_dur_ = new_dur;
91 
92   return SQLITE_OK;
93 }
94 
Cursor(WindowOperatorTable * table)95 WindowOperatorTable::Cursor::Cursor(WindowOperatorTable* table)
96     : Table::Cursor(table), table_(table) {}
97 
Filter(const QueryConstraints & qc,sqlite3_value ** argv)98 int WindowOperatorTable::Cursor::Filter(const QueryConstraints& qc,
99                                         sqlite3_value** argv) {
100   *this = Cursor(table_);
101   window_start_ = table_->window_start_;
102   window_end_ = table_->window_start_ + table_->window_dur_;
103   step_size_ = table_->quantum_ == 0 ? table_->window_dur_ : table_->quantum_;
104 
105   current_ts_ = window_start_;
106 
107   // Set return first if there is a equals constraint on the row id asking to
108   // return the first row.
109   bool return_first = qc.constraints().size() == 1 &&
110                       qc.constraints()[0].iColumn == Column::kRowId &&
111                       IsOpEq(qc.constraints()[0].op) &&
112                       sqlite3_value_int(argv[0]) == 0;
113   if (return_first) {
114     filter_type_ = FilterType::kReturnFirst;
115   } else {
116     filter_type_ = FilterType::kReturnAll;
117   }
118   return SQLITE_OK;
119 }
120 
Column(sqlite3_context * context,int N)121 int WindowOperatorTable::Cursor::Column(sqlite3_context* context, int N) {
122   switch (N) {
123     case Column::kQuantum: {
124       sqlite3_result_int64(context,
125                            static_cast<sqlite_int64>(table_->quantum_));
126       break;
127     }
128     case Column::kWindowStart: {
129       sqlite3_result_int64(context,
130                            static_cast<sqlite_int64>(table_->window_start_));
131       break;
132     }
133     case Column::kWindowDur: {
134       sqlite3_result_int(context, static_cast<int>(table_->window_dur_));
135       break;
136     }
137     case Column::kTs: {
138       sqlite3_result_int64(context, static_cast<sqlite_int64>(current_ts_));
139       break;
140     }
141     case Column::kDuration: {
142       sqlite3_result_int64(context, static_cast<sqlite_int64>(step_size_));
143       break;
144     }
145     case Column::kQuantumTs: {
146       sqlite3_result_int64(context, static_cast<sqlite_int64>(quantum_ts_));
147       break;
148     }
149     case Column::kRowId: {
150       sqlite3_result_int64(context, static_cast<sqlite_int64>(row_id_));
151       break;
152     }
153     default: {
154       PERFETTO_FATAL("Unknown column %d", N);
155       break;
156     }
157   }
158   return SQLITE_OK;
159 }
160 
Next()161 int WindowOperatorTable::Cursor::Next() {
162   switch (filter_type_) {
163     case FilterType::kReturnFirst:
164       current_ts_ = window_end_;
165       break;
166     case FilterType::kReturnAll:
167       current_ts_ += step_size_;
168       quantum_ts_++;
169       break;
170   }
171   row_id_++;
172   return SQLITE_OK;
173 }
174 
Eof()175 int WindowOperatorTable::Cursor::Eof() {
176   return current_ts_ >= window_end_;
177 }
178 
179 }  // namespace trace_processor
180 }  // namespace perfetto
181