1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "clock_event_filter_table.h"
17
18 #include <cmath>
19
20 namespace SysTuning {
21 namespace TraceStreamer {
22 namespace {
23 enum Index { ID = 0, TYPE, NAME, CPU };
24 }
ClockEventFilterTable(const TraceDataCache * dataCache)25 ClockEventFilterTable::ClockEventFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache)
26 {
27 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
28 tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT"));
29 tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
30 tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER"));
31 tablePriKey_.push_back("id");
32 }
33
~ClockEventFilterTable()34 ClockEventFilterTable::~ClockEventFilterTable() {}
35
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)36 void ClockEventFilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
37 {
38 constexpr double filterBaseCost = 1000.0; // set-up and tear-down
39 constexpr double indexCost = 2.0;
40 ei.estimatedCost = filterBaseCost;
41
42 auto rowCount = dataCache_->GetConstClockEventFilterData().Size();
43 if (rowCount == 0 || rowCount == 1) {
44 ei.estimatedRows = rowCount;
45 ei.estimatedCost += indexCost * rowCount;
46 return;
47 }
48
49 double filterCost = 0.0;
50 auto constraints = fc.GetConstraints();
51 if (constraints.empty()) { // scan all rows
52 filterCost = rowCount;
53 } else {
54 FilterByConstraint(fc, filterCost, rowCount);
55 }
56 ei.estimatedCost += filterCost;
57 ei.estimatedRows = rowCount;
58 ei.estimatedCost += rowCount * indexCost;
59
60 ei.isOrdered = true;
61 auto orderbys = fc.GetOrderBys();
62 for (auto i = 0; i < orderbys.size(); i++) {
63 switch (orderbys[i].iColumn) {
64 case ID:
65 break;
66 default: // other columns can be sorted by SQLite
67 ei.isOrdered = false;
68 break;
69 }
70 }
71 }
72
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)73 void ClockEventFilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
74 {
75 auto fcConstraints = fc.GetConstraints();
76 for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
77 if (rowCount <= 1) {
78 // only one row or nothing, needn't filter by constraint
79 filterCost += rowCount;
80 break;
81 }
82 const auto& c = fcConstraints[i];
83 switch (c.col) {
84 case ID: {
85 auto oldRowCount = rowCount;
86 if (CanFilterSorted(c.op, rowCount)) {
87 fc.UpdateConstraint(i, true);
88 filterCost += log2(oldRowCount); // binary search
89 } else {
90 filterCost += oldRowCount;
91 }
92 break;
93 }
94 default: // other column
95 filterCost += rowCount; // scan all rows
96 break;
97 }
98 }
99 }
100
CanFilterSorted(const char op,size_t & rowCount) const101 bool ClockEventFilterTable::CanFilterSorted(const char op, size_t& rowCount) const
102 {
103 switch (op) {
104 case SQLITE_INDEX_CONSTRAINT_EQ:
105 rowCount = rowCount / log2(rowCount);
106 break;
107 case SQLITE_INDEX_CONSTRAINT_GT:
108 case SQLITE_INDEX_CONSTRAINT_GE:
109 case SQLITE_INDEX_CONSTRAINT_LE:
110 case SQLITE_INDEX_CONSTRAINT_LT:
111 rowCount = (rowCount >> 1);
112 break;
113 default:
114 return false;
115 }
116 return true;
117 }
118
CreateCursor()119 std::unique_ptr<TableBase::Cursor> ClockEventFilterTable::CreateCursor()
120 {
121 return std::make_unique<Cursor>(dataCache_, this);
122 }
123
Cursor(const TraceDataCache * dataCache,TableBase * table)124 ClockEventFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
125 : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstClockEventFilterData().Size()))
126 {
127 }
128
~Cursor()129 ClockEventFilterTable::Cursor::~Cursor() {}
130
Filter(const FilterConstraints & fc,sqlite3_value ** argv)131 int ClockEventFilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
132 {
133 // reset indexMap_
134 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
135
136 if (rowCount_ <= 0) {
137 return SQLITE_OK;
138 }
139
140 auto& cs = fc.GetConstraints();
141 for (size_t i = 0; i < cs.size(); i++) {
142 const auto& c = cs[i];
143 switch (c.col) {
144 case ID:
145 FilterSorted(c.col, c.op, argv[i]);
146 break;
147 default:
148 break;
149 }
150 }
151
152 auto orderbys = fc.GetOrderBys();
153 for (auto i = orderbys.size(); i > 0;) {
154 i--;
155 switch (orderbys[i].iColumn) {
156 case ID:
157 indexMap_->SortBy(orderbys[i].desc);
158 break;
159 default:
160 break;
161 }
162 }
163
164 return SQLITE_OK;
165 }
166
Column(int col) const167 int ClockEventFilterTable::Cursor::Column(int col) const
168 {
169 switch (col) {
170 case ID:
171 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(
172 dataCache_->GetConstClockEventFilterData().IdsData()[CurrentRow()]));
173 break;
174 case TYPE: {
175 size_t typeId = static_cast<size_t>(dataCache_->GetConstClockEventFilterData().TypesData()[CurrentRow()]);
176 sqlite3_result_text(context_, dataCache_->GetDataFromDict(typeId).c_str(), STR_DEFAULT_LEN, nullptr);
177 break;
178 }
179 case NAME: {
180 size_t strId = static_cast<size_t>(dataCache_->GetConstClockEventFilterData().NamesData()[CurrentRow()]);
181 sqlite3_result_text(context_, dataCache_->GetDataFromDict(strId).c_str(), STR_DEFAULT_LEN, nullptr);
182 break;
183 }
184 case CPU:
185 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(
186 dataCache_->GetConstClockEventFilterData().CpusData()[CurrentRow()]));
187 break;
188 default:
189 TS_LOGF("Unregistered column : %d", col);
190 break;
191 }
192 return SQLITE_OK;
193 }
194
FilterSorted(int col,unsigned char op,sqlite3_value * argv)195 void ClockEventFilterTable::Cursor::FilterSorted(int col, unsigned char op, sqlite3_value* argv)
196 {
197 auto type = sqlite3_value_type(argv);
198 if (type != SQLITE_INTEGER) {
199 // other type consider it NULL, filter out nothing
200 indexMap_->Intersect(0, 0);
201 return;
202 }
203
204 switch (col) {
205 case ID: {
206 auto v = static_cast<uint64_t>(sqlite3_value_int64(argv));
207 auto getValue = [](const uint32_t& row) {
208 return row;
209 };
210 switch (op) {
211 case SQLITE_INDEX_CONSTRAINT_EQ:
212 indexMap_->IntersectabcEqual(
213 dataCache_->GetConstClockEventFilterData().IdsData(), v, getValue);
214 break;
215 case SQLITE_INDEX_CONSTRAINT_GT:
216 v++;
217 case SQLITE_INDEX_CONSTRAINT_GE: {
218 indexMap_->IntersectGreaterEqual(
219 dataCache_->GetConstClockEventFilterData().IdsData(), v, getValue);
220 break;
221 }
222 case SQLITE_INDEX_CONSTRAINT_LE:
223 v++;
224 case SQLITE_INDEX_CONSTRAINT_LT: {
225 indexMap_->IntersectLessEqual(
226 dataCache_->GetConstClockEventFilterData().IdsData(), v, getValue);
227 break;
228 }
229 default:
230 break;
231 } // end of switch (op)
232 } // end of case TS
233 default:
234 // can't filter, all rows
235 break;
236 }
237 }
238 } // namespace TraceStreamer
239 } // namespace SysTuning
240