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