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