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