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 "callstack_table.h" 17 18namespace SysTuning { 19namespace TraceStreamer { 20enum class Index : int32_t { 21 ID = 0, 22 TS, 23 DURS, 24 CALL_IDS, 25 CATS, 26 NAME, 27 DEPTHS, 28 COOKIES_ID, 29#if IS_WASM 30 COLORINDEX, 31#endif 32 PARENT_ID, 33 ARGSET, 34 CHAIN_IDS, 35 SPAN_IDS, 36 PARENT_SPAN_IDS, 37 FLAGS 38}; 39CallStackTable::CallStackTable(const TraceDataCache *dataCache) : TableBase(dataCache) 40{ 41 tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); 42 tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); 43 tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); 44 tableColumn_.push_back(TableBase::ColumnInfo("callid", "INTEGER")); 45 tableColumn_.push_back(TableBase::ColumnInfo("cat", "TEXT")); 46 tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); 47 tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER")); 48 tableColumn_.push_back(TableBase::ColumnInfo("cookie", "INTEGER")); 49#if IS_WASM 50 tableColumn_.push_back(TableBase::ColumnInfo("colorIndex", "INTEGER")); 51#endif 52 tableColumn_.push_back(TableBase::ColumnInfo("parent_id", "INTEGER")); 53 tableColumn_.push_back(TableBase::ColumnInfo("argsetid", "INTEGER")); 54 tableColumn_.push_back(TableBase::ColumnInfo("chainId", "TEXT")); 55 tableColumn_.push_back(TableBase::ColumnInfo("spanId", "TEXT")); 56 tableColumn_.push_back(TableBase::ColumnInfo("parentSpanId", "TEXT")); 57 tableColumn_.push_back(TableBase::ColumnInfo("flag", "TEXT")); 58 tablePriKey_.push_back("callid"); 59 tablePriKey_.push_back("ts"); 60 tablePriKey_.push_back("depth"); 61} 62 63CallStackTable::~CallStackTable() {} 64 65void CallStackTable::FilterByConstraint(FilterConstraints &callfc, 66 double &callfilterCost, 67 size_t callrowCount, 68 uint32_t callCurrenti) 69{ 70 // To use the EstimateFilterCost function in the TableBase parent class function to calculate the i-value of each 71 // for loop 72 const auto &callc = callfc.GetConstraints()[callCurrenti]; 73 switch (static_cast<Index>(callc.col)) { 74 case Index::ID: { 75 if (CanFilterId(callc.op, callrowCount)) { 76 callfc.UpdateConstraint(callCurrenti, true); 77 callfilterCost += 1; // id can position by 1 step 78 } else { 79 callfilterCost += callrowCount; // scan all rows 80 } 81 break; 82 } 83 default: // other column 84 callfilterCost += callrowCount; // scan all rows 85 break; 86 } 87} 88 89std::unique_ptr<TableBase::Cursor> CallStackTable::CreateCursor() 90{ 91 return std::make_unique<Cursor>(dataCache_, this); 92} 93 94CallStackTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table) 95 : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstInternalSlicesData().Size())), 96 slicesObj_(dataCache->GetConstInternalSlicesData()) 97{ 98} 99 100CallStackTable::Cursor::~Cursor() {} 101 102int32_t CallStackTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv) 103{ 104 // reset indexMap_ 105 indexMap_ = std::make_unique<IndexMap>(0, rowCount_); 106 107 if (rowCount_ <= 0) { 108 return SQLITE_OK; 109 } 110 111 auto callStackTabCs = fc.GetConstraints(); 112 std::set<uint32_t> sId = {static_cast<uint32_t>(Index::TS)}; 113 SwapIndexFront(callStackTabCs, sId); 114 for (size_t i = 0; i < callStackTabCs.size(); i++) { 115 const auto &c = callStackTabCs[i]; 116 switch (static_cast<Index>(c.col)) { 117 case Index::ID: 118 FilterId(c.op, argv[c.idxInaConstraint]); 119 break; 120 case Index::TS: 121 FilterTS(c.op, argv[c.idxInaConstraint], slicesObj_.TimeStampData()); 122 break; 123 case Index::CALL_IDS: 124 indexMap_->MixRange(c.op, static_cast<uint32_t>(sqlite3_value_int(argv[c.idxInaConstraint])), 125 slicesObj_.CallIds()); 126 break; 127 case Index::COOKIES_ID: 128 indexMap_->MixRange(c.op, static_cast<int64_t>(sqlite3_value_int64(argv[c.idxInaConstraint])), 129 slicesObj_.Cookies()); 130 break; 131 default: 132 break; 133 } 134 } 135 136 auto callStackTableOrderbys = fc.GetOrderBys(); 137 for (auto i = callStackTableOrderbys.size(); i > 0;) { 138 i--; 139 switch (static_cast<Index>(callStackTableOrderbys[i].iColumn)) { 140 case Index::ID: 141 indexMap_->SortBy(callStackTableOrderbys[i].desc); 142 break; 143 default: 144 break; 145 } 146 } 147 148 return SQLITE_OK; 149} 150 151int32_t CallStackTable::Cursor::Column(int32_t col) const 152{ 153 switch (static_cast<Index>(col)) { 154 case Index::ID: 155 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.IdsData()[CurrentRow()])); 156 break; 157 case Index::TS: 158 SetTypeColumnInt64(slicesObj_.TimeStampData()[CurrentRow()], INVALID_UINT64); 159 break; 160 case Index::DURS: 161 SetTypeColumnInt64(slicesObj_.DursData()[CurrentRow()], INVALID_UINT64); 162 break; 163 case Index::CALL_IDS: 164 SetTypeColumnInt64(slicesObj_.CallIds()[CurrentRow()], INVALID_UINT64); 165 break; 166#if IS_WASM 167 case Index::COLORINDEX: 168 SetTypeColumnInt64(slicesObj_.ColorIndexs()[CurrentRow()], INVALID_UINT64); 169 break; 170#endif 171 case Index::CATS: { 172 SetTypeColumnText(slicesObj_.CatsData()[CurrentRow()], INVALID_UINT64); 173 break; 174 } 175 case Index::NAME: { 176 SetTypeColumnText(slicesObj_.NamesData()[CurrentRow()], INVALID_UINT64); 177 break; 178 default: 179 HandleTypeColumns(col); 180 } 181 } 182 return SQLITE_OK; 183} 184void CallStackTable::Cursor::HandleTypeColumns(int32_t col) const 185{ 186 switch (static_cast<Index>(col)) { 187 case Index::DEPTHS: 188 SetTypeColumnInt64(slicesObj_.Depths()[CurrentRow()], INVALID_UINT64); 189 break; 190 case Index::COOKIES_ID: 191 SetTypeColumnInt64(slicesObj_.Cookies()[CurrentRow()], INVALID_INT64); 192 break; 193 case Index::PARENT_ID: { 194 if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) { 195 sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ParentIdData()[CurrentRow()].value())); 196 } 197 break; 198 } 199 case Index::ARGSET: 200 SetTypeColumnInt64(slicesObj_.ArgSetIdsData()[CurrentRow()], INVALID_UINT32); 201 break; 202 case Index::CHAIN_IDS: 203 SetTypeColumnTextNotEmpty(slicesObj_.ChainIds()[CurrentRow()].empty(), 204 slicesObj_.ChainIds()[CurrentRow()].c_str()); 205 break; 206 case Index::SPAN_IDS: 207 SetTypeColumnTextNotEmpty(slicesObj_.SpanIds()[CurrentRow()].empty(), 208 slicesObj_.SpanIds()[CurrentRow()].c_str()); 209 break; 210 case Index::PARENT_SPAN_IDS: 211 SetTypeColumnTextNotEmpty(slicesObj_.ParentSpanIds()[CurrentRow()].empty(), 212 slicesObj_.ParentSpanIds()[CurrentRow()].c_str()); 213 break; 214 case Index::FLAGS: 215 SetTypeColumnTextNotEmpty(slicesObj_.Flags()[CurrentRow()].empty(), 216 slicesObj_.Flags()[CurrentRow()].c_str()); 217 break; 218 default: 219 TS_LOGF("Unregistered column : %d", col); 220 break; 221 } 222} 223void CallStackTable::GetOrbyes(FilterConstraints &callfc, EstimatedIndexInfo &callei) 224{ 225 auto orderbys = callfc.GetOrderBys(); 226 for (auto i = 0; i < orderbys.size(); i++) { 227 switch (static_cast<Index>(orderbys[i].iColumn)) { 228 case Index::ID: 229 break; 230 default: // other columns can be sorted by SQLite 231 callei.isOrdered = false; 232 break; 233 } 234 } 235} 236} // namespace TraceStreamer 237} // namespace SysTuning 238