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 "callstack_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 IDENTIFY,
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 };
CallStackTable(const TraceDataCache * dataCache)38 CallStackTable::CallStackTable(const TraceDataCache* dataCache) : TableBase(dataCache)
39 {
40 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
41 tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER"));
42 tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
43 tableColumn_.push_back(TableBase::ColumnInfo("callid", "INTEGER"));
44 tableColumn_.push_back(TableBase::ColumnInfo("cat", "TEXT"));
45 tableColumn_.push_back(TableBase::ColumnInfo("identify", "INTEGER"));
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
~CallStackTable()61 CallStackTable::~CallStackTable() {}
62
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)63 void CallStackTable::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_->GetConstInternalSlicesData().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 CallStackTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
101 {
102 auto fcConstraints = fc.GetConstraints();
103 for (int32_t i = 0; i < static_cast<int32_t>(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
CreateCursor()127 std::unique_ptr<TableBase::Cursor> CallStackTable::CreateCursor()
128 {
129 return std::make_unique<Cursor>(dataCache_, this);
130 }
131
Cursor(const TraceDataCache * dataCache,TableBase * table)132 CallStackTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
133 : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstInternalSlicesData().Size())),
134 slicesObj_(dataCache->GetConstInternalSlicesData())
135 {
136 }
137
~Cursor()138 CallStackTable::Cursor::~Cursor() {}
139
Filter(const FilterConstraints & fc,sqlite3_value ** argv)140 int32_t CallStackTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
141 {
142 // reset indexMap_
143 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
144
145 if (rowCount_ <= 0) {
146 return SQLITE_OK;
147 }
148
149 auto& cs = fc.GetConstraints();
150 for (size_t i = 0; i < cs.size(); i++) {
151 const auto& c = cs[i];
152 switch (c.col) {
153 case ID:
154 FilterId(c.op, argv[i]);
155 break;
156 case TS:
157 FilterTS(c.op, argv[i], slicesObj_.TimeStampData());
158 break;
159 case CALL_ID:
160 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[i])), slicesObj_.CallIds());
161 break;
162 case COOKIE_ID:
163 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[i])), slicesObj_.Cookies());
164 break;
165 default:
166 break;
167 }
168 }
169
170 auto orderbys = fc.GetOrderBys();
171 for (auto i = orderbys.size(); i > 0;) {
172 i--;
173 switch (orderbys[i].iColumn) {
174 case ID:
175 indexMap_->SortBy(orderbys[i].desc);
176 break;
177 default:
178 break;
179 }
180 }
181
182 return SQLITE_OK;
183 }
184
Column(int32_t col) const185 int32_t CallStackTable::Cursor::Column(int32_t col) const
186 {
187 switch (col) {
188 case ID:
189 sqlite3_result_int64(context_, CurrentRow());
190 break;
191 case TS:
192 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.TimeStampData()[CurrentRow()]));
193 break;
194 case DUR:
195 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.DursData()[CurrentRow()]));
196 break;
197 case CALL_ID:
198 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.CallIds()[CurrentRow()]));
199 break;
200 case CAT: {
201 if (slicesObj_.CatsData()[CurrentRow()] != INVALID_UINT64) {
202 auto catsDataIndex = static_cast<size_t>(slicesObj_.CatsData()[CurrentRow()]);
203 sqlite3_result_text(context_, dataCache_->GetDataFromDict(catsDataIndex).c_str(), STR_DEFAULT_LEN,
204 nullptr);
205 }
206 break;
207 }
208 case IDENTIFY:
209 sqlite3_result_int(context_, slicesObj_.IdentifysData()[CurrentRow()]);
210 break;
211 case NAME: {
212 if (slicesObj_.NamesData()[CurrentRow()] != INVALID_UINT64) {
213 auto nameDataIndex = static_cast<size_t>(slicesObj_.NamesData()[CurrentRow()]);
214 sqlite3_result_text(context_, dataCache_->GetDataFromDict(nameDataIndex).c_str(), STR_DEFAULT_LEN,
215 nullptr);
216 }
217 break;
218 }
219 case DEPTH:
220 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.Depths()[CurrentRow()]));
221 break;
222 case COOKIE_ID:
223 if (slicesObj_.Cookies()[CurrentRow()] != INVALID_UINT64) {
224 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.Cookies()[CurrentRow()]));
225 }
226 break;
227 case PARENT_ID: {
228 if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) {
229 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ParentIdData()[CurrentRow()].value()));
230 }
231 break;
232 }
233 case ARGSET:
234 if (slicesObj_.ArgSetIdsData()[CurrentRow()] != INVALID_UINT32) {
235 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ArgSetIdsData()[CurrentRow()]));
236 }
237 break;
238 case CHAIN_ID:
239 if (!slicesObj_.ChainIds()[CurrentRow()].empty()) {
240 sqlite3_result_text(context_, slicesObj_.ChainIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
241 }
242 break;
243 case SPAN_ID:
244 if (!slicesObj_.SpanIds()[CurrentRow()].empty()) {
245 sqlite3_result_text(context_, slicesObj_.SpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
246 }
247 break;
248 case PARENT_SPAN_ID:
249 if (!slicesObj_.ParentSpanIds()[CurrentRow()].empty()) {
250 sqlite3_result_text(context_, slicesObj_.ParentSpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN,
251 nullptr);
252 }
253 break;
254 case FLAG:
255 if (!slicesObj_.Flags()[CurrentRow()].empty()) {
256 sqlite3_result_text(context_, slicesObj_.Flags()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
257 }
258 break;
259 case ARGS:
260 if (!slicesObj_.ArgsData()[CurrentRow()].empty()) {
261 sqlite3_result_text(context_, slicesObj_.ArgsData()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
262 }
263 break;
264 default:
265 TS_LOGF("Unregistered column : %d", col);
266 break;
267 }
268 return SQLITE_OK;
269 }
270 } // namespace TraceStreamer
271 } // namespace SysTuning
272