• 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 namespace {
21 enum Index {
22     ID = 0,
23     TS,
24     DUR,
25     CALL_ID,
26     CAT,
27     IDENTIFY,
28     NAME,
29     DEPTH,
30     COOKIE_ID,
31     PARENT_ID,
32     ARGSET,
33     CHAIN_ID,
34     SPAN_ID,
35     PARENT_SPAN_ID,
36     FLAG,
37     ARGS
38 };
39 }
CallStackTable(const TraceDataCache * dataCache)40 CallStackTable::CallStackTable(const TraceDataCache* dataCache) : TableBase(dataCache)
41 {
42     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
43     tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER"));
44     tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
45     tableColumn_.push_back(TableBase::ColumnInfo("callid", "INTEGER"));
46     tableColumn_.push_back(TableBase::ColumnInfo("cat", "TEXT"));
47     tableColumn_.push_back(TableBase::ColumnInfo("identify", "INTEGER"));
48     tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
49     tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER"));
50     tableColumn_.push_back(TableBase::ColumnInfo("cookie", "INTEGER"));
51     tableColumn_.push_back(TableBase::ColumnInfo("parent_id", "INTEGER"));
52     tableColumn_.push_back(TableBase::ColumnInfo("argsetid", "INTEGER"));
53     tableColumn_.push_back(TableBase::ColumnInfo("chainId", "TEXT"));
54     tableColumn_.push_back(TableBase::ColumnInfo("spanId", "TEXT"));
55     tableColumn_.push_back(TableBase::ColumnInfo("parentSpanId", "TEXT"));
56     tableColumn_.push_back(TableBase::ColumnInfo("flag", "TEXT"));
57     tableColumn_.push_back(TableBase::ColumnInfo("args", "TEXT"));
58     tablePriKey_.push_back("callid");
59     tablePriKey_.push_back("ts");
60     tablePriKey_.push_back("depth");
61 }
62 
~CallStackTable()63 CallStackTable::~CallStackTable() {}
64 
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)65 void CallStackTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
66 {
67     constexpr double filterBaseCost = 1000.0; // set-up and tear-down
68     constexpr double indexCost = 2.0;
69     ei.estimatedCost = filterBaseCost;
70 
71     auto rowCount = dataCache_->GetConstInternalSlicesData().Size();
72     if (rowCount == 0 || rowCount == 1) {
73         ei.estimatedRows = rowCount;
74         ei.estimatedCost += indexCost * rowCount;
75         return;
76     }
77 
78     double filterCost = 0.0;
79     auto constraints = fc.GetConstraints();
80     if (constraints.empty()) { // scan all rows
81         filterCost = rowCount;
82     } else {
83         FilterByConstraint(fc, filterCost, rowCount);
84     }
85     ei.estimatedCost += filterCost;
86     ei.estimatedRows = rowCount;
87     ei.estimatedCost += rowCount * indexCost;
88 
89     ei.isOrdered = true;
90     auto orderbys = fc.GetOrderBys();
91     for (auto i = 0; i < orderbys.size(); i++) {
92         switch (orderbys[i].iColumn) {
93             case ID:
94                 break;
95             default: // other columns can be sorted by SQLite
96                 ei.isOrdered = false;
97                 break;
98         }
99     }
100 }
101 
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)102 void CallStackTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
103 {
104     auto fcConstraints = fc.GetConstraints();
105     for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
106         if (rowCount <= 1) {
107             // only one row or nothing, needn't filter by constraint
108             filterCost += rowCount;
109             break;
110         }
111         const auto& c = fcConstraints[i];
112         switch (c.col) {
113             case ID: {
114                 if (CanFilterId(c.op, rowCount)) {
115                     fc.UpdateConstraint(i, true);
116                     filterCost += 1; // id can position by 1 step
117                 } else {
118                     filterCost += rowCount; // scan all rows
119                 }
120                 break;
121             }
122             default:                    // other column
123                 filterCost += rowCount; // scan all rows
124                 break;
125         }
126     }
127 }
128 
CanFilterId(const char op,size_t & rowCount)129 bool CallStackTable::CanFilterId(const char op, size_t& rowCount)
130 {
131     switch (op) {
132         case SQLITE_INDEX_CONSTRAINT_EQ:
133             rowCount = 1;
134             break;
135         case SQLITE_INDEX_CONSTRAINT_GT:
136         case SQLITE_INDEX_CONSTRAINT_GE:
137         case SQLITE_INDEX_CONSTRAINT_LE:
138         case SQLITE_INDEX_CONSTRAINT_LT:
139             // assume filter out a half of rows
140             rowCount = (rowCount >> 1);
141             break;
142         default:
143             return false;
144     }
145     return true;
146 }
147 
CreateCursor()148 std::unique_ptr<TableBase::Cursor> CallStackTable::CreateCursor()
149 {
150     return std::make_unique<Cursor>(dataCache_, this);
151 }
152 
Cursor(const TraceDataCache * dataCache,TableBase * table)153 CallStackTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
154     : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstInternalSlicesData().Size())),
155       slicesObj_(dataCache->GetConstInternalSlicesData())
156 {
157 }
158 
~Cursor()159 CallStackTable::Cursor::~Cursor() {}
160 
Filter(const FilterConstraints & fc,sqlite3_value ** argv)161 int CallStackTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
162 {
163     // reset indexMap_
164     indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
165 
166     if (rowCount_ <= 0) {
167         return SQLITE_OK;
168     }
169 
170     auto& cs = fc.GetConstraints();
171     for (size_t i = 0; i < cs.size(); i++) {
172         const auto& c = cs[i];
173         switch (c.col) {
174             case ID:
175                 FilterId(c.op, argv[i]);
176                 break;
177             case TS:
178                 FilterTS(c.op, argv[i], slicesObj_.TimeStamData());
179                 break;
180             case CALL_ID:
181                 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[i])), slicesObj_.CallIds());
182                 break;
183             case COOKIE_ID:
184                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[i])), slicesObj_.Cookies());
185                 break;
186             default:
187                 break;
188         }
189     }
190 
191     auto orderbys = fc.GetOrderBys();
192     for (auto i = orderbys.size(); i > 0;) {
193         i--;
194         switch (orderbys[i].iColumn) {
195             case ID:
196                 indexMap_->SortBy(orderbys[i].desc);
197                 break;
198             default:
199                 break;
200         }
201     }
202 
203     return SQLITE_OK;
204 }
205 
Column(int col) const206 int CallStackTable::Cursor::Column(int col) const
207 {
208     switch (col) {
209         case ID:
210             sqlite3_result_int64(context_, CurrentRow());
211             break;
212         case TS:
213             sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.TimeStamData()[CurrentRow()]));
214             break;
215         case DUR:
216             sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.DursData()[CurrentRow()]));
217             break;
218         case CALL_ID:
219             sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.CallIds()[CurrentRow()]));
220             break;
221         case CAT: {
222             if (slicesObj_.CatsData()[CurrentRow()] != INVALID_UINT64) {
223                 auto catsDataIndex = static_cast<size_t>(slicesObj_.CatsData()[CurrentRow()]);
224                 sqlite3_result_text(context_, dataCache_->GetDataFromDict(catsDataIndex).c_str(), STR_DEFAULT_LEN,
225                                     nullptr);
226             }
227             break;
228         }
229         case IDENTIFY:
230             sqlite3_result_int(context_, slicesObj_.IdentifysData()[CurrentRow()]);
231             break;
232         case NAME: {
233             if (slicesObj_.NamesData()[CurrentRow()] != INVALID_UINT64) {
234                 auto nameDataIndex = static_cast<size_t>(slicesObj_.NamesData()[CurrentRow()]);
235                 sqlite3_result_text(context_, dataCache_->GetDataFromDict(nameDataIndex).c_str(), STR_DEFAULT_LEN,
236                                     nullptr);
237             }
238             break;
239         }
240         case DEPTH:
241             sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.Depths()[CurrentRow()]));
242             break;
243         case COOKIE_ID:
244             if (slicesObj_.Cookies()[CurrentRow()] != INVALID_UINT64) {
245                 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.Cookies()[CurrentRow()]));
246             }
247             break;
248         case PARENT_ID: {
249             if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) {
250                 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ParentIdData()[CurrentRow()].value()));
251             }
252             break;
253         }
254         case ARGSET:
255             if (slicesObj_.ArgSetIdsData()[CurrentRow()] != INVALID_UINT32) {
256                 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ArgSetIdsData()[CurrentRow()]));
257             }
258             break;
259         case CHAIN_ID:
260             sqlite3_result_text(context_, slicesObj_.ChainIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
261             break;
262         case SPAN_ID:
263             sqlite3_result_text(context_, slicesObj_.SpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
264             break;
265         case PARENT_SPAN_ID:
266             sqlite3_result_text(context_, slicesObj_.ParentSpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
267             break;
268         case FLAG:
269             sqlite3_result_text(context_, slicesObj_.Flags()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
270             break;
271         case ARGS:
272             sqlite3_result_text(context_, slicesObj_.ArgsData()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
273             break;
274         default:
275             TS_LOGF("Unregistered column : %d", col);
276             break;
277     }
278     return SQLITE_OK;
279 }
280 } // namespace TraceStreamer
281 } // namespace SysTuning
282