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