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