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