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