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