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 "irq_table.h"
17
18 namespace SysTuning {
19 namespace TraceStreamer {
20 namespace {
21 enum Index {
22 ID = 0,
23 TS,
24 DUR,
25 CALL_ID,
26 CAT,
27 NAME,
28 DEPTH,
29 COOKIE_ID,
30 PARENT_ID,
31 ARGSET,
32 CHAIN_ID,
33 SPAN_ID,
34 PARENT_SPAN_ID,
35 FLAG,
36 ARGS
37 };
38 }
IrqTable(const TraceDataCache * dataCache)39 IrqTable::IrqTable(const TraceDataCache* dataCache) : TableBase(dataCache)
40 {
41 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
42 tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER"));
43 tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
44 tableColumn_.push_back(TableBase::ColumnInfo("callid", "INTEGER"));
45 tableColumn_.push_back(TableBase::ColumnInfo("cat", "TEXT"));
46 tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
47 tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER"));
48 tableColumn_.push_back(TableBase::ColumnInfo("cookie", "INTEGER"));
49 tableColumn_.push_back(TableBase::ColumnInfo("parent_id", "INTEGER"));
50 tableColumn_.push_back(TableBase::ColumnInfo("argsetid", "INTEGER"));
51 tableColumn_.push_back(TableBase::ColumnInfo("chainId", "TEXT"));
52 tableColumn_.push_back(TableBase::ColumnInfo("spanId", "TEXT"));
53 tableColumn_.push_back(TableBase::ColumnInfo("parentSpanId", "TEXT"));
54 tableColumn_.push_back(TableBase::ColumnInfo("flag", "TEXT"));
55 tableColumn_.push_back(TableBase::ColumnInfo("args", "TEXT"));
56 tablePriKey_.push_back("callid");
57 tablePriKey_.push_back("ts");
58 tablePriKey_.push_back("depth");
59 }
60
~IrqTable()61 IrqTable::~IrqTable() {}
62
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)63 void IrqTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
64 {
65 constexpr double filterBaseCost = 1000.0; // set-up and tear-down
66 constexpr double indexCost = 2.0;
67 ei.estimatedCost = filterBaseCost;
68
69 auto rowCount = dataCache_->GetConstIrqData().Size();
70 if (rowCount == 0 || rowCount == 1) {
71 ei.estimatedRows = rowCount;
72 ei.estimatedCost += indexCost * rowCount;
73 return;
74 }
75
76 double filterCost = 0.0;
77 auto constraints = fc.GetConstraints();
78 if (constraints.empty()) { // scan all rows
79 filterCost = rowCount;
80 } else {
81 FilterByConstraint(fc, filterCost, rowCount);
82 }
83 ei.estimatedCost += filterCost;
84 ei.estimatedRows = rowCount;
85 ei.estimatedCost += rowCount * indexCost;
86
87 ei.isOrdered = true;
88 auto orderbys = fc.GetOrderBys();
89 for (auto i = 0; i < orderbys.size(); i++) {
90 switch (orderbys[i].iColumn) {
91 case ID:
92 break;
93 default: // other columns can be sorted by SQLite
94 ei.isOrdered = false;
95 break;
96 }
97 }
98 }
99
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)100 void IrqTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
101 {
102 auto fcConstraints = fc.GetConstraints();
103 for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
104 if (rowCount <= 1) {
105 // only one row or nothing, needn't filter by constraint
106 filterCost += rowCount;
107 break;
108 }
109 const auto& c = fcConstraints[i];
110 switch (c.col) {
111 case ID: {
112 if (CanFilterId(c.op, rowCount)) {
113 fc.UpdateConstraint(i, true);
114 filterCost += 1; // id can position by 1 step
115 } else {
116 filterCost += rowCount; // scan all rows
117 }
118 break;
119 }
120 default: // other column
121 filterCost += rowCount; // scan all rows
122 break;
123 }
124 }
125 }
126
CanFilterId(const char op,size_t & rowCount)127 bool IrqTable::CanFilterId(const char op, size_t& rowCount)
128 {
129 switch (op) {
130 case SQLITE_INDEX_CONSTRAINT_EQ:
131 rowCount = 1;
132 break;
133 case SQLITE_INDEX_CONSTRAINT_GT:
134 case SQLITE_INDEX_CONSTRAINT_GE:
135 case SQLITE_INDEX_CONSTRAINT_LE:
136 case SQLITE_INDEX_CONSTRAINT_LT:
137 // assume filter out a half of rows
138 rowCount = (rowCount >> 1);
139 break;
140 default:
141 return false;
142 }
143 return true;
144 }
145
CreateCursor()146 std::unique_ptr<TableBase::Cursor> IrqTable::CreateCursor()
147 {
148 return std::make_unique<Cursor>(dataCache_, this);
149 }
150
Cursor(const TraceDataCache * dataCache,TableBase * table)151 IrqTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
152 : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstIrqData().Size())),
153 slicesObj_(dataCache->GetConstIrqData())
154 {
155 }
156
~Cursor()157 IrqTable::Cursor::~Cursor() {}
158
Filter(const FilterConstraints & fc,sqlite3_value ** argv)159 int IrqTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
160 {
161 // reset indexMap_
162 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
163
164 if (rowCount_ <= 0) {
165 return SQLITE_OK;
166 }
167
168 auto& cs = fc.GetConstraints();
169 for (size_t i = 0; i < cs.size(); i++) {
170 const auto& c = cs[i];
171 switch (c.col) {
172 case ID:
173 FilterId(c.op, argv[i]);
174 break;
175 default:
176 break;
177 }
178 }
179
180 auto orderbys = fc.GetOrderBys();
181 for (auto i = orderbys.size(); i > 0;) {
182 i--;
183 switch (orderbys[i].iColumn) {
184 case ID:
185 indexMap_->SortBy(orderbys[i].desc);
186 break;
187 default:
188 break;
189 }
190 }
191
192 return SQLITE_OK;
193 }
194
Column(int column) const195 int IrqTable::Cursor::Column(int column) const
196 {
197 switch (column) {
198 case ID:
199 sqlite3_result_int64(context_, CurrentRow());
200 break;
201 case TS:
202 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.TimeStamData()[CurrentRow()]));
203 break;
204 case DUR:
205 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.DursData()[CurrentRow()]));
206 break;
207 case CALL_ID:
208 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.CallIds()[CurrentRow()]));
209 break;
210 case CAT: {
211 if (slicesObj_.CatsData()[CurrentRow()] != INVALID_UINT64) {
212 auto catsDataIndex = static_cast<size_t>(slicesObj_.CatsData()[CurrentRow()]);
213 sqlite3_result_text(context_, dataCache_->GetDataFromDict(catsDataIndex).c_str(), STR_DEFAULT_LEN,
214 nullptr);
215 }
216 break;
217 }
218 case NAME: {
219 if (slicesObj_.NamesData()[CurrentRow()] != INVALID_UINT64) {
220 auto nameDataIndex = static_cast<size_t>(slicesObj_.NamesData()[CurrentRow()]);
221 sqlite3_result_text(context_, dataCache_->GetDataFromDict(nameDataIndex).c_str(), STR_DEFAULT_LEN,
222 nullptr);
223 }
224 break;
225 }
226 case DEPTH:
227 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.Depths()[CurrentRow()]));
228 break;
229 case COOKIE_ID:
230 if (slicesObj_.Cookies()[CurrentRow()] != INVALID_UINT64) {
231 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.Cookies()[CurrentRow()]));
232 }
233 break;
234 case PARENT_ID: {
235 if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) {
236 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ParentIdData()[CurrentRow()].value()));
237 }
238 break;
239 }
240 case ARGSET:
241 if (slicesObj_.ArgSetIdsData()[CurrentRow()] != INVALID_UINT32) {
242 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ArgSetIdsData()[CurrentRow()]));
243 }
244 break;
245 case CHAIN_ID:
246 sqlite3_result_text(context_, slicesObj_.ChainIds()[CurrentRow()].c_str(),
247 STR_DEFAULT_LEN, nullptr);
248 break;
249 case SPAN_ID:
250 sqlite3_result_text(context_, slicesObj_.SpanIds()[CurrentRow()].c_str(),
251 STR_DEFAULT_LEN, nullptr);
252 break;
253 case PARENT_SPAN_ID:
254 sqlite3_result_text(context_,
255 slicesObj_.ParentSpanIds()[CurrentRow()].c_str(),
256 STR_DEFAULT_LEN, nullptr);
257 break;
258 case FLAG:
259 sqlite3_result_text(context_, slicesObj_.Flags()[CurrentRow()].c_str(),
260 STR_DEFAULT_LEN, nullptr);
261 break;
262 case ARGS:
263 sqlite3_result_text(context_, slicesObj_.ArgsData()[CurrentRow()].c_str(),
264 STR_DEFAULT_LEN, nullptr);
265 break;
266 default:
267 TS_LOGF("Unregistered column : %d", column);
268 break;
269 }
270 return SQLITE_OK;
271 }
272 } // namespace TraceStreamer
273 } // namespace SysTuning
274