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