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 "thread_state_table.h"
17 #include "thread_state_flag.h"
18 
19 #include <cmath>
20 
21 namespace SysTuning {
22 namespace TraceStreamer {
23 enum class Index : int32_t { ID = 0, TS, DUR, CPU, INTERNAL_TID, TID, PID, STATE, ARGSETID };
ThreadStateTable(const TraceDataCache *dataCache)24 ThreadStateTable::ThreadStateTable(const TraceDataCache *dataCache) : TableBase(dataCache)
25 {
26     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
27     tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER"));
28     tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
29     tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER"));
30     tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER"));
31     tableColumn_.push_back(TableBase::ColumnInfo("tid", "INTEGER"));
32     tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER"));
33     tableColumn_.push_back(TableBase::ColumnInfo("state", "TEXT"));
34     tableColumn_.push_back(TableBase::ColumnInfo("arg_setid", "INTEGER"));
35     tablePriKey_.push_back("id");
36 }
37 
~ThreadStateTable()38 ThreadStateTable::~ThreadStateTable() {}
39 
FilterByConstraint(FilterConstraints &statefc, double &statefilterCost, size_t staterowCount, uint32_t statecurrenti)40 void ThreadStateTable::FilterByConstraint(FilterConstraints &statefc,
41                                           double &statefilterCost,
42                                           size_t staterowCount,
43                                           uint32_t statecurrenti)
44 {
45     // To use the EstimateFilterCost function in the TableBase parent class function to calculate the i-value of each
46     // for loop
47     const auto &statec = statefc.GetConstraints()[statecurrenti];
48     switch (static_cast<Index>(statec.col)) {
49         case Index::ID: {
50             if (CanFilterId(statec.op, staterowCount)) {
51                 statefc.UpdateConstraint(statecurrenti, true);
52                 statefilterCost += 1; // id can position by 1 step
53             } else {
54                 statefilterCost += staterowCount; // scan all rows
55             }
56             break;
57         }
58         case Index::TS: {
59             auto stateoldRowCount = staterowCount;
60             if (CanFilterSorted(statec.op, staterowCount)) {
61                 statefc.UpdateConstraint(statecurrenti, true);
62                 statefilterCost += log2(stateoldRowCount); // binary search
63             } else {
64                 statefilterCost += stateoldRowCount;
65             }
66             break;
67         }
68         default:                              // other column
69             statefilterCost += staterowCount; // scan all rows
70             break;
71     }
72 }
73 
CreateCursor()74 std::unique_ptr<TableBase::Cursor> ThreadStateTable::CreateCursor()
75 {
76     return std::make_unique<Cursor>(dataCache_, this);
77 }
78 
Cursor(const TraceDataCache *dataCache, TableBase *table)79 ThreadStateTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
80     : TableBase::Cursor(dataCache, table, dataCache->GetConstThreadStateData().Size()),
81       threadStateObj_(dataCache->GetConstThreadStateData())
82 {
83 }
84 
~Cursor()85 ThreadStateTable::Cursor::~Cursor() {}
86 
Filter(const FilterConstraints &fc, sqlite3_value **argv)87 int32_t ThreadStateTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
88 {
89     // reset
90     if (rowCount_ <= 0) {
91         return SQLITE_OK;
92     }
93     IndexMap *indexMapBack = indexMap_.get();
94     if (indexMap_->HasData()) {
95         indexMapBack = std::make_unique<IndexMap>(0, rowCount_).get();
96     }
97     HandleIndex(fc, argv, indexMapBack);
98     if (indexMap_->HasData()) {
99         indexMap_->Merge(indexMapBack);
100     }
101 
102     auto ThreadStateOrderbys = fc.GetOrderBys();
103     for (auto i = ThreadStateOrderbys.size(); i > 0;) {
104         i--;
105         switch (static_cast<Index>(ThreadStateOrderbys[i].iColumn)) {
106             case Index::ID:
107             case Index::TS:
108                 indexMap_->SortBy(ThreadStateOrderbys[i].desc);
109                 break;
110             default:
111                 break;
112         }
113     }
114 
115     return SQLITE_OK;
116 }
117 
HandleIndex(const FilterConstraints &fc, sqlite3_value **argv, IndexMap *indexMapBack)118 void ThreadStateTable::Cursor::HandleIndex(const FilterConstraints &fc, sqlite3_value **argv, IndexMap *indexMapBack)
119 {
120     auto cs = fc.GetConstraints();
121     std::set<uint32_t> sId = {static_cast<uint32_t>(Index::TS)};
122     SwapIndexFront(cs, sId);
123     for (size_t i = 0; i < cs.size(); i++) {
124         const auto &c = cs[i];
125         switch (static_cast<Index>(c.col)) {
126             case Index::ID:
127                 indexMapBack->FilterId(c.op, argv[c.idxInaConstraint]);
128                 break;
129             case Index::TS:
130                 indexMapBack->FilterTS(c.op, argv[c.idxInaConstraint], threadStateObj_.TimeStampData());
131                 break;
132             case Index::INTERNAL_TID:
133                 indexMapBack->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
134                                        threadStateObj_.ItidsData());
135                 break;
136             case Index::TID:
137                 indexMapBack->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
138                                        threadStateObj_.TidsData());
139                 break;
140             case Index::PID:
141                 indexMapBack->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
142                                        threadStateObj_.PidsData());
143                 break;
144             case Index::DUR:
145                 indexMapBack->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[c.idxInaConstraint])),
146                                        threadStateObj_.DursData());
147                 break;
148             case Index::CPU:
149                 indexMapBack->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
150                                        threadStateObj_.CpusData());
151                 break;
152             case Index::STATE:
153                 indexMapBack->MixRange(
154                     c.op,
155                     static_cast<DataIndex>(dataCache_->GetThreadStateValue(
156                         std::string(reinterpret_cast<const char *>(sqlite3_value_text(argv[c.idxInaConstraint]))))),
157                     threadStateObj_.StatesData());
158                 break;
159             case Index::ARGSETID:
160                 indexMapBack->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
161                                        threadStateObj_.ArgSetsData());
162                 break;
163             default:
164                 break;
165         }
166     }
167 }
168 
Column(int32_t col) const169 int32_t ThreadStateTable::Cursor::Column(int32_t col) const
170 {
171     switch (static_cast<Index>(col)) {
172         case Index::ID:
173             sqlite3_result_int64(context_, static_cast<int32_t>(threadStateObj_.IdsData()[CurrentRow()]));
174             break;
175         case Index::TS:
176             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(threadStateObj_.TimeStampData()[CurrentRow()]));
177             break;
178         case Index::DUR:
179             SetTypeColumnInt64(threadStateObj_.DursData()[CurrentRow()], INVALID_UINT64);
180             break;
181         case Index::CPU:
182             if (threadStateObj_.CpusData()[CurrentRow()] != INVALID_CPU) {
183                 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(threadStateObj_.CpusData()[CurrentRow()]));
184             }
185             break;
186         case Index::INTERNAL_TID:
187             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(threadStateObj_.ItidsData()[CurrentRow()]));
188             break;
189         case Index::TID:
190             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(threadStateObj_.TidsData()[CurrentRow()]));
191             break;
192         case Index::PID:
193             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(threadStateObj_.PidsData()[CurrentRow()]));
194             break;
195         case Index::STATE: {
196             const std::string &str = dataCache_->GetConstSchedStateData(threadStateObj_.StatesData()[CurrentRow()]);
197             sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr);
198             break;
199         }
200         case Index::ARGSETID:
201             if (threadStateObj_.ArgSetsData()[CurrentRow()] != INVALID_UINT32) {
202                 sqlite3_result_int64(context_, static_cast<sqlite3_int64>(threadStateObj_.ArgSetsData()[CurrentRow()]));
203             }
204             break;
205         default:
206             TS_LOGF("Unregistered column : %d", col);
207             break;
208     }
209     return SQLITE_OK;
210 }
211 
GetOrbyes(FilterConstraints &statefc, EstimatedIndexInfo &stateei)212 void ThreadStateTable::GetOrbyes(FilterConstraints &statefc, EstimatedIndexInfo &stateei)
213 {
214     auto stateorderbys = statefc.GetOrderBys();
215     for (auto i = 0; i < stateorderbys.size(); i++) {
216         switch (static_cast<Index>(stateorderbys[i].iColumn)) {
217             case Index::ID:
218             case Index::TS:
219                 break;
220             default: // other columns can be sorted by SQLite
221                 stateei.isOrdered = false;
222                 break;
223         }
224     }
225 }
226 } // namespace TraceStreamer
227 } // namespace SysTuning
228