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 28 WindowOperatorTable::WindowOperatorTable(sqlite3*, const TraceStorage*) {} 29 30 void WindowOperatorTable::RegisterTable(sqlite3* db, 31 const TraceStorage* storage) { 32 Table::Register<WindowOperatorTable>(db, storage, "window", true); 33 } 34 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 56 std::unique_ptr<Table::Cursor> WindowOperatorTable::CreateCursor() { 57 return std::unique_ptr<Table::Cursor>(new Cursor(this)); 58 } 59 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 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 95 WindowOperatorTable::Cursor::Cursor(WindowOperatorTable* table) 96 : Table::Cursor(table), table_(table) {} 97 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 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 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 175 int WindowOperatorTable::Cursor::Eof() { 176 return current_ts_ >= window_end_; 177 } 178 179 } // namespace trace_processor 180 } // namespace perfetto 181