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 "measure_table.h"
17 #include <cmath>
18
19 namespace SysTuning {
20 namespace TraceStreamer {
21 namespace {
22 enum Index { TYPE = 0, TS, VALUE, FILTER_ID };
23 }
MeasureTable(const TraceDataCache * dataCache)24 MeasureTable::MeasureTable(const TraceDataCache* dataCache) : TableBase(dataCache)
25 {
26 tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT"));
27 tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER"));
28 tableColumn_.push_back(TableBase::ColumnInfo("value", "INTEGER"));
29 tableColumn_.push_back(TableBase::ColumnInfo("filter_id", "INTEGER"));
30 tablePriKey_.push_back("ts");
31 tablePriKey_.push_back("filter_id");
32 }
33
~MeasureTable()34 MeasureTable::~MeasureTable() {}
35
CreateCursor()36 std::unique_ptr<TableBase::Cursor> MeasureTable::CreateCursor()
37 {
38 return std::make_unique<Cursor>(dataCache_, this);
39 }
40
Cursor(const TraceDataCache * dataCache,TableBase * table)41 MeasureTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
42 : TableBase::Cursor(
43 dataCache,
44 table,
45 static_cast<uint32_t>(table->name_ == "measure" || table->name_ == "_measure"
46 ? dataCache->GetConstMeasureData().Size()
47 : (table->name_ == "process_measure" || table->name_ == "_process_measure"
48 ? dataCache->GetConstProcessMeasureData().Size()
49 : dataCache->GetConstSysMemMeasureData().Size()))),
50 measureObj(table->name_ == "measure" || table->name_ == "_measure"
51 ? dataCache->GetConstMeasureData()
52 : (table->name_ == "process_measure" || table->name_ == "_process_measure"
53 ? dataCache->GetConstProcessMeasureData()
54 : dataCache->GetConstSysMemMeasureData()))
55 {
56 }
57
~Cursor()58 MeasureTable::Cursor::~Cursor() {}
59
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)60 void MeasureTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
61 {
62 constexpr double filterBaseCost = 1000.0; // set-up and tear-down
63 constexpr double indexCost = 2.0;
64 ei.estimatedCost = filterBaseCost;
65
66 auto rowCount = dataCache_->GetConstMeasureData().Size();
67 if (rowCount == 0 || rowCount == 1) {
68 ei.estimatedRows = rowCount;
69 ei.estimatedCost += indexCost * rowCount;
70 return;
71 }
72
73 double filterCost = 0.0;
74 auto constraints = fc.GetConstraints();
75 if (constraints.empty()) { // scan all rows
76 filterCost = rowCount;
77 } else {
78 FilterByConstraint(fc, filterCost, rowCount);
79 }
80 ei.estimatedCost += filterCost;
81 ei.estimatedRows = rowCount;
82 ei.estimatedCost += rowCount * indexCost;
83
84 ei.isOrdered = true;
85 auto orderbys = fc.GetOrderBys();
86 for (auto i = 0; i < orderbys.size(); i++) {
87 switch (orderbys[i].iColumn) {
88 case TS:
89 break;
90 default: // other columns can be sorted by SQLite
91 ei.isOrdered = false;
92 break;
93 }
94 }
95 }
96
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)97 void MeasureTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
98 {
99 auto fcConstraints = fc.GetConstraints();
100 for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
101 if (rowCount <= 1) {
102 // only one row or nothing, needn't filter by constraint
103 filterCost += rowCount;
104 break;
105 }
106 const auto& c = fcConstraints[i];
107 switch (c.col) {
108 case TS: {
109 auto oldRowCount = rowCount;
110 if (CanFilterSorted(c.op, rowCount)) {
111 fc.UpdateConstraint(i, true);
112 filterCost += log2(oldRowCount); // binary search
113 } else {
114 filterCost += oldRowCount;
115 }
116 break;
117 }
118 default: // other column
119 filterCost += rowCount; // scan all rows
120 break;
121 }
122 }
123 }
124
CanFilterSorted(const char op,size_t & rowCount) const125 bool MeasureTable::CanFilterSorted(const char op, size_t& rowCount) const
126 {
127 switch (op) {
128 case SQLITE_INDEX_CONSTRAINT_EQ:
129 rowCount = rowCount / log2(rowCount);
130 break;
131 case SQLITE_INDEX_CONSTRAINT_GT:
132 case SQLITE_INDEX_CONSTRAINT_GE:
133 case SQLITE_INDEX_CONSTRAINT_LE:
134 case SQLITE_INDEX_CONSTRAINT_LT:
135 rowCount = (rowCount >> 1);
136 break;
137 default:
138 return false;
139 }
140 return true;
141 }
142
Filter(const FilterConstraints & fc,sqlite3_value ** argv)143 int MeasureTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
144 {
145 // reset
146 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
147
148 if (rowCount_ <= 0) {
149 return SQLITE_OK;
150 }
151 auto& cs = fc.GetConstraints();
152 for (size_t i = 0; i < cs.size(); i++) {
153 const auto& c = cs[i];
154 switch (c.col) {
155 case TS:
156 FilterTS(c.op, argv[i], measureObj.TimeStamData());
157 break;
158 case FILTER_ID:
159 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[i])),
160 measureObj.FilterIdData());
161 break;
162 default:
163 break;
164 }
165 }
166
167 auto orderbys = fc.GetOrderBys();
168 for (auto i = orderbys.size(); i > 0;) {
169 i--;
170 switch (orderbys[i].iColumn) {
171 case TS:
172 indexMap_->SortBy(orderbys[i].desc);
173 break;
174 case FILTER_ID:
175 indexMap_->SortBy(orderbys[i].desc);
176 break;
177 default:
178 break;
179 }
180 }
181
182 return SQLITE_OK;
183 }
184
Column(int column) const185 int MeasureTable::Cursor::Column(int column) const
186 {
187 switch (column) {
188 case TYPE:
189 sqlite3_result_text(context_, "measure", STR_DEFAULT_LEN, nullptr);
190 break;
191 case TS:
192 sqlite3_result_int64(context_, static_cast<int64_t>(measureObj.TimeStamData()[CurrentRow()]));
193 break;
194 case VALUE:
195 sqlite3_result_int64(context_, static_cast<int64_t>(measureObj.ValuesData()[CurrentRow()]));
196 break;
197 case FILTER_ID:
198 sqlite3_result_int64(context_, static_cast<int32_t>(measureObj.FilterIdData()[CurrentRow()]));
199 break;
200 default:
201 TS_LOGF("Unregistered column : %d", column);
202 break;
203 }
204 return SQLITE_OK;
205 }
206 } // namespace TraceStreamer
207 } // namespace SysTuning
208