• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "perf_sample_table.h"
17 
18 namespace SysTuning {
19 namespace TraceStreamer {
20 namespace {
21 enum Index {
22     ID = 0,
23     CALLCHAIN_ID,
24     TIMESTAMP,
25     THREAD_ID,
26     EVENT_COUNT,
27     EVENT_TYPE_ID,
28     TIMESTAMP_TRACE,
29     CPU_ID,
30     THREAD_STATE
31 };
32 }
PerfSampleTable(const TraceDataCache * dataCache)33 PerfSampleTable::PerfSampleTable(const TraceDataCache* dataCache) : TableBase(dataCache)
34 {
35     tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
36     tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER"));
37     tableColumn_.push_back(TableBase::ColumnInfo("timestamp", "INTEGER"));
38     tableColumn_.push_back(TableBase::ColumnInfo("thread_id", "INTEGER"));
39     tableColumn_.push_back(TableBase::ColumnInfo("event_count", "INTEGER"));
40     tableColumn_.push_back(TableBase::ColumnInfo("event_type_id", "INTEGER"));
41     tableColumn_.push_back(TableBase::ColumnInfo("timestamp_trace", "INTEGER"));
42     tableColumn_.push_back(TableBase::ColumnInfo("cpu_id", "INTEGER"));
43     tableColumn_.push_back(TableBase::ColumnInfo("thread_state", "TEXT"));
44     tablePriKey_.push_back("id");
45 }
46 
~PerfSampleTable()47 PerfSampleTable::~PerfSampleTable() {}
48 
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)49 void PerfSampleTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei)
50 {
51     constexpr double filterBaseCost = 1000.0; // set-up and tear-down
52     constexpr double indexCost = 2.0;
53     ei.estimatedCost = filterBaseCost;
54 
55     auto rowCount = dataCache_->GetConstPerfSampleData().Size();
56     if (rowCount == 0 || rowCount == 1) {
57         ei.estimatedRows = rowCount;
58         ei.estimatedCost += indexCost * rowCount;
59         return;
60     }
61 
62     double filterCost = 0.0;
63     auto constraints = fc.GetConstraints();
64     if (constraints.empty()) { // scan all rows
65         filterCost = rowCount;
66     } else {
67         FilterByConstraint(fc, filterCost, rowCount);
68     }
69     ei.estimatedCost += filterCost;
70     ei.estimatedRows = rowCount;
71     ei.estimatedCost += rowCount * indexCost;
72 
73     ei.isOrdered = true;
74     auto orderbys = fc.GetOrderBys();
75     for (auto i = 0; i < orderbys.size(); i++) {
76         switch (orderbys[i].iColumn) {
77             case ID:
78                 break;
79             default: // other columns can be sorted by SQLite
80                 ei.isOrdered = false;
81                 break;
82         }
83     }
84 }
85 
FilterByConstraint(FilterConstraints & fc,double & filterCost,size_t rowCount)86 void PerfSampleTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount)
87 {
88     auto fcConstraints = fc.GetConstraints();
89     for (int i = 0; i < static_cast<int>(fcConstraints.size()); i++) {
90         if (rowCount <= 1) {
91             // only one row or nothing, needn't filter by constraint
92             filterCost += rowCount;
93             break;
94         }
95         const auto& c = fcConstraints[i];
96         switch (c.col) {
97             case ID: {
98                 if (CanFilterId(c.op, rowCount)) {
99                     fc.UpdateConstraint(i, true);
100                     filterCost += 1; // id can position by 1 step
101                 } else {
102                     filterCost += rowCount; // scan all rows
103                 }
104                 break;
105             }
106             default:                    // other column
107                 filterCost += rowCount; // scan all rows
108                 break;
109         }
110     }
111 }
112 
CanFilterId(const char op,size_t & rowCount)113 bool PerfSampleTable::CanFilterId(const char op, size_t& rowCount)
114 {
115     switch (op) {
116         case SQLITE_INDEX_CONSTRAINT_EQ:
117             rowCount = 1;
118             break;
119         case SQLITE_INDEX_CONSTRAINT_GT:
120         case SQLITE_INDEX_CONSTRAINT_GE:
121         case SQLITE_INDEX_CONSTRAINT_LE:
122         case SQLITE_INDEX_CONSTRAINT_LT:
123             // assume filter out a half of rows
124             rowCount = (rowCount >> 1);
125             break;
126         default:
127             return false;
128     }
129     return true;
130 }
131 
CreateCursor()132 std::unique_ptr<TableBase::Cursor> PerfSampleTable::CreateCursor()
133 {
134     return std::make_unique<Cursor>(dataCache_, this);
135 }
136 
Cursor(const TraceDataCache * dataCache,TableBase * table)137 PerfSampleTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table)
138     : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstPerfSampleData().Size())),
139       perfSampleObj_(dataCache->GetConstPerfSampleData())
140 {
141 }
142 
~Cursor()143 PerfSampleTable::Cursor::~Cursor() {}
144 
Filter(const FilterConstraints & fc,sqlite3_value ** argv)145 int PerfSampleTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv)
146 {
147     // reset indexMap_
148     indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
149 
150     if (rowCount_ <= 0) {
151         return SQLITE_OK;
152     }
153 
154     auto& cs = fc.GetConstraints();
155     for (size_t i = 0; i < cs.size(); i++) {
156         const auto& c = cs[i];
157         switch (c.col) {
158             case ID:
159                 FilterId(c.op, argv[i]);
160                 break;
161             case CALLCHAIN_ID:
162                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[i])),
163                                     perfSampleObj_.SampleIds());
164                 break;
165             case THREAD_ID:
166                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[i])), perfSampleObj_.Tids());
167                 break;
168             case EVENT_TYPE_ID:
169                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[i])),
170                                     perfSampleObj_.EventTypeIds());
171                 break;
172             case CPU_ID:
173                 indexMap_->MixRange(c.op, static_cast<uint64_t>(sqlite3_value_int64(argv[i])), perfSampleObj_.CpuIds());
174                 break;
175             default:
176                 break;
177         }
178     }
179     auto orderbys = fc.GetOrderBys();
180     for (auto i = orderbys.size(); i > 0;) {
181         i--;
182         switch (orderbys[i].iColumn) {
183             case ID:
184                 indexMap_->SortBy(orderbys[i].desc);
185                 break;
186             default:
187                 break;
188         }
189     }
190 
191     return SQLITE_OK;
192 }
193 
Column(int column) const194 int PerfSampleTable::Cursor::Column(int column) const
195 {
196     switch (column) {
197         case ID:
198             sqlite3_result_int64(context_, static_cast<int32_t>(perfSampleObj_.IdsData()[CurrentRow()]));
199             break;
200         case CALLCHAIN_ID:
201             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.SampleIds()[CurrentRow()]));
202             break;
203         case TIMESTAMP:
204             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.TimeStamData()[CurrentRow()]));
205             break;
206         case THREAD_ID:
207             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.Tids()[CurrentRow()]));
208             break;
209         case EVENT_COUNT:
210             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.EventCounts()[CurrentRow()]));
211             break;
212         case EVENT_TYPE_ID:
213             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.EventTypeIds()[CurrentRow()]));
214             break;
215         case TIMESTAMP_TRACE:
216             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.TimestampTraces()[CurrentRow()]));
217             break;
218         case CPU_ID:
219             sqlite3_result_int64(context_, static_cast<int64_t>(perfSampleObj_.CpuIds()[CurrentRow()]));
220             break;
221         case THREAD_STATE:
222             if (perfSampleObj_.ThreadStates()[CurrentRow()] != INVALID_UINT64) {
223                 auto threadStateIndex = static_cast<size_t>(perfSampleObj_.ThreadStates()[CurrentRow()]);
224                 sqlite3_result_text(context_, dataCache_->GetDataFromDict(threadStateIndex).c_str(), STR_DEFAULT_LEN,
225                                     nullptr);
226             }
227             break;
228         default:
229             TS_LOGF("Unregistered column : %d", column);
230             break;
231     }
232     return SQLITE_OK;
233 }
234 } // namespace TraceStreamer
235 } // namespace SysTuning
236