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