• 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 "ebpf_callstack_table.h"
17 
18 namespace SysTuning {
19 namespace TraceStreamer {
20 namespace {
21 enum Index {
22     ID = 0,
23     CALLCHAIN_ID,
24     DEPTH,
25     IP,
26     SYMBOLS_ID,
27     FILE_PATH_ID,
28 };
29 }
EbpfCallStackTable(const TraceDataCache * dataCache)30 EbpfCallStackTable::EbpfCallStackTable(const TraceDataCache* dataCache) : TableBase(dataCache)
31 {
32     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
33     tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER"));
34     tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER"));
35     tableColumn_.push_back(TableBase::ColumnInfo("ip", "TEXT"));
36     tableColumn_.push_back(TableBase::ColumnInfo("symbols_id", "INTEGER"));
37     tableColumn_.push_back(TableBase::ColumnInfo("file_path_id", "INTEGER"));
38     tablePriKey_.push_back("id");
39 }
40 
~EbpfCallStackTable()41 EbpfCallStackTable::~EbpfCallStackTable() {}
42 
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)43 void EbpfCallStackTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
44 {
45     constexpr double filterBaseCost = 1000.0; // set-up and tear-down
46     constexpr double indexCost = 2.0;
47     ei.estimatedCost = filterBaseCost;
48 
49     auto rowCount = dataCache_->GetConstHidumpData().Size();
50     if (rowCount == 0 || rowCount == 1) {
51         ei.estimatedRows = rowCount;
52         ei.estimatedCost += indexCost * rowCount;
53         return;
54     }
55 
56     double filterCost = 0.0;
57     auto constraints = fc.GetConstraints();
58     if (constraints.empty()) { // scan all rows
59         filterCost = rowCount;
60     } else {
61         FilterByConstraint(fc, filterCost, rowCount);
62     }
63     ei.estimatedCost += filterCost;
64     ei.estimatedRows = rowCount;
65     ei.estimatedCost += rowCount * indexCost;
66 
67     ei.isOrdered = true;
68     auto orderbys = fc.GetOrderBys();
69     for (auto i = 0; i < orderbys.size(); i++) {
70         switch (orderbys[i].iColumn) {
71             case ID:
72                 break;
73             default: // other columns can be sorted by SQLite
74                 ei.isOrdered = false;
75                 break;
76         }
77     }
78 }
79 
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)80 void EbpfCallStackTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
81 {
82     auto fcConstraints = fc.GetConstraints();
83     for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
84         if (rowCount <= 1) {
85             // only one row or nothing, needn't filter by constraint
86             filterCost += rowCount;
87             break;
88         }
89         const auto& c = fcConstraints[i];
90         switch (c.col) {
91             case ID: {
92                 if (CanFilterId(c.op, rowCount)) {
93                     fc.UpdateConstraint(i, true);
94                     filterCost += 1; // id can position by 1 step
95                 } else {
96                     filterCost += rowCount; // scan all rows
97                 }
98                 break;
99             }
100             default:                    // other column
101                 filterCost += rowCount; // scan all rows
102                 break;
103         }
104     }
105 }
106 
CanFilterId(const char op,size_t & rowCount)107 bool EbpfCallStackTable::CanFilterId(const char op, size_t& rowCount)
108 {
109     switch (op) {
110         case SQLITE_INDEX_CONSTRAINT_EQ:
111             rowCount = 1;
112             break;
113         case SQLITE_INDEX_CONSTRAINT_GT:
114         case SQLITE_INDEX_CONSTRAINT_GE:
115         case SQLITE_INDEX_CONSTRAINT_LE:
116         case SQLITE_INDEX_CONSTRAINT_LT:
117             // assume filter out a half of rows
118             rowCount = (rowCount >> 1);
119             break;
120         default:
121             return false;
122     }
123     return true;
124 }
125 
CreateCursor()126 std::unique_ptr<TableBase::Cursor> EbpfCallStackTable::CreateCursor()
127 {
128     return std::make_unique<Cursor>(dataCache_, this);
129 }
130 
Cursor(const TraceDataCache * dataCache,TableBase * table)131 EbpfCallStackTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
132     : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstEbpfCallStackData().Size())),
133       ebpfCallStackObj_(dataCache->GetConstEbpfCallStackData())
134 {
135 }
136 
~Cursor()137 EbpfCallStackTable::Cursor::~Cursor() {}
138 
Filter(const FilterConstraints & fc,sqlite3_value ** argv)139 int EbpfCallStackTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
140 {
141     // reset indexMap_
142     indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
143 
144     if (rowCount_ <= 0) {
145         return SQLITE_OK;
146     }
147 
148     auto& cs = fc.GetConstraints();
149     for (size_t i = 0; i < cs.size(); i++) {
150         const auto& c = cs[i];
151         switch (c.col) {
152             case ID:
153                 FilterId(c.op, argv[i]);
154                 break;
155             default:
156                 break;
157         }
158     }
159 
160     auto orderbys = fc.GetOrderBys();
161     for (auto i = orderbys.size(); i > 0;) {
162         i--;
163         switch (orderbys[i].iColumn) {
164             case ID:
165                 indexMap_->SortBy(orderbys[i].desc);
166                 break;
167             default:
168                 break;
169         }
170     }
171 
172     return SQLITE_OK;
173 }
174 
Column(int column) const175 int EbpfCallStackTable::Cursor::Column(int column) const
176 {
177     switch (column) {
178         case ID:
179             sqlite3_result_int64(context_, static_cast<int32_t>(ebpfCallStackObj_.IdsData()[CurrentRow()]));
180             break;
181         case CALLCHAIN_ID:
182             sqlite3_result_int64(context_, static_cast<int64_t>(ebpfCallStackObj_.CallChainIds()[CurrentRow()]));
183             break;
184         case DEPTH:
185             sqlite3_result_int64(context_, static_cast<int64_t>(ebpfCallStackObj_.Depths()[CurrentRow()]));
186             break;
187         case IP: {
188             if (ebpfCallStackObj_.Ips()[CurrentRow()] != INVALID_UINT64) {
189                 auto returnValueIndex = ebpfCallStackObj_.Ips()[CurrentRow()];
190                 sqlite3_result_text(context_, dataCache_->GetDataFromDict(returnValueIndex).c_str(), STR_DEFAULT_LEN,
191                                     nullptr);
192             }
193             break;
194         }
195         case SYMBOLS_ID: {
196             if (ebpfCallStackObj_.SymbolIds()[CurrentRow()] != INVALID_UINT64) {
197                 sqlite3_result_int64(context_, static_cast<int64_t>(ebpfCallStackObj_.SymbolIds()[CurrentRow()]));
198             }
199             break;
200         }
201         case FILE_PATH_ID: {
202             if (ebpfCallStackObj_.FilePathIds()[CurrentRow()] != INVALID_UINT64) {
203                 sqlite3_result_int64(context_, static_cast<int64_t>(ebpfCallStackObj_.FilePathIds()[CurrentRow()]));
204             }
205             break;
206         }
207         default:
208             TS_LOGF("Unregistered column : %d", column);
209             break;
210     }
211     return SQLITE_OK;
212 }
213 } // namespace TraceStreamer
214 } // namespace SysTuning
215