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