• 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 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