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