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 "paged_memory_sample_table.h"
17
18 namespace SysTuning {
19 namespace TraceStreamer {
20 namespace {
21 enum Index { ID = 0, CALLCHAIN_ID, TYPE, IPID, START_TS, END_TS, DUR, SIZE, ADDR, ITID };
22 }
PagedMemorySampleTable(const TraceDataCache * dataCache)23 PagedMemorySampleTable::PagedMemorySampleTable(const TraceDataCache* dataCache) : TableBase(dataCache)
24 {
25 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
26 tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER"));
27 tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER"));
28 tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
29 tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER"));
30 tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER"));
31 tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
32 tableColumn_.push_back(TableBase::ColumnInfo("size", "INTEGER"));
33 tableColumn_.push_back(TableBase::ColumnInfo("addr", "TEXT"));
34 tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER"));
35 tablePriKey_.push_back("id");
36 }
37
~PagedMemorySampleTable()38 PagedMemorySampleTable::~PagedMemorySampleTable() {}
39
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)40 void PagedMemorySampleTable::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 PagedMemorySampleTable::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 PagedMemorySampleTable::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> PagedMemorySampleTable::CreateCursor()
124 {
125 return std::make_unique<Cursor>(dataCache_, this);
126 }
127
Cursor(const TraceDataCache * dataCache,TableBase * table)128 PagedMemorySampleTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
129 : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstPagedMemorySampleData().Size())),
130 PagedMemorySampleDataObj_(dataCache->GetConstPagedMemorySampleData())
131 {
132 }
133
~Cursor()134 PagedMemorySampleTable::Cursor::~Cursor() {}
135
Filter(const FilterConstraints & fc,sqlite3_value ** argv)136 int PagedMemorySampleTable::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 return SQLITE_OK;
169 }
170
Column(int column) const171 int PagedMemorySampleTable::Cursor::Column(int column) const
172 {
173 switch (column) {
174 case ID:
175 sqlite3_result_int64(context_, static_cast<int32_t>(PagedMemorySampleDataObj_.IdsData()[CurrentRow()]));
176 break;
177 case CALLCHAIN_ID:
178 sqlite3_result_int64(context_,
179 static_cast<int64_t>(PagedMemorySampleDataObj_.CallChainIds()[CurrentRow()]));
180 break;
181 case TYPE:
182 sqlite3_result_int64(context_, static_cast<int64_t>(PagedMemorySampleDataObj_.Types()[CurrentRow()]));
183 break;
184 case IPID:
185 sqlite3_result_int64(context_, static_cast<int64_t>(PagedMemorySampleDataObj_.Ipids()[CurrentRow()]));
186 break;
187 case ITID:
188 sqlite3_result_int64(context_, static_cast<int64_t>(PagedMemorySampleDataObj_.Itids()[CurrentRow()]));
189 break;
190 case START_TS:
191 sqlite3_result_int64(context_, static_cast<int64_t>(PagedMemorySampleDataObj_.StartTs()[CurrentRow()]));
192 break;
193 case END_TS:
194 sqlite3_result_int64(context_, static_cast<int64_t>(PagedMemorySampleDataObj_.EndTs()[CurrentRow()]));
195 break;
196 case DUR:
197 sqlite3_result_int64(context_, static_cast<int64_t>(PagedMemorySampleDataObj_.Durs()[CurrentRow()]));
198 break;
199 case SIZE: {
200 if (PagedMemorySampleDataObj_.Sizes()[CurrentRow()] != MAX_SIZE_T) {
201 sqlite3_result_int64(context_, static_cast<int64_t>(PagedMemorySampleDataObj_.Sizes()[CurrentRow()]));
202 }
203 break;
204 }
205 case ADDR: {
206 if (PagedMemorySampleDataObj_.Addr()[CurrentRow()] != INVALID_UINT64) {
207 auto firstArgIndex = PagedMemorySampleDataObj_.Addr()[CurrentRow()];
208 sqlite3_result_text(context_, dataCache_->GetDataFromDict(firstArgIndex).c_str(), STR_DEFAULT_LEN,
209 nullptr);
210 }
211 break;
212 }
213 default:
214 TS_LOGF("Unregistered column : %d", column);
215 break;
216 }
217 return SQLITE_OK;
218 }
219
FilterId(unsigned char op,sqlite3_value * argv)220 void PagedMemorySampleTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv)
221 {
222 auto type = sqlite3_value_type(argv);
223 if (type != SQLITE_INTEGER) {
224 // other type consider it NULL
225 indexMap_->Intersect(0, 0);
226 return;
227 }
228 auto v = static_cast<TableRowId>(sqlite3_value_int64(argv));
229 switch (op) {
230 case SQLITE_INDEX_CONSTRAINT_EQ:
231 indexMap_->Intersect(v, v + 1);
232 break;
233 case SQLITE_INDEX_CONSTRAINT_GE:
234 indexMap_->Intersect(v, rowCount_);
235 break;
236 case SQLITE_INDEX_CONSTRAINT_GT:
237 v++;
238 indexMap_->Intersect(v, rowCount_);
239 break;
240 case SQLITE_INDEX_CONSTRAINT_LE:
241 v++;
242 indexMap_->Intersect(0, v);
243 break;
244 case SQLITE_INDEX_CONSTRAINT_LT:
245 indexMap_->Intersect(0, v);
246 break;
247 default:
248 // can't filter, all rows
249 break;
250 }
251 }
252 } // namespace TraceStreamer
253 } // namespace SysTuning
254