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 "cpu_measure_filter_table.h"
17
18 #include <cmath>
19
20 #include "log.h"
21
22 namespace SysTuning {
23 namespace TraceStreamer {
24 namespace {
25 enum Index { ID = 0, TYPE, NAME, CPU };
26 }
CpuMeasureFilterTable(const TraceDataCache * dataCache)27 CpuMeasureFilterTable::CpuMeasureFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache)
28 {
29 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
30 tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT"));
31 tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
32 tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER"));
33 tablePriKey_.push_back("id");
34 }
35
~CpuMeasureFilterTable()36 CpuMeasureFilterTable::~CpuMeasureFilterTable() {}
37
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)38 void CpuMeasureFilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
39 {
40 constexpr double filterBaseCost = 1000.0; // set-up and tear-down
41 constexpr double indexCost = 2.0;
42 ei.estimatedCost = filterBaseCost;
43
44 auto rowCount = dataCache_->GetConstCpuMeasureData().Size();
45 if (rowCount == 0 || rowCount == 1) {
46 ei.estimatedRows = rowCount;
47 ei.estimatedCost += indexCost * rowCount;
48 return;
49 }
50
51 double filterCost = 0.0;
52 auto constraints = fc.GetConstraints();
53 if (constraints.empty()) { // scan all rows
54 filterCost = rowCount;
55 } else {
56 FilterByConstraint(fc, filterCost, rowCount);
57 }
58 ei.estimatedCost += filterCost;
59 ei.estimatedRows = rowCount;
60 ei.estimatedCost += rowCount * indexCost;
61
62 ei.isOrdered = true;
63 auto orderbys = fc.GetOrderBys();
64 for (auto i = 0; i < orderbys.size(); i++) {
65 switch (orderbys[i].iColumn) {
66 case ID:
67 break;
68 default: // other columns can be sorted by SQLite
69 ei.isOrdered = false;
70 break;
71 }
72 }
73 }
74
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)75 void CpuMeasureFilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
76 {
77 auto fcConstraints = fc.GetConstraints();
78 for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
79 if (rowCount <= 1) {
80 // only one row or nothing, needn't filter by constraint
81 filterCost += rowCount;
82 break;
83 }
84 const auto& c = fcConstraints[i];
85 switch (c.col) {
86 case ID: {
87 auto oldRowCount = rowCount;
88 if (CanFilterSorted(c.op, rowCount)) {
89 fc.UpdateConstraint(i, true);
90 filterCost += log2(oldRowCount); // binary search
91 } else {
92 filterCost += oldRowCount;
93 }
94 break;
95 }
96 default: // other column
97 filterCost += rowCount; // scan all rows
98 break;
99 }
100 }
101 }
102
CanFilterSorted(const char op,size_t & rowCount) const103 bool CpuMeasureFilterTable::CanFilterSorted(const char op, size_t& rowCount) const
104 {
105 switch (op) {
106 case SQLITE_INDEX_CONSTRAINT_EQ:
107 rowCount = rowCount / log2(rowCount);
108 break;
109 case SQLITE_INDEX_CONSTRAINT_GT:
110 case SQLITE_INDEX_CONSTRAINT_GE:
111 case SQLITE_INDEX_CONSTRAINT_LE:
112 case SQLITE_INDEX_CONSTRAINT_LT:
113 rowCount = (rowCount >> 1);
114 break;
115 default:
116 return false;
117 }
118 return true;
119 }
120
CreateCursor()121 std::unique_ptr<TableBase::Cursor> CpuMeasureFilterTable::CreateCursor()
122 {
123 return std::make_unique<Cursor>(dataCache_, this);
124 }
125
Cursor(const TraceDataCache * dataCache,TableBase * table)126 CpuMeasureFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
127 : TableBase::Cursor(dataCache, table,
128 static_cast<uint32_t>(dataCache->GetConstCpuMeasureData().Size())),
129 cpuMeasureObj_(dataCache->GetConstCpuMeasureData())
130 {
131 }
132
~Cursor()133 CpuMeasureFilterTable::Cursor::~Cursor() {}
134
Filter(const FilterConstraints & fc,sqlite3_value ** argv)135 int CpuMeasureFilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
136 {
137 // reset indexMap_
138 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
139
140 if (rowCount_ <= 0) {
141 return SQLITE_OK;
142 }
143
144 auto& cs = fc.GetConstraints();
145 for (size_t i = 0; i < cs.size(); i++) {
146 const auto& c = cs[i];
147 switch (c.col) {
148 case ID:
149 FilterSorted(c.col, c.op, argv[i]);
150 break;
151 case CPU:
152 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[i])), cpuMeasureObj_.CpuData());
153 break;
154 default:
155 break;
156 }
157 }
158
159 auto orderbys = fc.GetOrderBys();
160 for (auto i = orderbys.size(); i > 0;) {
161 i--;
162 switch (orderbys[i].iColumn) {
163 case ID:
164 indexMap_->SortBy(orderbys[i].desc);
165 break;
166 default:
167 break;
168 }
169 }
170
171 return SQLITE_OK;
172 }
173
Column(int column) const174 int CpuMeasureFilterTable::Cursor::Column(int column) const
175 {
176 switch (column) {
177 case ID:
178 sqlite3_result_int64(context_, static_cast<int64_t>(cpuMeasureObj_.IdsData()[CurrentRow()]));
179 break;
180 case TYPE:
181 sqlite3_result_text(context_, "cpu_measure_filter", STR_DEFAULT_LEN, nullptr);
182 break;
183 case NAME: {
184 const std::string& str =
185 dataCache_->GetDataFromDict(static_cast<size_t>(cpuMeasureObj_.NameData()[CurrentRow()]));
186 sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr);
187 break;
188 }
189 case CPU:
190 sqlite3_result_int64(context_, static_cast<int32_t>(cpuMeasureObj_.CpuData()[CurrentRow()]));
191 break;
192 default:
193 TS_LOGF("Unregistered column : %d", column);
194 break;
195 }
196 return SQLITE_OK;
197 }
198
FilterSorted(int col,unsigned char op,sqlite3_value * argv)199 void CpuMeasureFilterTable::Cursor::FilterSorted(int col, unsigned char op, sqlite3_value* argv)
200 {
201 auto type = sqlite3_value_type(argv);
202 if (type != SQLITE_INTEGER) {
203 // other type consider it NULL, filter out nothing
204 indexMap_->Intersect(0, 0);
205 return;
206 }
207
208 switch (col) {
209 case ID: {
210 auto v = static_cast<uint64_t>(sqlite3_value_int64(argv));
211 auto getValue = [](const uint32_t& row) {
212 return row;
213 };
214 switch (op) {
215 case SQLITE_INDEX_CONSTRAINT_EQ:
216 indexMap_->IntersectabcEqual(cpuMeasureObj_.IdsData(), v, getValue);
217 break;
218 case SQLITE_INDEX_CONSTRAINT_GT:
219 v++;
220 case SQLITE_INDEX_CONSTRAINT_GE: {
221 indexMap_->IntersectGreaterEqual(cpuMeasureObj_.IdsData(), v, getValue);
222 break;
223 }
224 case SQLITE_INDEX_CONSTRAINT_LE:
225 v++;
226 case SQLITE_INDEX_CONSTRAINT_LT: {
227 indexMap_->IntersectLessEqual(cpuMeasureObj_.IdsData(), v, getValue);
228 break;
229 }
230 default:
231 break;
232 } // end of switch (op)
233 } // end of case TS
234 default:
235 // can't filter, all rows
236 break;
237 }
238 }
239 } // namespace TraceStreamer
240 } // namespace SysTuning
241