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 "perf_sample_table.h"
17 
18 namespace SysTuning {
19 namespace TraceStreamer {
20 enum class Index : int32_t {
21     ID = 0,
22     CALLCHAIN_ID,
23     TIMESTAMP,
24     THREAD_ID,
25     EVENT_COUNT,
26     EVENT_TYPE_ID,
27     TIMESTAMP_TRACE,
28     CPU_ID,
29     THREAD_STATE
30 };
PerfSampleTable(const TraceDataCache *dataCache)31 PerfSampleTable::PerfSampleTable(const TraceDataCache *dataCache) : TableBase(dataCache)
32 {
33     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
34     tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER"));
35     tableColumn_.push_back(TableBase::ColumnInfo("timeStamp", "INTEGER"));
36     tableColumn_.push_back(TableBase::ColumnInfo("thread_id", "INTEGER"));
37     tableColumn_.push_back(TableBase::ColumnInfo("event_count", "INTEGER"));
38     tableColumn_.push_back(TableBase::ColumnInfo("event_type_id", "INTEGER"));
39     tableColumn_.push_back(TableBase::ColumnInfo("timestamp_trace", "INTEGER"));
40     tableColumn_.push_back(TableBase::ColumnInfo("cpu_id", "INTEGER"));
41     tableColumn_.push_back(TableBase::ColumnInfo("thread_state", "TEXT"));
42     tablePriKey_.push_back("id");
43 }
44 
~PerfSampleTable()45 PerfSampleTable::~PerfSampleTable() {}
46 
FilterByConstraint(FilterConstraints &samplefc, double &samplefilterCost, size_t samplerowCount, uint32_t samplecurrenti)47 void PerfSampleTable::FilterByConstraint(FilterConstraints &samplefc,
48                                          double &samplefilterCost,
49                                          size_t samplerowCount,
50                                          uint32_t samplecurrenti)
51 {
52     // To use the EstimateFilterCost function in the TableBase parent class function to calculate the i-value of each
53     // for loop
54     const auto &samplec = samplefc.GetConstraints()[samplecurrenti];
55     switch (static_cast<Index>(samplec.col)) {
56         case Index::ID: {
57             if (CanFilterId(samplec.op, samplerowCount)) {
58                 samplefc.UpdateConstraint(samplecurrenti, true);
59                 samplefilterCost += 1; // id can position by 1 step
60             } else {
61                 samplefilterCost += samplerowCount; // scan all rows
62             }
63             break;
64         }
65         default:                                // other column
66             samplefilterCost += samplerowCount; // scan all rows
67             break;
68     }
69 }
70 
CreateCursor()71 std::unique_ptr<TableBase::Cursor> PerfSampleTable::CreateCursor()
72 {
73     return std::make_unique<Cursor>(dataCache_, this);
74 }
75 
Cursor(const TraceDataCache *dataCache, TableBase *table)76 PerfSampleTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
77     : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstPerfSampleData().Size())),
78       perfSampleObj_(dataCache->GetConstPerfSampleData())
79 {
80 }
81 
~Cursor()82 PerfSampleTable::Cursor::~Cursor() {}
83 
Filter(const FilterConstraints &fc, sqlite3_value **argv)84 int32_t PerfSampleTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
85 {
86     // reset indexMap_
87     indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
88 
89     if (rowCount_ <= 0) {
90         return SQLITE_OK;
91     }
92 
93     auto perfSampleCs = fc.GetConstraints();
94     std::set<uint32_t> sId = {static_cast<uint32_t>(Index::ID)};
95     SwapIndexFront(perfSampleCs, sId);
96     for (size_t i = 0; i < perfSampleCs.size(); i++) {
97         const auto &c = perfSampleCs[i];
98         switch (static_cast<Index>(c.col)) {
99             case Index::ID:
100                 FilterId(c.op, argv[c.idxInaConstraint]);
101                 break;
102             case Index::CALLCHAIN_ID:
103                 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int64(argv[c.idxInaConstraint])),
104                                     perfSampleObj_.SampleIds());
105                 break;
106             case Index::THREAD_ID:
107                 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int64(argv[c.idxInaConstraint])),
108                                     perfSampleObj_.Tids());
109                 break;
110             case Index::EVENT_TYPE_ID:
111                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[c.idxInaConstraint])),
112                                     perfSampleObj_.EventTypeIds());
113                 break;
114             case Index::CPU_ID:
115                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[c.idxInaConstraint])),
116                                     perfSampleObj_.CpuIds());
117                 break;
118             default:
119                 break;
120         }
121     }
122     auto perfSampleOrderbys = fc.GetOrderBys();
123     for (auto i = perfSampleOrderbys.size(); i > 0;) {
124         i--;
125         switch (static_cast<Index>(perfSampleOrderbys[i].iColumn)) {
126             case Index::ID:
127                 indexMap_->SortBy(perfSampleOrderbys[i].desc);
128                 break;
129             default:
130                 break;
131         }
132     }
133 
134     return SQLITE_OK;
135 }
136 
Column(int32_t column) const137 int32_t PerfSampleTable::Cursor::Column(int32_t column) const
138 {
139     switch (static_cast<Index>(column)) {
140         case Index::ID:
141             sqlite3_result_int64(context_, static_cast<int32_t>(perfSampleObj_.IdsData()[CurrentRow()]));
142             break;
143         case Index::CALLCHAIN_ID:
144             if (perfSampleObj_.SampleIds()[CurrentRow()] != INVALID_UINT32) {
145                 sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.SampleIds()[CurrentRow()]));
146             } else {
147                 sqlite3_result_int64(context_, static_cast<int64_t>(INVALID_CALL_CHAIN_ID));
148             }
149             break;
150         case Index::TIMESTAMP:
151             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.TimeStampData()[CurrentRow()]));
152             break;
153         case Index::THREAD_ID:
154             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.Tids()[CurrentRow()]));
155             break;
156         case Index::EVENT_COUNT:
157             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.EventCounts()[CurrentRow()]));
158             break;
159         case Index::EVENT_TYPE_ID:
160             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.EventTypeIds()[CurrentRow()]));
161             break;
162         case Index::TIMESTAMP_TRACE:
163             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.TimestampTraces()[CurrentRow()]));
164             break;
165         case Index::CPU_ID:
166             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.CpuIds()[CurrentRow()]));
167             break;
168         case Index::THREAD_STATE:
169             if (perfSampleObj_.ThreadStates()[CurrentRow()] != INVALID_UINT64) {
170                 auto threadStateIndex = static_cast<size_t>(perfSampleObj_.ThreadStates()[CurrentRow()]);
171                 sqlite3_result_text(context_, dataCache_->GetDataFromDict(threadStateIndex).c_str(), STR_DEFAULT_LEN,
172                                     nullptr);
173             }
174             break;
175         default:
176             TS_LOGF("Unregistered column : %d", column);
177             break;
178     }
179     return SQLITE_OK;
180 }
181 
GetOrbyes(FilterConstraints &samplefc, EstimatedIndexInfo &sampleei)182 void PerfSampleTable::GetOrbyes(FilterConstraints &samplefc, EstimatedIndexInfo &sampleei)
183 {
184     auto sampleorderbys = samplefc.GetOrderBys();
185     for (auto i = 0; i < sampleorderbys.size(); i++) {
186         switch (static_cast<Index>(sampleorderbys[i].iColumn)) {
187             case Index::ID:
188                 break;
189             default: // other columns can be sorted by SQLite
190                 sampleei.isOrdered = false;
191                 break;
192         }
193     }
194 }
195 } // namespace TraceStreamer
196 } // namespace SysTuning
197