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