• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 namespace {
21 enum Index {ID = 0, IPID, TYPE, PID, NAME, START_TS, SWITCH_COUNT, THREAD_COUNT, SLICE_COUNT, MEM_COUNT };
22 }
ProcessTable(const TraceDataCache * dataCache)23 ProcessTable::ProcessTable(const TraceDataCache* dataCache) : TableBase(dataCache)
24 {
25     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
26     tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
27     tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT"));
28     tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER"));
29     tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
30     tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER"));
31     tableColumn_.push_back(TableBase::ColumnInfo("swtich_count", "INTEGER"));
32     tableColumn_.push_back(TableBase::ColumnInfo("thread_count", "INTEGER"));
33     tableColumn_.push_back(TableBase::ColumnInfo("slice_count", "INTEGER"));
34     tableColumn_.push_back(TableBase::ColumnInfo("mem_count", "INTEGER"));
35     tablePriKey_.push_back("id");
36 }
37 
~ProcessTable()38 ProcessTable::~ProcessTable() {}
39 
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)40 void ProcessTable::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_->ProcessSize();
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 IPID:
69             case ID:
70                 break;
71             default: // other columns can be sorted by SQLite
72                 ei.isOrdered = false;
73                 break;
74         }
75     }
76 }
77 
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)78 void ProcessTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
79 {
80     auto fcConstraints = fc.GetConstraints();
81     for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
82         if (rowCount <= 1) {
83             // only one row or nothing, needn't filter by constraint
84             filterCost += rowCount;
85             break;
86         }
87         const auto& c = fcConstraints[i];
88         switch (c.col) {
89             case IPID:
90             case ID: {
91                 if (CanFilterId(c.op, rowCount)) {
92                     fc.UpdateConstraint(i, true);
93                     filterCost += 1; // id can position by 1 step
94                 } else {
95                     filterCost += rowCount; // scan all rows
96                 }
97                 break;
98             }
99             default:                    // other column
100                 filterCost += rowCount; // scan all rows
101                 break;
102         }
103     }
104 }
105 
CanFilterId(const char op,size_t & rowCount)106 bool ProcessTable::CanFilterId(const char op, size_t& rowCount)
107 {
108     switch (op) {
109         case SQLITE_INDEX_CONSTRAINT_EQ:
110             rowCount = 1;
111             break;
112         case SQLITE_INDEX_CONSTRAINT_GT:
113         case SQLITE_INDEX_CONSTRAINT_GE:
114         case SQLITE_INDEX_CONSTRAINT_LE:
115         case SQLITE_INDEX_CONSTRAINT_LT:
116             // assume filter out a half of rows
117             rowCount = (rowCount >> 1);
118             break;
119         default:
120             return false;
121     }
122     return true;
123 }
124 
Update(int argc,sqlite3_value ** argv,sqlite3_int64 * pRowid)125 int ProcessTable::Update(int argc, sqlite3_value** argv, sqlite3_int64* pRowid)
126 {
127     if (argc <= 1) {
128         return SQLITE_READONLY;
129     }
130     if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
131         return SQLITE_READONLY;
132     }
133     auto id = sqlite3_value_int64(argv[0]);
134     auto process = wdataCache_->GetProcessData(static_cast<InternalPid>(id));
135     constexpr int colOffset = 2;
136     for (auto i = colOffset; i < argc; i++) {
137         auto col = i - colOffset;
138         if (col != NAME) {
139             continue;
140         }
141         const char* name = reinterpret_cast<const char*>(sqlite3_value_text(argv[i]));
142         if (name == nullptr) {
143             process->cmdLine_.clear();
144         } else {
145             process->cmdLine_ = name;
146         }
147         break;
148     }
149     return SQLITE_OK;
150 }
151 
CreateCursor()152 std::unique_ptr<TableBase::Cursor> ProcessTable::CreateCursor()
153 {
154     return std::make_unique<Cursor>(dataCache_, this);
155 }
156 
Cursor(const TraceDataCache * dataCache,TableBase * table)157 ProcessTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
158     : TableBase::Cursor(dataCache, table, dataCache->ProcessSize())
159 {
160 }
161 
~Cursor()162 ProcessTable::Cursor::~Cursor() {}
163 
Filter(const FilterConstraints & fc,sqlite3_value ** argv)164 int ProcessTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
165 {
166     // reset indexMap_
167     indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
168 
169     if (rowCount_ <= 0) {
170         return SQLITE_OK;
171     }
172 
173     auto& cs = fc.GetConstraints();
174     for (size_t i = 0; i < cs.size(); i++) {
175         const auto& c = cs[i];
176         switch (c.col) {
177             case ID:
178             case IPID:
179                 FilterId(c.op, argv[i]);
180                 break;
181             case PID:
182                 FilterIndex(c.col, c.op, argv[i]);
183                 break;
184             default:
185                 break;
186         }
187     }
188 
189     auto orderbys = fc.GetOrderBys();
190     for (auto i = orderbys.size(); i > 0;) {
191         i--;
192         switch (orderbys[i].iColumn) {
193             case ID:
194             case IPID:
195                 indexMap_->SortBy(orderbys[i].desc);
196                 break;
197             default:
198                 break;
199         }
200     }
201 
202     return SQLITE_OK;
203 }
204 
Column(int col) const205 int ProcessTable::Cursor::Column(int col) const
206 {
207     const auto& process = dataCache_->GetConstProcessData(CurrentRow());
208     switch (col) {
209         case ID:
210         case IPID:
211             sqlite3_result_int64(context_, CurrentRow());
212             break;
213         case TYPE:
214             sqlite3_result_text(context_, "process", STR_DEFAULT_LEN, nullptr);
215             break;
216         case PID:
217             sqlite3_result_int64(context_, process.pid_);
218             break;
219         case NAME:
220             if (process.cmdLine_.size()) {
221                 sqlite3_result_text(context_, process.cmdLine_.c_str(), static_cast<int>(process.cmdLine_.length()),
222                                     nullptr);
223             }
224             break;
225         case START_TS:
226             if (process.startT_) {
227                 sqlite3_result_int64(context_, static_cast<int64_t>(process.startT_));
228             }
229             break;
230         case SWITCH_COUNT:
231             sqlite3_result_int64(context_, process.switchCount_);
232             break;
233         case THREAD_COUNT:
234             sqlite3_result_int64(context_, process.threadCount_);
235             break;
236         case SLICE_COUNT:
237             sqlite3_result_int64(context_, process.sliceSize_);
238             break;
239         case MEM_COUNT:
240             sqlite3_result_int64(context_, process.memSize_);
241             break;
242         default:
243             TS_LOGF("Unregistered column : %d", col);
244             break;
245     }
246     return SQLITE_OK;
247 }
248 
FilterPid(unsigned char op,uint64_t value)249 void ProcessTable::Cursor::FilterPid(unsigned char op, uint64_t value)
250 {
251     bool remove = false;
252     if (indexMap_->HasData()) {
253         indexMap_->CovertToIndexMap();
254         remove = true;
255     }
256     const auto& processQueue = dataCache_->GetConstProcessData();
257     auto size = processQueue.size();
258     switch (op) {
259         case SQLITE_INDEX_CONSTRAINT_EQ:
260             if (remove) {
261                 for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) {
262                     if (processQueue[*i].pid_ != value) {
263                         i = indexMap_->rowIndex_.erase(i);
264                     } else {
265                         i++;
266                     }
267                 }
268             } else {
269                 for (auto i = 0; i < size; i++) {
270                     if (processQueue[i].pid_ == value) {
271                         indexMap_->rowIndex_.push_back(i);
272                     }
273                 }
274             }
275             indexMap_->FixSize();
276             break;
277         case SQLITE_INDEX_CONSTRAINT_NE:
278             if (remove) {
279                 for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) {
280                     if (processQueue[*i].pid_ == value) {
281                         i = indexMap_->rowIndex_.erase(i);
282                     } else {
283                         i++;
284                     }
285                 }
286             } else {
287                 for (auto i = 0; i < size; i++) {
288                     if (processQueue[i].pid_ != value) {
289                         indexMap_->rowIndex_.push_back(i);
290                     }
291                 }
292             }
293             indexMap_->FixSize();
294             break;
295         case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
296             break;
297         default:
298             break;
299     } // end of switch (op)
300 }
FilterIndex(int col,unsigned char op,sqlite3_value * argv)301 void ProcessTable::Cursor::FilterIndex(int col, unsigned char op, sqlite3_value* argv)
302 {
303     auto type = sqlite3_value_type(argv);
304     switch (col) {
305         case PID:
306             /* code */
307             FilterPid(op, static_cast<uint64_t>(sqlite3_value_int64(argv)));
308             break;
309 
310         default:
311             break;
312     }
313 }
FilterId(unsigned char op,sqlite3_value * argv)314 void ProcessTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv)
315 {
316     auto type = sqlite3_value_type(argv);
317     auto v = static_cast<TableRowId>(sqlite3_value_int64(argv));
318     switch (op) {
319         case SQLITE_INDEX_CONSTRAINT_EQ:
320             indexMap_->Intersect(v, v + 1);
321             break;
322         case SQLITE_INDEX_CONSTRAINT_GE:
323             indexMap_->Intersect(v, rowCount_);
324             break;
325         case SQLITE_INDEX_CONSTRAINT_GT:
326             v++;
327             indexMap_->Intersect(v, rowCount_);
328             break;
329         case SQLITE_INDEX_CONSTRAINT_LE:
330             v++;
331             indexMap_->Intersect(0, v);
332             break;
333         case SQLITE_INDEX_CONSTRAINT_LT:
334             indexMap_->Intersect(0, v);
335             break;
336         default:
337             // can't filter, all rows
338             break;
339     }
340 }
341 } // namespace TraceStreamer
342 } // namespace SysTuning
343