1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ci
16fb726d48Sopenharmony_ci#include "thread_table.h"
17fb726d48Sopenharmony_ci
18fb726d48Sopenharmony_cinamespace SysTuning {
19fb726d48Sopenharmony_cinamespace TraceStreamer {
20fb726d48Sopenharmony_cienum class Index : int32_t { ID = 0, ITID, TID, NAME, START_TS, END_TS, INTERNAL_PID, IS_MAIN_THREAD, SWITCH_COUNT };
21fb726d48Sopenharmony_ciThreadTable::ThreadTable(const TraceDataCache *dataCache) : TableBase(dataCache)
22fb726d48Sopenharmony_ci{
23fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
24fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER"));
25fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("tid", "INTEGER"));
26fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT"));
27fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER"));
28fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER"));
29fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
30fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("is_main_thread", "INTEGER"));
31fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("switch_count", "INTEGER"));
32fb726d48Sopenharmony_ci    tablePriKey_.push_back("id");
33fb726d48Sopenharmony_ci}
34fb726d48Sopenharmony_ci
35fb726d48Sopenharmony_ciThreadTable::~ThreadTable() {}
36fb726d48Sopenharmony_ci
37fb726d48Sopenharmony_civoid ThreadTable::FilterByConstraint(FilterConstraints &threadfc,
38fb726d48Sopenharmony_ci                                     double &threadfilterCost,
39fb726d48Sopenharmony_ci                                     size_t threadrowCount,
40fb726d48Sopenharmony_ci                                     uint32_t threadcurrenti)
41fb726d48Sopenharmony_ci{
42fb726d48Sopenharmony_ci    // To use the EstimateFilterCost function in the TableBase parent class function to calculate the i-value of each
43fb726d48Sopenharmony_ci    // for loop
44fb726d48Sopenharmony_ci    const auto &threadc = threadfc.GetConstraints()[threadcurrenti];
45fb726d48Sopenharmony_ci    switch (static_cast<Index>(threadc.col)) {
46fb726d48Sopenharmony_ci        case Index::ITID:
47fb726d48Sopenharmony_ci        case Index::ID: {
48fb726d48Sopenharmony_ci            if (CanFilterId(threadc.op, threadrowCount)) {
49fb726d48Sopenharmony_ci                threadfc.UpdateConstraint(threadcurrenti, true);
50fb726d48Sopenharmony_ci                threadfilterCost += 1; // id can position by 1 step
51fb726d48Sopenharmony_ci            } else {
52fb726d48Sopenharmony_ci                threadfilterCost += threadrowCount; // scan all rows
53fb726d48Sopenharmony_ci            }
54fb726d48Sopenharmony_ci            break;
55fb726d48Sopenharmony_ci        }
56fb726d48Sopenharmony_ci        default:                                // other column
57fb726d48Sopenharmony_ci            threadfilterCost += threadrowCount; // scan all rows
58fb726d48Sopenharmony_ci            break;
59fb726d48Sopenharmony_ci    }
60fb726d48Sopenharmony_ci}
61fb726d48Sopenharmony_ci
62fb726d48Sopenharmony_cistd::unique_ptr<TableBase::Cursor> ThreadTable::CreateCursor()
63fb726d48Sopenharmony_ci{
64fb726d48Sopenharmony_ci    return std::make_unique<Cursor>(dataCache_, this);
65fb726d48Sopenharmony_ci}
66fb726d48Sopenharmony_ci
67fb726d48Sopenharmony_ciThreadTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
68fb726d48Sopenharmony_ci    : TableBase::Cursor(dataCache, table, dataCache->ThreadSize())
69fb726d48Sopenharmony_ci{
70fb726d48Sopenharmony_ci}
71fb726d48Sopenharmony_ci
72fb726d48Sopenharmony_ciThreadTable::Cursor::~Cursor() {}
73fb726d48Sopenharmony_ci
74fb726d48Sopenharmony_ciint32_t ThreadTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
75fb726d48Sopenharmony_ci{
76fb726d48Sopenharmony_ci    // reset indexMapBack_
77fb726d48Sopenharmony_ci    if (rowCount_ <= 0) {
78fb726d48Sopenharmony_ci        return SQLITE_OK;
79fb726d48Sopenharmony_ci    }
80fb726d48Sopenharmony_ci    indexMapBack_ = indexMap_.get();
81fb726d48Sopenharmony_ci    if (indexMap_->HasData()) {
82fb726d48Sopenharmony_ci        indexMapBack_ = std::make_unique<IndexMap>(0, rowCount_).get();
83fb726d48Sopenharmony_ci    }
84fb726d48Sopenharmony_ci    auto cs = fc.GetConstraints();
85fb726d48Sopenharmony_ci    std::set<uint32_t> sId = {static_cast<uint32_t>(Index::ID)};
86fb726d48Sopenharmony_ci    SwapIndexFront(cs, sId);
87fb726d48Sopenharmony_ci    for (size_t i = 0; i < cs.size(); i++) {
88fb726d48Sopenharmony_ci        const auto &c = cs[i];
89fb726d48Sopenharmony_ci        switch (static_cast<Index>(c.col)) {
90fb726d48Sopenharmony_ci            case Index::ID:
91fb726d48Sopenharmony_ci            case Index::ITID:
92fb726d48Sopenharmony_ci                FilterId(c.op, argv[c.idxInaConstraint]);
93fb726d48Sopenharmony_ci                break;
94fb726d48Sopenharmony_ci            default:
95fb726d48Sopenharmony_ci                break;
96fb726d48Sopenharmony_ci        }
97fb726d48Sopenharmony_ci    }
98fb726d48Sopenharmony_ci    if (indexMap_->HasData()) {
99fb726d48Sopenharmony_ci        indexMap_->Merge(indexMapBack_);
100fb726d48Sopenharmony_ci    }
101fb726d48Sopenharmony_ci
102fb726d48Sopenharmony_ci    auto orderbys = fc.GetOrderBys();
103fb726d48Sopenharmony_ci    for (auto i = orderbys.size(); i > 0;) {
104fb726d48Sopenharmony_ci        i--;
105fb726d48Sopenharmony_ci        switch (static_cast<Index>(orderbys[i].iColumn)) {
106fb726d48Sopenharmony_ci            case Index::ID:
107fb726d48Sopenharmony_ci            case Index::ITID:
108fb726d48Sopenharmony_ci                indexMap_->SortBy(orderbys[i].desc);
109fb726d48Sopenharmony_ci                break;
110fb726d48Sopenharmony_ci            default:
111fb726d48Sopenharmony_ci                break;
112fb726d48Sopenharmony_ci        }
113fb726d48Sopenharmony_ci    }
114fb726d48Sopenharmony_ci
115fb726d48Sopenharmony_ci    return SQLITE_OK;
116fb726d48Sopenharmony_ci}
117fb726d48Sopenharmony_ci
118fb726d48Sopenharmony_ciint32_t ThreadTable::Cursor::Column(int32_t col) const
119fb726d48Sopenharmony_ci{
120fb726d48Sopenharmony_ci    const auto &thread = dataCache_->GetConstThreadData(CurrentRow());
121fb726d48Sopenharmony_ci    switch (static_cast<Index>(col)) {
122fb726d48Sopenharmony_ci        case Index::ID:
123fb726d48Sopenharmony_ci        case Index::ITID: {
124fb726d48Sopenharmony_ci            sqlite3_result_int64(context_, CurrentRow());
125fb726d48Sopenharmony_ci            break;
126fb726d48Sopenharmony_ci        }
127fb726d48Sopenharmony_ci        case Index::TID: {
128fb726d48Sopenharmony_ci            SetTypeColumnInt64(thread.tid_, INVALID_UINT32);
129fb726d48Sopenharmony_ci            break;
130fb726d48Sopenharmony_ci        }
131fb726d48Sopenharmony_ci        case Index::NAME: {
132fb726d48Sopenharmony_ci            SetNameColumn(thread);
133fb726d48Sopenharmony_ci            break;
134fb726d48Sopenharmony_ci        }
135fb726d48Sopenharmony_ci        case Index::START_TS:
136fb726d48Sopenharmony_ci            SetTypeColumnInt64NotZero(thread.startT_);
137fb726d48Sopenharmony_ci            break;
138fb726d48Sopenharmony_ci        case Index::END_TS:
139fb726d48Sopenharmony_ci            SetTypeColumnInt64NotZero(thread.endT_);
140fb726d48Sopenharmony_ci
141fb726d48Sopenharmony_ci            break;
142fb726d48Sopenharmony_ci        case Index::INTERNAL_PID:
143fb726d48Sopenharmony_ci            SetTypeColumnInt32(thread.internalPid_, INVALID_UINT32);
144fb726d48Sopenharmony_ci            break;
145fb726d48Sopenharmony_ci        case Index::IS_MAIN_THREAD: {
146fb726d48Sopenharmony_ci            // When it is not clear which process the thread belongs to, is_main_thread should be set to null
147fb726d48Sopenharmony_ci            if (thread.internalPid_ == INVALID_UINT32) {
148fb726d48Sopenharmony_ci                break;
149fb726d48Sopenharmony_ci            }
150fb726d48Sopenharmony_ci            const auto &process = dataCache_->GetConstProcessData(thread.internalPid_);
151fb726d48Sopenharmony_ci            sqlite3_result_int(context_, thread.tid_ == process.pid_);
152fb726d48Sopenharmony_ci            break;
153fb726d48Sopenharmony_ci        }
154fb726d48Sopenharmony_ci        case Index::SWITCH_COUNT: {
155fb726d48Sopenharmony_ci            // When it is not clear which process the thread belongs to, is_main_thread should be set to null
156fb726d48Sopenharmony_ci            sqlite3_result_int(context_, thread.switchCount_);
157fb726d48Sopenharmony_ci            break;
158fb726d48Sopenharmony_ci        }
159fb726d48Sopenharmony_ci        default:
160fb726d48Sopenharmony_ci            TS_LOGF("Unregistered column : %d", col);
161fb726d48Sopenharmony_ci            break;
162fb726d48Sopenharmony_ci    }
163fb726d48Sopenharmony_ci    return SQLITE_OK;
164fb726d48Sopenharmony_ci}
165fb726d48Sopenharmony_ci
166fb726d48Sopenharmony_civoid ThreadTable::Cursor::SetNameColumn(const Thread &thread) const
167fb726d48Sopenharmony_ci{
168fb726d48Sopenharmony_ci    const auto &name = dataCache_->GetDataFromDict(thread.nameIndex_);
169fb726d48Sopenharmony_ci    if (name.size()) {
170fb726d48Sopenharmony_ci        sqlite3_result_text(context_, name.c_str(), static_cast<int32_t>(name.length()), nullptr);
171fb726d48Sopenharmony_ci    }
172fb726d48Sopenharmony_ci}
173fb726d48Sopenharmony_ci
174fb726d48Sopenharmony_civoid ThreadTable::Cursor::FilterId(unsigned char op, sqlite3_value *argv)
175fb726d48Sopenharmony_ci{
176fb726d48Sopenharmony_ci    auto type = sqlite3_value_type(argv);
177fb726d48Sopenharmony_ci    if (type != SQLITE_INTEGER) {
178fb726d48Sopenharmony_ci        // other type consider it NULL
179fb726d48Sopenharmony_ci        indexMapBack_->Intersect(0, 0);
180fb726d48Sopenharmony_ci        return;
181fb726d48Sopenharmony_ci    }
182fb726d48Sopenharmony_ci
183fb726d48Sopenharmony_ci    auto threadTabArgv = static_cast<TableRowId>(sqlite3_value_int64(argv));
184fb726d48Sopenharmony_ci    switch (op) {
185fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_EQ:
186fb726d48Sopenharmony_ci            indexMapBack_->Intersect(threadTabArgv, threadTabArgv + 1);
187fb726d48Sopenharmony_ci            break;
188fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_GE:
189fb726d48Sopenharmony_ci            indexMapBack_->Intersect(threadTabArgv, rowCount_);
190fb726d48Sopenharmony_ci            break;
191fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_GT:
192fb726d48Sopenharmony_ci            threadTabArgv++;
193fb726d48Sopenharmony_ci            indexMapBack_->Intersect(threadTabArgv, rowCount_);
194fb726d48Sopenharmony_ci            break;
195fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_LE:
196fb726d48Sopenharmony_ci            threadTabArgv++;
197fb726d48Sopenharmony_ci            indexMapBack_->Intersect(0, threadTabArgv);
198fb726d48Sopenharmony_ci            break;
199fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_LT:
200fb726d48Sopenharmony_ci            indexMapBack_->Intersect(0, threadTabArgv);
201fb726d48Sopenharmony_ci            break;
202fb726d48Sopenharmony_ci        default:
203fb726d48Sopenharmony_ci            // can't filter, all rows
204fb726d48Sopenharmony_ci            break;
205fb726d48Sopenharmony_ci    }
206fb726d48Sopenharmony_ci}
207fb726d48Sopenharmony_civoid ThreadTable::GetOrbyes(FilterConstraints &fc, EstimatedIndexInfo &ei)
208fb726d48Sopenharmony_ci{
209fb726d48Sopenharmony_ci    auto orderbys = fc.GetOrderBys();
210fb726d48Sopenharmony_ci    for (auto i = 0; i < orderbys.size(); i++) {
211fb726d48Sopenharmony_ci        switch (static_cast<Index>(orderbys[i].iColumn)) {
212fb726d48Sopenharmony_ci            case Index::ITID:
213fb726d48Sopenharmony_ci            case Index::ID:
214fb726d48Sopenharmony_ci                break;
215fb726d48Sopenharmony_ci            default: // other columns can be sorted by SQLite
216fb726d48Sopenharmony_ci                ei.isOrdered = false;
217fb726d48Sopenharmony_ci                break;
218fb726d48Sopenharmony_ci        }
219fb726d48Sopenharmony_ci    }
220fb726d48Sopenharmony_ci}
221fb726d48Sopenharmony_ci} // namespace TraceStreamer
222fb726d48Sopenharmony_ci} // namespace SysTuning
223