1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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_table.h"
17
18 namespace SysTuning {
19 namespace TraceStreamer {
20 enum class Index : int32_t { ID = 0, IPID, PID, NAME, START_TS, SWITCH_COUNT, THREAD_COUNT, SLICE_COUNT, MEM_COUNT };
ProcessTable(const TraceDataCache *dataCache)21 ProcessTable::ProcessTable(const TraceDataCache *dataCache) : TableBase(dataCache)
22 {
23 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
24 tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
25 tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER"));
26 tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
27 tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER"));
28 tableColumn_.push_back(TableBase::ColumnInfo("switch_count", "INTEGER"));
29 tableColumn_.push_back(TableBase::ColumnInfo("thread_count", "INTEGER"));
30 tableColumn_.push_back(TableBase::ColumnInfo("slice_count", "INTEGER"));
31 tableColumn_.push_back(TableBase::ColumnInfo("mem_count", "INTEGER"));
32 tablePriKey_.push_back("id");
33 }
34
~ProcessTable()35 ProcessTable::~ProcessTable() {}
36
FilterByConstraint(FilterConstraints &processfc, double &processfilterCost, size_t processrowCount, uint32_t processcurrenti)37 void ProcessTable::FilterByConstraint(FilterConstraints &processfc,
38 double &processfilterCost,
39 size_t processrowCount,
40 uint32_t processcurrenti)
41 {
42 // To use the EstimateFilterCost function in the TableBase parent class function to calculate the i-value of each
43 // for loop
44 const auto &processc = processfc.GetConstraints()[processcurrenti];
45 switch (static_cast<Index>(processc.col)) {
46 case Index::IPID:
47 case Index::ID: {
48 if (CanFilterId(processc.op, processrowCount)) {
49 processfc.UpdateConstraint(processcurrenti, true);
50 processfilterCost += 1; // id can position by 1 step
51 } else {
52 processfilterCost += processrowCount; // scan all rows
53 }
54 break;
55 }
56 default: // other column
57 processfilterCost += processrowCount; // scan all rows
58 break;
59 }
60 }
61
Update(int32_t argc, sqlite3_value **argv, sqlite3_int64 *pRowid)62 int32_t ProcessTable::Update(int32_t argc, sqlite3_value **argv, sqlite3_int64 *pRowid)
63 {
64 if (argc <= 1) {
65 return SQLITE_READONLY;
66 }
67 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
68 return SQLITE_READONLY;
69 }
70 auto id = sqlite3_value_int64(argv[0]);
71 auto process = wdataCache_->GetProcessData(static_cast<InternalPid>(id));
72 constexpr int32_t colOffset = 2;
73 for (auto i = colOffset; i < argc; i++) {
74 auto col = i - colOffset;
75 if (static_cast<Index>(col) != Index::NAME) {
76 continue;
77 }
78 const char *name = reinterpret_cast<const char *>(sqlite3_value_text(argv[i]));
79 if (name == nullptr) {
80 process->cmdLine_.clear();
81 } else {
82 process->cmdLine_ = name;
83 }
84 break;
85 }
86 return SQLITE_OK;
87 }
88
CreateCursor()89 std::unique_ptr<TableBase::Cursor> ProcessTable::CreateCursor()
90 {
91 return std::make_unique<Cursor>(dataCache_, this);
92 }
93
Cursor(const TraceDataCache *dataCache, TableBase *table)94 ProcessTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
95 : TableBase::Cursor(dataCache, table, dataCache->ProcessSize())
96 {
97 }
98
~Cursor()99 ProcessTable::Cursor::~Cursor() {}
100
Filter(const FilterConstraints &fc, sqlite3_value **argv)101 int32_t ProcessTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
102 {
103 // reset indexMap_
104 indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
105
106 if (rowCount_ <= 0) {
107 return SQLITE_OK;
108 }
109
110 auto processTableCs = fc.GetConstraints();
111 std::set<uint32_t> sId = {static_cast<uint32_t>(Index::ID)};
112 SwapIndexFront(processTableCs, sId);
113 for (size_t i = 0; i < processTableCs.size(); i++) {
114 const auto &c = processTableCs[i];
115 switch (static_cast<Index>(c.col)) {
116 case Index::ID:
117 case Index::IPID:
118 FilterId(c.op, argv[c.idxInaConstraint]);
119 break;
120 case Index::PID:
121 FilterIndex(c.col, c.op, argv[c.idxInaConstraint]);
122 break;
123 default:
124 break;
125 }
126 }
127
128 auto processTableOrderbys = fc.GetOrderBys();
129 for (auto i = processTableOrderbys.size(); i > 0;) {
130 i--;
131 switch (static_cast<Index>(processTableOrderbys[i].iColumn)) {
132 case Index::ID:
133 case Index::IPID:
134 indexMap_->SortBy(processTableOrderbys[i].desc);
135 break;
136 default:
137 break;
138 }
139 }
140
141 return SQLITE_OK;
142 }
143
Column(int32_t col) const144 int32_t ProcessTable::Cursor::Column(int32_t col) const
145 {
146 const auto &process = dataCache_->GetConstProcessData(CurrentRow());
147 switch (static_cast<Index>(col)) {
148 case Index::ID:
149 case Index::IPID:
150 sqlite3_result_int64(context_, CurrentRow());
151 break;
152 case Index::PID:
153 sqlite3_result_int64(context_, process.pid_);
154 break;
155 case Index::NAME:
156 if (process.cmdLine_.size()) {
157 sqlite3_result_text(context_, process.cmdLine_.c_str(), static_cast<int32_t>(process.cmdLine_.length()),
158 nullptr);
159 }
160 break;
161 case Index::START_TS:
162 if (process.startT_) {
163 sqlite3_result_int64(context_, static_cast<int64_t>(process.startT_));
164 }
165 break;
166 case Index::SWITCH_COUNT:
167 sqlite3_result_int64(context_, process.switchCount_);
168 break;
169 case Index::THREAD_COUNT:
170 sqlite3_result_int64(context_, process.threadCount_);
171 break;
172 case Index::SLICE_COUNT:
173 sqlite3_result_int64(context_, process.sliceSize_);
174 break;
175 case Index::MEM_COUNT:
176 sqlite3_result_int64(context_, process.memSize_);
177 break;
178 default:
179 TS_LOGF("Unregistered column : %d", col);
180 break;
181 }
182 return SQLITE_OK;
183 }
184
FilterPid(unsigned char op, uint64_t value)185 void ProcessTable::Cursor::FilterPid(unsigned char op, uint64_t value)
186 {
187 bool remove = false;
188 if (indexMap_->HasData()) {
189 indexMap_->ConvertToIndexMap();
190 remove = true;
191 }
192 switch (op) {
193 case SQLITE_INDEX_CONSTRAINT_EQ:
194 HandleIndexConstraintEQ(remove, value);
195 break;
196 case SQLITE_INDEX_CONSTRAINT_NE:
197 HandleIndexConstraintNQ(remove, value);
198 break;
199 case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
200 break;
201 default:
202 break;
203 } // end of switch (op)
204 }
HandleIndexConstraintEQ(bool remove, uint64_t value)205 void ProcessTable::Cursor::HandleIndexConstraintEQ(bool remove, uint64_t value)
206 {
207 if (remove) {
208 for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) {
209 if (dataCache_->GetConstProcessData()[*i].pid_ != value) {
210 i = indexMap_->rowIndex_.erase(i);
211 } else {
212 i++;
213 }
214 }
215 } else {
216 for (auto i = 0; i < dataCache_->GetConstProcessData().size(); i++) {
217 if (dataCache_->GetConstProcessData()[i].pid_ == value) {
218 indexMap_->rowIndex_.push_back(i);
219 }
220 }
221 }
222 indexMap_->FixSize();
223 }
HandleIndexConstraintNQ(bool remove, uint64_t value)224 void ProcessTable::Cursor::HandleIndexConstraintNQ(bool remove, uint64_t value)
225 {
226 if (remove) {
227 for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) {
228 if (dataCache_->GetConstProcessData()[*i].pid_ == value) {
229 i = indexMap_->rowIndex_.erase(i);
230 } else {
231 i++;
232 }
233 }
234 } else {
235 for (auto i = 0; i < dataCache_->GetConstProcessData().size(); i++) {
236 if (dataCache_->GetConstProcessData()[i].pid_ != value) {
237 indexMap_->rowIndex_.push_back(i);
238 }
239 }
240 }
241 indexMap_->FixSize();
242 }
FilterIndex(int32_t col, unsigned char op, sqlite3_value *argv)243 void ProcessTable::Cursor::FilterIndex(int32_t col, unsigned char op, sqlite3_value *argv)
244 {
245 switch (static_cast<Index>(col)) {
246 case Index::PID:
247 /* code */
248 FilterPid(op, static_cast<uint64_t>(sqlite3_value_int64(argv)));
249 break;
250
251 default:
252 break;
253 }
254 }
FilterId(unsigned char op, sqlite3_value *argv)255 void ProcessTable::Cursor::FilterId(unsigned char op, sqlite3_value *argv)
256 {
257 auto procArgv = static_cast<TableRowId>(sqlite3_value_int64(argv));
258 switch (op) {
259 case SQLITE_INDEX_CONSTRAINT_EQ:
260 indexMap_->Intersect(procArgv, procArgv + 1);
261 break;
262 case SQLITE_INDEX_CONSTRAINT_GE:
263 indexMap_->Intersect(procArgv, rowCount_);
264 break;
265 case SQLITE_INDEX_CONSTRAINT_GT:
266 procArgv++;
267 indexMap_->Intersect(procArgv, rowCount_);
268 break;
269 case SQLITE_INDEX_CONSTRAINT_LE:
270 procArgv++;
271 indexMap_->Intersect(0, procArgv);
272 break;
273 case SQLITE_INDEX_CONSTRAINT_LT:
274 indexMap_->Intersect(0, procArgv);
275 break;
276 default:
277 // can't filter, all rows
278 break;
279 }
280 }
281
GetOrbyes(FilterConstraints &processfc, EstimatedIndexInfo &processei)282 void ProcessTable::GetOrbyes(FilterConstraints &processfc, EstimatedIndexInfo &processei)
283 {
284 auto processorderbys = processfc.GetOrderBys();
285 for (auto i = 0; i < processorderbys.size(); i++) {
286 switch (static_cast<Index>(processorderbys[i].iColumn)) {
287 case Index::IPID:
288 case Index::ID:
289 break;
290 default: // other columns can be sorted by SQLite
291 processei.isOrdered = false;
292 break;
293 }
294 }
295 }
296 } // namespace TraceStreamer
297 } // namespace SysTuning
298