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 "sched_slice_table.h"
17
18 #include <cmath>
19
20 namespace SysTuning {
21 namespace TraceStreamer {
22 namespace {
23 enum Index { ID = 0, TYPE, TS, DUR, TS_END, CPU, INTERNAL_TID, INTERNAL_PID, END_STATE, PRIORITY };
24 }
SchedSliceTable(const TraceDataCache * dataCache)25 SchedSliceTable::SchedSliceTable(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("ts", "INTEGER"));
30 tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
31 tableColumn_.push_back(TableBase::ColumnInfo("ts_end", "INTEGER"));
32 tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER"));
33 tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER"));
34 tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
35 tableColumn_.push_back(TableBase::ColumnInfo("end_state", "TEXT"));
36 tableColumn_.push_back(TableBase::ColumnInfo("priority", "INTEGER"));
37 tablePriKey_.push_back("id");
38 }
39
~SchedSliceTable()40 SchedSliceTable::~SchedSliceTable() {}
41
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)42 void SchedSliceTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
43 {
44 constexpr double filterBaseCost = 1000.0; // set-up and tear-down
45 constexpr double indexCost = 2.0;
46 ei.estimatedCost = filterBaseCost;
47
48 auto rowCount = dataCache_->GetConstSchedSliceData().Size();
49 if (rowCount == 0 || rowCount == 1) {
50 ei.estimatedRows = rowCount;
51 ei.estimatedCost += indexCost * rowCount;
52 return;
53 }
54
55 double filterCost = 0.0;
56 auto constraints = fc.GetConstraints();
57 if (constraints.empty()) { // scan all rows
58 filterCost = rowCount;
59 } else {
60 FilterByConstraint(fc, filterCost, rowCount);
61 }
62 ei.estimatedCost += filterCost;
63 ei.estimatedRows = rowCount;
64 ei.estimatedCost += rowCount * indexCost;
65
66 ei.isOrdered = true;
67 auto orderbys = fc.GetOrderBys();
68 for (auto i = 0; i < orderbys.size(); i++) {
69 switch (orderbys[i].iColumn) {
70 case ID:
71 case TS:
72 break;
73 default: // other columns can be sorted by SQLite
74 ei.isOrdered = false;
75 break;
76 }
77 }
78 }
79
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)80 void SchedSliceTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
81 {
82 auto fcConstraints = fc.GetConstraints();
83 for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
84 if (rowCount <= 1) {
85 // only one row or nothing, needn't filter by constraint
86 filterCost += rowCount;
87 break;
88 }
89 const auto& c = fcConstraints[i];
90 switch (c.col) {
91 case ID: {
92 if (CanFilterId(c.op, rowCount)) {
93 fc.UpdateConstraint(i, true);
94 filterCost += 1; // id can position by 1 step
95 } else {
96 filterCost += rowCount; // scan all rows
97 }
98 break;
99 }
100 case TS: {
101 auto oldRowCount = rowCount;
102 if (CanFilterSorted(c.op, rowCount)) {
103 fc.UpdateConstraint(i, true);
104 filterCost += log2(oldRowCount); // binary search
105 } else {
106 filterCost += oldRowCount;
107 }
108 break;
109 }
110 default: // other column
111 filterCost += rowCount; // scan all rows
112 break;
113 }
114 }
115 }
116
CanFilterId(const char op,size_t & rowCount)117 bool SchedSliceTable::CanFilterId(const char op, size_t& rowCount)
118 {
119 switch (op) {
120 case SQLITE_INDEX_CONSTRAINT_EQ:
121 rowCount = 1;
122 break;
123 case SQLITE_INDEX_CONSTRAINT_GT:
124 case SQLITE_INDEX_CONSTRAINT_GE:
125 case SQLITE_INDEX_CONSTRAINT_LE:
126 case SQLITE_INDEX_CONSTRAINT_LT:
127 // assume filter out a half of rows
128 rowCount = (rowCount >> 1);
129 break;
130 default:
131 return false;
132 }
133 return true;
134 }
135
CanFilterSorted(const char op,size_t & rowCount) const136 bool SchedSliceTable::CanFilterSorted(const char op, size_t& rowCount) const
137 {
138 switch (op) {
139 case SQLITE_INDEX_CONSTRAINT_EQ:
140 rowCount = rowCount / log2(rowCount);
141 break;
142 case SQLITE_INDEX_CONSTRAINT_GT:
143 case SQLITE_INDEX_CONSTRAINT_GE:
144 case SQLITE_INDEX_CONSTRAINT_LE:
145 case SQLITE_INDEX_CONSTRAINT_LT:
146 rowCount = (rowCount >> 1);
147 break;
148 default:
149 return false;
150 }
151 return true;
152 }
153
CreateCursor()154 std::unique_ptr<TableBase::Cursor> SchedSliceTable::CreateCursor()
155 {
156 return std::make_unique<Cursor>(dataCache_, this);
157 }
158
Cursor(const TraceDataCache * dataCache,TableBase * table)159 SchedSliceTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
160 : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstSchedSliceData().Size())),
161 schedSliceObj_(dataCache->GetConstSchedSliceData())
162 {
163 }
164
~Cursor()165 SchedSliceTable::Cursor::~Cursor() {}
166
Filter(const FilterConstraints & fc,sqlite3_value ** argv)167 int SchedSliceTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
168 {
169 // reset indexMap_
170 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
171
172 if (rowCount_ <= 0) {
173 return SQLITE_OK;
174 }
175
176 auto& cs = fc.GetConstraints();
177 for (size_t i = 0; i < cs.size(); i++) {
178 const auto& c = cs[i];
179 switch (c.col) {
180 case ID:
181 FilterId(c.op, argv[i]);
182 break;
183 case TS:
184 FilterTS(c.op, argv[i], schedSliceObj_.TimeStamData());
185 break;
186 case CPU:
187 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[i])), schedSliceObj_.CpusData());
188 break;
189 case INTERNAL_TID:
190 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[i])),
191 schedSliceObj_.InternalTidsData());
192 break;
193 case INTERNAL_PID:
194 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[i])),
195 schedSliceObj_.InternalPidsData());
196 break;
197 case DUR:
198 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[i])),
199 schedSliceObj_.DursData());
200 break;
201 default:
202 break;
203 }
204 }
205
206 auto orderbys = fc.GetOrderBys();
207 for (auto i = orderbys.size(); i > 0;) {
208 i--;
209 switch (orderbys[i].iColumn) {
210 case ID:
211 case TS:
212 indexMap_->SortBy(orderbys[i].desc);
213 break;
214 default:
215 break;
216 }
217 }
218
219 return SQLITE_OK;
220 }
221
Column(int col) const222 int SchedSliceTable::Cursor::Column(int col) const
223 {
224 switch (col) {
225 case ID:
226 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(CurrentRow()));
227 break;
228 case TYPE:
229 sqlite3_result_text(context_, "sched_slice", STR_DEFAULT_LEN, nullptr);
230 break;
231 case TS:
232 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.TimeStamData()[CurrentRow()]));
233 break;
234 case DUR:
235 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.DursData()[CurrentRow()]));
236 break;
237 case TS_END:
238 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.TsEndData()[CurrentRow()]));
239 break;
240 case CPU:
241 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.CpusData()[CurrentRow()]));
242 break;
243 case INTERNAL_TID:
244 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.InternalTidsData()[CurrentRow()]));
245 break;
246 case INTERNAL_PID:
247 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.InternalPidsData()[CurrentRow()]));
248 break;
249 case END_STATE: {
250 const std::string& str = dataCache_->GetConstSchedStateData(schedSliceObj_.EndStatesData()[CurrentRow()]);
251 sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr);
252 break;
253 }
254 case PRIORITY:
255 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.PriorityData()[CurrentRow()]));
256 break;
257 default:
258 TS_LOGF("Unregistered column : %d", col);
259 break;
260 }
261 return SQLITE_OK;
262 }
263 } // namespace TraceStreamer
264 } // namespace SysTuning
265