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 "sched_slice_table.h"
17 
18 #include <cmath>
19 
20 namespace SysTuning {
21 namespace TraceStreamer {
22 enum class Index : int32_t { ID = 0, TS, DUR, TS_END, CPU, INTERNAL_TID, INTERNAL_PID, END_STATE, PRIORITY, ARGSETID };
SchedSliceTable(const TraceDataCache *dataCache)23 SchedSliceTable::SchedSliceTable(const TraceDataCache *dataCache) : TableBase(dataCache)
24 {
25     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
26     tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER"));
27     tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER"));
28     tableColumn_.push_back(TableBase::ColumnInfo("ts_end", "INTEGER"));
29     tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER"));
30     tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER"));
31     tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
32     tableColumn_.push_back(TableBase::ColumnInfo("end_state", "TEXT"));
33     tableColumn_.push_back(TableBase::ColumnInfo("priority", "INTEGER"));
34     tableColumn_.push_back(TableBase::ColumnInfo("arg_setid", "INTEGER"));
35     tablePriKey_.push_back("id");
36 }
37 
~SchedSliceTable()38 SchedSliceTable::~SchedSliceTable() {}
39 
FilterByConstraint(FilterConstraints &schedfc, double &schedfilterCost, size_t schedrowCount, uint32_t schedcurrenti)40 void SchedSliceTable::FilterByConstraint(FilterConstraints &schedfc,
41                                          double &schedfilterCost,
42                                          size_t schedrowCount,
43                                          uint32_t schedcurrenti)
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 &schedc = schedfc.GetConstraints()[schedcurrenti];
48     switch (static_cast<Index>(schedc.col)) {
49         case Index::ID: {
50             if (CanFilterId(schedc.op, schedrowCount)) {
51                 schedfc.UpdateConstraint(schedcurrenti, true);
52                 schedfilterCost += 1; // id can position by 1 step
53             } else {
54                 schedfilterCost += schedrowCount; // scan all rows
55             }
56             break;
57         }
58         case Index::TS: {
59             auto schedoldRowCount = schedrowCount;
60             if (CanFilterSorted(schedc.op, schedrowCount)) {
61                 schedfc.UpdateConstraint(schedcurrenti, true);
62                 schedfilterCost += log2(schedoldRowCount); // binary search
63             } else {
64                 schedfilterCost += schedoldRowCount;
65             }
66             break;
67         }
68         default:                              // other column
69             schedfilterCost += schedrowCount; // scan all rows
70             break;
71     }
72 }
73 
CreateCursor()74 std::unique_ptr<TableBase::Cursor> SchedSliceTable::CreateCursor()
75 {
76     return std::make_unique<Cursor>(dataCache_, this);
77 }
78 
Cursor(const TraceDataCache *dataCache, TableBase *table)79 SchedSliceTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
80     : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstSchedSliceData().Size())),
81       schedSliceObj_(dataCache->GetConstSchedSliceData())
82 {
83 }
84 
~Cursor()85 SchedSliceTable::Cursor::~Cursor() {}
86 
Filter(const FilterConstraints &fc, sqlite3_value **argv)87 int32_t SchedSliceTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
88 {
89     // reset indexMap_
90     indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
91 
92     if (rowCount_ <= 0) {
93         return SQLITE_OK;
94     }
95 
96     auto schedSliceTabCs = fc.GetConstraints();
97     std::set<uint32_t> sId = {static_cast<uint32_t>(Index::TS)};
98     SwapIndexFront(schedSliceTabCs, sId);
99     for (size_t i = 0; i < schedSliceTabCs.size(); i++) {
100         const auto &c = schedSliceTabCs[i];
101         switch (static_cast<Index>(c.col)) {
102             case Index::ID:
103                 FilterId(c.op, argv[c.idxInaConstraint]);
104                 break;
105             case Index::TS:
106                 FilterTS(c.op, argv[c.idxInaConstraint], schedSliceObj_.TimeStampData());
107                 break;
108             case Index::CPU:
109                 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
110                                     schedSliceObj_.CpusData());
111                 break;
112             case Index::INTERNAL_TID:
113                 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
114                                     schedSliceObj_.InternalTidsData());
115                 break;
116             case Index::INTERNAL_PID:
117                 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])),
118                                     schedSliceObj_.InternalPidsData());
119                 break;
120             case Index::DUR:
121                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[c.idxInaConstraint])),
122                                     schedSliceObj_.DursData());
123                 break;
124             default:
125                 break;
126         }
127     }
128 
129     auto schedSliceOrderbys = fc.GetOrderBys();
130     for (auto i = static_cast<int32_t>(schedSliceOrderbys.size()) - 1; i >= 0; i--) {
131         switch (static_cast<Index>(schedSliceOrderbys[i].iColumn)) {
132             case Index::ID:
133             case Index::TS:
134                 indexMap_->SortBy(schedSliceOrderbys[i].desc);
135                 break;
136             default:
137                 break;
138         }
139     }
140 
141     return SQLITE_OK;
142 }
143 
Column(int32_t col) const144 int32_t SchedSliceTable::Cursor::Column(int32_t col) const
145 {
146     switch (static_cast<Index>(col)) {
147         case Index::ID:
148             sqlite3_result_int64(context_, static_cast<int32_t>(schedSliceObj_.IdsData()[CurrentRow()]));
149             break;
150         case Index::TS:
151             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.TimeStampData()[CurrentRow()]));
152             break;
153         case Index::DUR:
154             SetTypeColumnInt64(schedSliceObj_.DursData()[CurrentRow()], INVALID_UINT64);
155             break;
156         case Index::TS_END:
157             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.TsEndData()[CurrentRow()]));
158             break;
159         case Index::CPU:
160             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.CpusData()[CurrentRow()]));
161             break;
162         case Index::INTERNAL_TID:
163             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.InternalTidsData()[CurrentRow()]));
164             break;
165         case Index::INTERNAL_PID:
166             sqlite3_result_int64(context_, static_cast<sqlite3_int64>(schedSliceObj_.InternalPidsData()[CurrentRow()]));
167             break;
168         case Index::END_STATE: {
169             const std::string &str = dataCache_->GetConstSchedStateData(schedSliceObj_.EndStatesData()[CurrentRow()]);
170             sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr);
171             break;
172         }
173         case Index::PRIORITY:
174             sqlite3_result_int(context_, schedSliceObj_.PriorityData()[CurrentRow()]);
175             break;
176         case Index::ARGSETID: {
177             const uint32_t &argSetId = schedSliceObj_.ArgSetData()[CurrentRow()];
178             if (argSetId != INVALID_UINT32) {
179                 sqlite3_result_int(context_, argSetId);
180             }
181             break;
182         }
183         default:
184             TS_LOGF("Unregistered column : %d", col);
185             break;
186     }
187     return SQLITE_OK;
188 }
189 
GetOrbyes(FilterConstraints &schedfc, EstimatedIndexInfo &schedei)190 void SchedSliceTable::GetOrbyes(FilterConstraints &schedfc, EstimatedIndexInfo &schedei)
191 {
192     auto schedorderbys = schedfc.GetOrderBys();
193     for (auto i = 0; i < schedorderbys.size(); i++) {
194         switch (static_cast<Index>(schedorderbys[i].iColumn)) {
195             case Index::ID:
196             case Index::TS:
197                 break;
198             default: // other columns can be sorted by SQLite
199                 schedei.isOrdered = false;
200                 break;
201         }
202     }
203 }
204 } // namespace TraceStreamer
205 } // namespace SysTuning
206