• 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 "thread_table.h"
17 
18 namespace SysTuning {
19 namespace TraceStreamer {
20 enum Index { ID = 0, ITID, TYPE, TID, NAME, START_TS, END_TS, INTERNAL_PID, IS_MAIN_THREAD, SWITCH_COUNT };
ThreadTable(const TraceDataCache * dataCache)21 ThreadTable::ThreadTable(const TraceDataCache* dataCache) : TableBase(dataCache)
22 {
23     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
24     tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER"));
25     tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT"));
26     tableColumn_.push_back(TableBase::ColumnInfo("tid", "INTEGER"));
27     tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
28     tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER"));
29     tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER"));
30     tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
31     tableColumn_.push_back(TableBase::ColumnInfo("is_main_thread", "INTEGER"));
32     tableColumn_.push_back(TableBase::ColumnInfo("switch_count", "INTEGER"));
33     tablePriKey_.push_back("id");
34 }
35 
~ThreadTable()36 ThreadTable::~ThreadTable() {}
37 
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)38 void ThreadTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
39 {
40     constexpr double filterBaseCost = 1000.0; // set-up and tear-down
41     constexpr double indexCost = 2.0;
42     ei.estimatedCost = filterBaseCost;
43 
44     auto rowCount = dataCache_->ThreadSize();
45     if (rowCount == 0 || rowCount == 1) {
46         ei.estimatedRows = rowCount;
47         ei.estimatedCost += indexCost * rowCount;
48         return;
49     }
50 
51     double filterCost = 0.0;
52     auto constraints = fc.GetConstraints();
53     if (constraints.empty()) { // scan all rows
54         filterCost = rowCount;
55     } else {
56         FilterByConstraint(fc, filterCost, rowCount);
57     }
58     ei.estimatedCost += filterCost;
59     ei.estimatedRows = rowCount;
60     ei.estimatedCost += rowCount * indexCost;
61 
62     ei.isOrdered = true;
63     auto orderbys = fc.GetOrderBys();
64     for (auto i = 0; i < orderbys.size(); i++) {
65         switch (orderbys[i].iColumn) {
66             case ITID:
67             case ID:
68                 break;
69             default: // other columns can be sorted by SQLite
70                 ei.isOrdered = false;
71                 break;
72         }
73     }
74 }
75 
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)76 void ThreadTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
77 {
78     auto fcConstraints = fc.GetConstraints();
79     for (int32_t i = 0; i < static_cast<int32_t>(fcConstraints.size()); i++) {
80         if (rowCount <= 1) {
81             // only one row or nothing, needn't filter by constraint
82             filterCost += rowCount;
83             break;
84         }
85         const auto& c = fcConstraints[i];
86         switch (c.col) {
87             case ITID:
88             case ID: {
89                 if (CanFilterId(c.op, rowCount)) {
90                     fc.UpdateConstraint(i, true);
91                     filterCost += 1; // id can position by 1 step
92                 } else {
93                     filterCost += rowCount; // scan all rows
94                 }
95                 break;
96             }
97             default:                    // other column
98                 filterCost += rowCount; // scan all rows
99                 break;
100         }
101     }
102 }
103 
CreateCursor()104 std::unique_ptr<TableBase::Cursor> ThreadTable::CreateCursor()
105 {
106     return std::make_unique<Cursor>(dataCache_, this);
107 }
108 
Cursor(const TraceDataCache * dataCache,TableBase * table)109 ThreadTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
110     : TableBase::Cursor(dataCache, table, dataCache->ThreadSize())
111 {
112 }
113 
~Cursor()114 ThreadTable::Cursor::~Cursor() {}
FilterTid(unsigned char op,uint64_t value)115 void ThreadTable::Cursor::FilterTid(unsigned char op, uint64_t value)
116 {
117     bool remove = false;
118     if (indexMapBack_->HasData()) {
119         indexMapBack_->CovertToIndexMap();
120         remove = true;
121     }
122     const auto& threadQueue = dataCache_->GetConstThreadData();
123     auto size = threadQueue.size();
124     switch (op) {
125         case SQLITE_INDEX_CONSTRAINT_EQ:
126             if (remove) {
127                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
128                     if (threadQueue[*i].tid_ != value) {
129                         i = indexMapBack_->rowIndex_.erase(i);
130                     } else {
131                         i++;
132                     }
133                 }
134             } else {
135                 for (auto i = 0; i < size; i++) {
136                     if (threadQueue[i].tid_ == value) {
137                         indexMapBack_->rowIndex_.push_back(i);
138                     }
139                 }
140             }
141             indexMapBack_->FixSize();
142             break;
143         case SQLITE_INDEX_CONSTRAINT_ISNOT:
144         case SQLITE_INDEX_CONSTRAINT_NE:
145             if (remove) {
146                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
147                     if (threadQueue[*i].tid_ == value) {
148                         i = indexMapBack_->rowIndex_.erase(i);
149                     } else {
150                         i++;
151                     }
152                 }
153             } else {
154                 for (auto i = 0; i < size; i++) {
155                     if (threadQueue[i].tid_ != value) {
156                         indexMapBack_->rowIndex_.push_back(i);
157                     }
158                 }
159             }
160             indexMapBack_->FixSize();
161             break;
162         default:
163             break;
164     } // end of switch (op)
165 }
FilterIpid(unsigned char op,uint64_t value)166 void ThreadTable::Cursor::FilterIpid(unsigned char op, uint64_t value)
167 {
168     bool remove = false;
169     if (indexMapBack_->HasData()) {
170         indexMapBack_->CovertToIndexMap();
171         remove = true;
172     }
173     const auto& threadQueue = dataCache_->GetConstThreadData();
174     auto size = threadQueue.size();
175     rowIndexBak_.clear();
176     bool changed = false;
177     switch (op) {
178         case SQLITE_INDEX_CONSTRAINT_EQ:
179             if (remove) {
180                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
181                     if (threadQueue[*i].internalPid_ != value) {
182                         i++;
183                     } else {
184                         changed = true;
185                         rowIndexBak_.push_back(*i);
186                         i++;
187                     }
188                 }
189                 if (changed) {
190                     indexMapBack_->rowIndex_ = rowIndexBak_;
191                 }
192             } else {
193                 for (auto i = 0; i < size; i++) {
194                     if (threadQueue[i].internalPid_ == value) {
195                         indexMapBack_->rowIndex_.push_back(i);
196                     }
197                 }
198             }
199             indexMapBack_->FixSize();
200             break;
201         case SQLITE_INDEX_CONSTRAINT_ISNULL:
202             if (remove) {
203                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
204                     if (threadQueue[*i].internalPid_ != INVALID_UINT32) {
205                         i++;
206                     } else {
207                         changed = true;
208                         rowIndexBak_.push_back(*i);
209                         i++;
210                     }
211                 }
212                 if (changed) {
213                     indexMapBack_->rowIndex_ = rowIndexBak_;
214                 }
215             } else {
216                 for (auto i = 0; i < size; i++) {
217                     if (threadQueue[i].internalPid_ == INVALID_UINT32) {
218                         indexMapBack_->rowIndex_.push_back(i);
219                     }
220                 }
221             }
222             indexMapBack_->FixSize();
223             break;
224         case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
225             if (remove) {
226                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
227                     if (threadQueue[*i].internalPid_ == INVALID_UINT32) {
228                         i++;
229                     } else {
230                         changed = true;
231                         rowIndexBak_.push_back(*i);
232                         i++;
233                     }
234                 }
235                 if (changed) {
236                     indexMapBack_->rowIndex_ = rowIndexBak_;
237                 }
238             } else {
239                 for (auto i = 0; i < size; i++) {
240                     if (threadQueue[i].internalPid_ != INVALID_UINT32) {
241                         indexMapBack_->rowIndex_.push_back(i);
242                     }
243                 }
244             }
245             indexMapBack_->FixSize();
246             break;
247         default:
248             break;
249     } // end of switch (op)
250 }
FilterSwitchCount(unsigned char op,uint64_t value)251 void ThreadTable::Cursor::FilterSwitchCount(unsigned char op, uint64_t value)
252 {
253     bool remove = false;
254     if (indexMapBack_->HasData()) {
255         indexMapBack_->CovertToIndexMap();
256         remove = true;
257     }
258     const auto& threadQueue = dataCache_->GetConstThreadData();
259     auto size = threadQueue.size();
260     rowIndexBak_.clear();
261     bool changed = false;
262     switch (op) {
263         case SQLITE_INDEX_CONSTRAINT_EQ:
264             if (remove) {
265                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
266                     if (threadQueue[*i].switchCount_ != value) {
267                         i++;
268                     } else {
269                         changed = true;
270                         rowIndexBak_.push_back(*i);
271                         i++;
272                     }
273                 }
274                 if (changed) {
275                     indexMapBack_->rowIndex_ = rowIndexBak_;
276                 }
277             } else {
278                 for (auto i = 0; i < size; i++) {
279                     if (threadQueue[i].switchCount_ == value) {
280                         indexMapBack_->rowIndex_.push_back(i);
281                     }
282                 }
283             }
284             indexMapBack_->FixSize();
285             break;
286         case SQLITE_INDEX_CONSTRAINT_ISNULL:
287             if (remove) {
288                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
289                     if (threadQueue[*i].switchCount_ != INVALID_UINT32) {
290                         i++;
291                     } else {
292                         changed = true;
293                         rowIndexBak_.push_back(*i);
294                         i++;
295                     }
296                 }
297                 if (changed) {
298                     indexMapBack_->rowIndex_ = rowIndexBak_;
299                 }
300             } else {
301                 for (auto i = 0; i < size; i++) {
302                     if (threadQueue[i].switchCount_ == INVALID_UINT32) {
303                         indexMapBack_->rowIndex_.push_back(i);
304                     }
305                 }
306             }
307             indexMapBack_->FixSize();
308             break;
309         case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
310             if (remove) {
311                 for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) {
312                     if (threadQueue[*i].switchCount_ == INVALID_UINT32) {
313                         i++;
314                     } else {
315                         changed = true;
316                         rowIndexBak_.push_back(*i);
317                         i++;
318                     }
319                 }
320                 if (changed) {
321                     indexMapBack_->rowIndex_ = rowIndexBak_;
322                 }
323             } else {
324                 for (auto i = 0; i < size; i++) {
325                     if (threadQueue[i].switchCount_ != INVALID_UINT32) {
326                         indexMapBack_->rowIndex_.push_back(i);
327                     }
328                 }
329             }
330             indexMapBack_->FixSize();
331             break;
332         default:
333             break;
334     } // end of switch (op)
335 }
FilterIndex(int32_t col,unsigned char op,sqlite3_value * argv)336 void ThreadTable::Cursor::FilterIndex(int32_t col, unsigned char op, sqlite3_value* argv)
337 {
338     switch (col) {
339         case INTERNAL_PID:
340             FilterIpid(op, static_cast<uint64_t>(sqlite3_value_int64(argv)));
341             break;
342         case TID:
343             FilterTid(op, static_cast<uint64_t>(sqlite3_value_int64(argv)));
344             break;
345         case SWITCH_COUNT:
346             FilterSwitchCount(op, static_cast<uint64_t>(sqlite3_value_int64(argv)));
347             break;
348         default:
349             // we can't filter all rows
350             break;
351     }
352 }
Filter(const FilterConstraints & fc,sqlite3_value ** argv)353 int32_t ThreadTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
354 {
355     // reset indexMapBack_
356     if (rowCount_ <= 0) {
357         return SQLITE_OK;
358     }
359     indexMapBack_ = indexMap_.get();
360     if (indexMap_->HasData()) {
361         indexMapBack_ = std::make_unique<IndexMap>(0, rowCount_).get();
362     }
363     auto& cs = fc.GetConstraints();
364     for (size_t i = 0; i < cs.size(); i++) {
365         const auto& c = cs[i];
366         switch (c.col) {
367             case ID:
368             case ITID:
369                 FilterId(c.op, argv[i]);
370                 break;
371             case TID:
372             case INTERNAL_PID:
373             case SWITCH_COUNT:
374                 FilterIndex(c.col, c.op, argv[i]);
375                 break;
376             default:
377                 break;
378         }
379     }
380     if (indexMap_->HasData()) {
381         indexMap_->Merge(indexMapBack_);
382     }
383 
384     auto orderbys = fc.GetOrderBys();
385     for (auto i = orderbys.size(); i > 0;) {
386         i--;
387         switch (orderbys[i].iColumn) {
388             case ID:
389             case ITID:
390                 indexMap_->SortBy(orderbys[i].desc);
391                 break;
392             default:
393                 break;
394         }
395     }
396 
397     return SQLITE_OK;
398 }
399 
Column(int32_t col) const400 int32_t ThreadTable::Cursor::Column(int32_t col) const
401 {
402     const auto& thread = dataCache_->GetConstThreadData(CurrentRow());
403     switch (col) {
404         case ID:
405         case ITID: {
406             sqlite3_result_int64(context_, CurrentRow());
407             break;
408         }
409         case TYPE: {
410             sqlite3_result_text(context_, "thread", strlen("thread"), nullptr);
411             break;
412         }
413         case TID: {
414             sqlite3_result_int64(context_, static_cast<int32_t>(thread.tid_));
415             break;
416         }
417         case NAME: {
418             const auto& name = dataCache_->GetDataFromDict(thread.nameIndex_);
419             if (name.size()) {
420                 sqlite3_result_text(context_, name.c_str(), static_cast<int32_t>(name.length()), nullptr);
421             }
422             break;
423         }
424         case START_TS: {
425             if (thread.startT_) {
426                 sqlite3_result_int64(context_, static_cast<int64_t>(thread.startT_));
427             }
428             break;
429         }
430         case END_TS: {
431             if (thread.endT_) {
432                 sqlite3_result_int64(context_, static_cast<int64_t>(thread.endT_));
433             }
434             break;
435         }
436         case INTERNAL_PID: {
437             if (thread.internalPid_ != INVALID_UINT32) {
438                 sqlite3_result_int(context_, static_cast<int32_t>(thread.internalPid_));
439             }
440             break;
441         }
442         case IS_MAIN_THREAD: {
443             // When it is not clear which process the thread belongs to, is_main_thread should be set to null
444             if (thread.internalPid_ == INVALID_UINT32) {
445                 break;
446             }
447             const auto& process = dataCache_->GetConstProcessData(thread.internalPid_);
448             sqlite3_result_int(context_, thread.tid_ == process.pid_);
449             break;
450         }
451         case SWITCH_COUNT: {
452             // When it is not clear which process the thread belongs to, is_main_thread should be set to null
453             sqlite3_result_int(context_, thread.switchCount_);
454             break;
455         }
456 
457         default:
458             TS_LOGF("Unregistered column : %d", col);
459             break;
460     }
461     return SQLITE_OK;
462 }
463 
Update(int32_t argc,sqlite3_value ** argv,sqlite3_int64 * pRowid)464 int32_t ThreadTable::Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid)
465 {
466     if (argc <= 1) {
467         return SQLITE_READONLY;
468     }
469     if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
470         return SQLITE_READONLY;
471     }
472     auto id = sqlite3_value_int64(argv[0]);
473     auto thread = wdataCache_->GetThreadData(static_cast<InternalPid>(id));
474     constexpr int32_t colOffset = 2;
475     for (auto i = colOffset; i < argc; i++) {
476         auto col = i - colOffset;
477         if (col != INTERNAL_PID) {
478             continue;
479         }
480         auto ipid = static_cast<uint32_t>(sqlite3_value_int(argv[i]));
481         if (ipid) {
482             thread->internalPid_ = ipid;
483         }
484         break;
485     }
486     return SQLITE_OK;
487 }
FilterId(unsigned char op,sqlite3_value * argv)488 void ThreadTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv)
489 {
490     auto type = sqlite3_value_type(argv);
491     if (type != SQLITE_INTEGER) {
492         // other type consider it NULL
493         indexMapBack_->Intersect(0, 0);
494         return;
495     }
496 
497     auto v = static_cast<TableRowId>(sqlite3_value_int64(argv));
498     switch (op) {
499         case SQLITE_INDEX_CONSTRAINT_EQ:
500             indexMapBack_->Intersect(v, v + 1);
501             break;
502         case SQLITE_INDEX_CONSTRAINT_GE:
503             indexMapBack_->Intersect(v, rowCount_);
504             break;
505         case SQLITE_INDEX_CONSTRAINT_GT:
506             v++;
507             indexMapBack_->Intersect(v, rowCount_);
508             break;
509         case SQLITE_INDEX_CONSTRAINT_LE:
510             v++;
511             indexMapBack_->Intersect(0, v);
512             break;
513         case SQLITE_INDEX_CONSTRAINT_LT:
514             indexMapBack_->Intersect(0, v);
515             break;
516         default:
517             // can't filter, all rows
518             break;
519     }
520 }
521 } // namespace TraceStreamer
522 } // namespace SysTuning
523