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