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