• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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