• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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