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