1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 class Index : int32_t {
21 ID = 0,
22 TS,
23 DURS,
24 CALL_IDS,
25 CATS,
26 NAME,
27 DEPTHS,
28 COOKIES_ID,
29 #if IS_WASM
30 COLORINDEX,
31 #endif
32 PARENT_ID,
33 ARGSET,
34 CHAIN_IDS,
35 SPAN_IDS,
36 PARENT_SPAN_IDS,
37 FLAGS,
38 TRACE_LEVEL,
39 TRACE_TAG,
40 CUSTOM_CATEGORY,
41 CUSTOM_ARGS,
42 CHILD_CALLID
43 };
CallStackTable(const TraceDataCache * dataCache)44 CallStackTable::CallStackTable(const TraceDataCache *dataCache) : TableBase(dataCache)
45 {
46 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
47 tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER"));
48 tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
49 tableColumn_.push_back(TableBase::ColumnInfo("callid", "INTEGER"));
50 tableColumn_.push_back(TableBase::ColumnInfo("cat", "TEXT"));
51 tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
52 tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER"));
53 tableColumn_.push_back(TableBase::ColumnInfo("cookie", "INTEGER"));
54 #if IS_WASM
55 tableColumn_.push_back(TableBase::ColumnInfo("colorIndex", "INTEGER"));
56 #endif
57 tableColumn_.push_back(TableBase::ColumnInfo("parent_id", "INTEGER"));
58 tableColumn_.push_back(TableBase::ColumnInfo("argsetid", "INTEGER"));
59 tableColumn_.push_back(TableBase::ColumnInfo("chainId", "TEXT"));
60 tableColumn_.push_back(TableBase::ColumnInfo("spanId", "TEXT"));
61 tableColumn_.push_back(TableBase::ColumnInfo("parentSpanId", "TEXT"));
62 tableColumn_.push_back(TableBase::ColumnInfo("flag", "TEXT"));
63 tableColumn_.push_back(TableBase::ColumnInfo("trace_level", "TEXT"));
64 tableColumn_.push_back(TableBase::ColumnInfo("trace_tag", "TEXT"));
65 tableColumn_.push_back(TableBase::ColumnInfo("custom_category", "TEXT"));
66 tableColumn_.push_back(TableBase::ColumnInfo("custom_args", "TEXT"));
67 tableColumn_.push_back(TableBase::ColumnInfo("child_callid", "INTEGER"));
68 tablePriKey_.push_back("callid");
69 tablePriKey_.push_back("ts");
70 tablePriKey_.push_back("depth");
71 }
72
~CallStackTable()73 CallStackTable::~CallStackTable() {}
74
FilterByConstraint(FilterConstraints & callfc,double & callfilterCost,size_t callrowCount,uint32_t callCurrenti)75 void CallStackTable::FilterByConstraint(FilterConstraints &callfc,
76 double &callfilterCost,
77 size_t callrowCount,
78 uint32_t callCurrenti)
79 {
80 // To use the EstimateFilterCost function in the TableBase parent class function to calculate the i-value of each
81 // for loop
82 const auto &callc = callfc.GetConstraints()[callCurrenti];
83 switch (static_cast<Index>(callc.col)) {
84 case Index::ID: {
85 if (CanFilterId(callc.op, callrowCount)) {
86 callfc.UpdateConstraint(callCurrenti, true);
87 callfilterCost += 1; // id can position by 1 step
88 } else {
89 callfilterCost += callrowCount; // scan all rows
90 }
91 break;
92 }
93 default: // other column
94 callfilterCost += callrowCount; // scan all rows
95 break;
96 }
97 }
98
CreateCursor()99 std::unique_ptr<TableBase::Cursor> CallStackTable::CreateCursor()
100 {
101 return std::make_unique<Cursor>(dataCache_, this);
102 }
103
Cursor(const TraceDataCache * dataCache,TableBase * table)104 CallStackTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
105 : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstInternalSlicesData().Size())),
106 slicesObj_(dataCache->GetConstInternalSlicesData())
107 {
108 }
109
~Cursor()110 CallStackTable::Cursor::~Cursor() {}
111
Filter(const FilterConstraints & fc,sqlite3_value ** argv)112 int32_t CallStackTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
113 {
114 // reset indexMap_
115 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
116
117 if (rowCount_ <= 0) {
118 return SQLITE_OK;
119 }
120
121 auto callStackTabCs = fc.GetConstraints();
122 std::set<uint32_t> sId = {static_cast<uint32_t>(Index::TS)};
123 SwapIndexFront(callStackTabCs, sId);
124 for (size_t i = 0; i < callStackTabCs.size(); i++) {
125 const auto &c = callStackTabCs[i];
126 switch (static_cast<Index>(c.col)) {
127 case Index::ID:
128 FilterId(c.op, argv[c.idxInaConstraint]);
129 break;
130 case Index::TS:
131 FilterTS(c.op, argv[c.idxInaConstraint], slicesObj_.TimeStampData());
132 break;
133 case Index::CALL_IDS:
134 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
135 slicesObj_.CallIds());
136 break;
137 case Index::COOKIES_ID:
138 indexMap_->MixRange(c.op, static_cast<int64_t>(sqlite3_value_int64(argv[c.idxInaConstraint])),
139 slicesObj_.Cookies());
140 break;
141 default:
142 break;
143 }
144 }
145
146 auto callStackTableOrderbys = fc.GetOrderBys();
147 for (auto i = callStackTableOrderbys.size(); i > 0;) {
148 i--;
149 switch (static_cast<Index>(callStackTableOrderbys[i].iColumn)) {
150 case Index::ID:
151 indexMap_->SortBy(callStackTableOrderbys[i].desc);
152 break;
153 default:
154 break;
155 }
156 }
157
158 return SQLITE_OK;
159 }
160
Column(int32_t col) const161 int32_t CallStackTable::Cursor::Column(int32_t col) const
162 {
163 switch (static_cast<Index>(col)) {
164 case Index::ID:
165 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.IdsData()[CurrentRow()]));
166 break;
167 case Index::TS:
168 SetTypeColumnInt64(slicesObj_.TimeStampData()[CurrentRow()], INVALID_UINT64);
169 break;
170 case Index::DURS:
171 SetTypeColumnInt64(slicesObj_.DursData()[CurrentRow()], INVALID_UINT64);
172 break;
173 case Index::CALL_IDS:
174 SetTypeColumnInt64(slicesObj_.CallIds()[CurrentRow()], INVALID_UINT64);
175 break;
176 #if IS_WASM
177 case Index::COLORINDEX:
178 SetTypeColumnInt64(slicesObj_.ColorIndexs()[CurrentRow()], INVALID_UINT64);
179 break;
180 #endif
181 case Index::CATS: {
182 SetTypeColumnText(slicesObj_.CatsData()[CurrentRow()], INVALID_UINT64);
183 break;
184 }
185 case Index::NAME: {
186 SetTypeColumnText(slicesObj_.NamesData()[CurrentRow()], INVALID_UINT64);
187 break;
188 default:
189 HandleTypeColumns(col);
190 }
191 }
192 return SQLITE_OK;
193 }
HandleTypeColumns(int32_t col) const194 void CallStackTable::Cursor::HandleTypeColumns(int32_t col) const
195 {
196 switch (static_cast<Index>(col)) {
197 case Index::DEPTHS:
198 SetTypeColumnInt64(slicesObj_.Depths()[CurrentRow()], INVALID_UINT64);
199 break;
200 case Index::COOKIES_ID:
201 SetTypeColumnInt64(slicesObj_.Cookies()[CurrentRow()], INVALID_INT64);
202 break;
203 case Index::PARENT_ID: {
204 if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) {
205 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ParentIdData()[CurrentRow()].value()));
206 }
207 break;
208 }
209 case Index::ARGSET:
210 SetTypeColumnInt64(slicesObj_.ArgSetIdsData()[CurrentRow()], INVALID_UINT32);
211 break;
212 case Index::CHAIN_IDS:
213 SetTypeColumnTextNotEmpty(slicesObj_.ChainIds()[CurrentRow()].empty(),
214 slicesObj_.ChainIds()[CurrentRow()].c_str());
215 break;
216 case Index::SPAN_IDS:
217 SetTypeColumnTextNotEmpty(slicesObj_.SpanIds()[CurrentRow()].empty(),
218 slicesObj_.SpanIds()[CurrentRow()].c_str());
219 break;
220 case Index::PARENT_SPAN_IDS:
221 SetTypeColumnTextNotEmpty(slicesObj_.ParentSpanIds()[CurrentRow()].empty(),
222 slicesObj_.ParentSpanIds()[CurrentRow()].c_str());
223 break;
224 case Index::FLAGS:
225 SetTypeColumnTextNotEmpty(slicesObj_.Flags()[CurrentRow()].empty(),
226 slicesObj_.Flags()[CurrentRow()].c_str());
227 break;
228 case Index::TRACE_LEVEL:
229 SetTypeColumnTextNotEmpty(slicesObj_.TraceLevelsData()[CurrentRow()].empty(),
230 slicesObj_.TraceLevelsData()[CurrentRow()].c_str());
231 break;
232 case Index::TRACE_TAG:
233 SetTypeColumnText(slicesObj_.TraceTagsData()[CurrentRow()], INVALID_UINT64);
234 break;
235 case Index::CUSTOM_CATEGORY:
236 SetTypeColumnText(slicesObj_.CustomCategorysData()[CurrentRow()], INVALID_UINT64);
237 break;
238 case Index::CUSTOM_ARGS:
239 SetTypeColumnText(slicesObj_.CustomArgsData()[CurrentRow()], INVALID_UINT64);
240 break;
241 case Index::CHILD_CALLID: {
242 if (slicesObj_.ChildCallidData()[CurrentRow()].has_value()) {
243 sqlite3_result_int64(context_,
244 static_cast<int64_t>(slicesObj_.ChildCallidData()[CurrentRow()].value()));
245 }
246 break;
247 }
248 default:
249 TS_LOGF("Unregistered column : %d", col);
250 break;
251 }
252 }
GetOrbyes(FilterConstraints & callfc,EstimatedIndexInfo & callei)253 void CallStackTable::GetOrbyes(FilterConstraints &callfc, EstimatedIndexInfo &callei)
254 {
255 auto orderbys = callfc.GetOrderBys();
256 for (auto i = 0; i < orderbys.size(); i++) {
257 switch (static_cast<Index>(orderbys[i].iColumn)) {
258 case Index::ID:
259 break;
260 default: // other columns can be sorted by SQLite
261 callei.isOrdered = false;
262 break;
263 }
264 }
265 }
266 } // namespace TraceStreamer
267 } // namespace SysTuning
268