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 "process_table.h"
17fb726d48Sopenharmony_ci
18fb726d48Sopenharmony_cinamespace SysTuning {
19fb726d48Sopenharmony_cinamespace TraceStreamer {
20fb726d48Sopenharmony_cienum class Index : int32_t { ID = 0, IPID, PID, NAME, START_TS, SWITCH_COUNT, THREAD_COUNT, SLICE_COUNT, MEM_COUNT };
21fb726d48Sopenharmony_ciProcessTable::ProcessTable(const TraceDataCache *dataCache) : TableBase(dataCache)
22fb726d48Sopenharmony_ci{
23fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER"));
24fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER"));
25fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("pid", "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("switch_count", "INTEGER"));
29fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("thread_count", "INTEGER"));
30fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("slice_count", "INTEGER"));
31fb726d48Sopenharmony_ci    tableColumn_.push_back(TableBase::ColumnInfo("mem_count", "INTEGER"));
32fb726d48Sopenharmony_ci    tablePriKey_.push_back("id");
33fb726d48Sopenharmony_ci}
34fb726d48Sopenharmony_ci
35fb726d48Sopenharmony_ciProcessTable::~ProcessTable() {}
36fb726d48Sopenharmony_ci
37fb726d48Sopenharmony_civoid ProcessTable::FilterByConstraint(FilterConstraints &processfc,
38fb726d48Sopenharmony_ci                                      double &processfilterCost,
39fb726d48Sopenharmony_ci                                      size_t processrowCount,
40fb726d48Sopenharmony_ci                                      uint32_t processcurrenti)
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 &processc = processfc.GetConstraints()[processcurrenti];
45fb726d48Sopenharmony_ci    switch (static_cast<Index>(processc.col)) {
46fb726d48Sopenharmony_ci        case Index::IPID:
47fb726d48Sopenharmony_ci        case Index::ID: {
48fb726d48Sopenharmony_ci            if (CanFilterId(processc.op, processrowCount)) {
49fb726d48Sopenharmony_ci                processfc.UpdateConstraint(processcurrenti, true);
50fb726d48Sopenharmony_ci                processfilterCost += 1; // id can position by 1 step
51fb726d48Sopenharmony_ci            } else {
52fb726d48Sopenharmony_ci                processfilterCost += processrowCount; // scan all rows
53fb726d48Sopenharmony_ci            }
54fb726d48Sopenharmony_ci            break;
55fb726d48Sopenharmony_ci        }
56fb726d48Sopenharmony_ci        default:                                  // other column
57fb726d48Sopenharmony_ci            processfilterCost += processrowCount; // scan all rows
58fb726d48Sopenharmony_ci            break;
59fb726d48Sopenharmony_ci    }
60fb726d48Sopenharmony_ci}
61fb726d48Sopenharmony_ci
62fb726d48Sopenharmony_ciint32_t ProcessTable::Update(int32_t argc, sqlite3_value **argv, sqlite3_int64 *pRowid)
63fb726d48Sopenharmony_ci{
64fb726d48Sopenharmony_ci    if (argc <= 1) {
65fb726d48Sopenharmony_ci        return SQLITE_READONLY;
66fb726d48Sopenharmony_ci    }
67fb726d48Sopenharmony_ci    if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
68fb726d48Sopenharmony_ci        return SQLITE_READONLY;
69fb726d48Sopenharmony_ci    }
70fb726d48Sopenharmony_ci    auto id = sqlite3_value_int64(argv[0]);
71fb726d48Sopenharmony_ci    auto process = wdataCache_->GetProcessData(static_cast<InternalPid>(id));
72fb726d48Sopenharmony_ci    constexpr int32_t colOffset = 2;
73fb726d48Sopenharmony_ci    for (auto i = colOffset; i < argc; i++) {
74fb726d48Sopenharmony_ci        auto col = i - colOffset;
75fb726d48Sopenharmony_ci        if (static_cast<Index>(col) != Index::NAME) {
76fb726d48Sopenharmony_ci            continue;
77fb726d48Sopenharmony_ci        }
78fb726d48Sopenharmony_ci        const char *name = reinterpret_cast<const char *>(sqlite3_value_text(argv[i]));
79fb726d48Sopenharmony_ci        if (name == nullptr) {
80fb726d48Sopenharmony_ci            process->cmdLine_.clear();
81fb726d48Sopenharmony_ci        } else {
82fb726d48Sopenharmony_ci            process->cmdLine_ = name;
83fb726d48Sopenharmony_ci        }
84fb726d48Sopenharmony_ci        break;
85fb726d48Sopenharmony_ci    }
86fb726d48Sopenharmony_ci    return SQLITE_OK;
87fb726d48Sopenharmony_ci}
88fb726d48Sopenharmony_ci
89fb726d48Sopenharmony_cistd::unique_ptr<TableBase::Cursor> ProcessTable::CreateCursor()
90fb726d48Sopenharmony_ci{
91fb726d48Sopenharmony_ci    return std::make_unique<Cursor>(dataCache_, this);
92fb726d48Sopenharmony_ci}
93fb726d48Sopenharmony_ci
94fb726d48Sopenharmony_ciProcessTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
95fb726d48Sopenharmony_ci    : TableBase::Cursor(dataCache, table, dataCache->ProcessSize())
96fb726d48Sopenharmony_ci{
97fb726d48Sopenharmony_ci}
98fb726d48Sopenharmony_ci
99fb726d48Sopenharmony_ciProcessTable::Cursor::~Cursor() {}
100fb726d48Sopenharmony_ci
101fb726d48Sopenharmony_ciint32_t ProcessTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
102fb726d48Sopenharmony_ci{
103fb726d48Sopenharmony_ci    // reset indexMap_
104fb726d48Sopenharmony_ci    indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
105fb726d48Sopenharmony_ci
106fb726d48Sopenharmony_ci    if (rowCount_ <= 0) {
107fb726d48Sopenharmony_ci        return SQLITE_OK;
108fb726d48Sopenharmony_ci    }
109fb726d48Sopenharmony_ci
110fb726d48Sopenharmony_ci    auto processTableCs = fc.GetConstraints();
111fb726d48Sopenharmony_ci    std::set<uint32_t> sId = {static_cast<uint32_t>(Index::ID)};
112fb726d48Sopenharmony_ci    SwapIndexFront(processTableCs, sId);
113fb726d48Sopenharmony_ci    for (size_t i = 0; i < processTableCs.size(); i++) {
114fb726d48Sopenharmony_ci        const auto &c = processTableCs[i];
115fb726d48Sopenharmony_ci        switch (static_cast<Index>(c.col)) {
116fb726d48Sopenharmony_ci            case Index::ID:
117fb726d48Sopenharmony_ci            case Index::IPID:
118fb726d48Sopenharmony_ci                FilterId(c.op, argv[c.idxInaConstraint]);
119fb726d48Sopenharmony_ci                break;
120fb726d48Sopenharmony_ci            case Index::PID:
121fb726d48Sopenharmony_ci                FilterIndex(c.col, c.op, argv[c.idxInaConstraint]);
122fb726d48Sopenharmony_ci                break;
123fb726d48Sopenharmony_ci            default:
124fb726d48Sopenharmony_ci                break;
125fb726d48Sopenharmony_ci        }
126fb726d48Sopenharmony_ci    }
127fb726d48Sopenharmony_ci
128fb726d48Sopenharmony_ci    auto processTableOrderbys = fc.GetOrderBys();
129fb726d48Sopenharmony_ci    for (auto i = processTableOrderbys.size(); i > 0;) {
130fb726d48Sopenharmony_ci        i--;
131fb726d48Sopenharmony_ci        switch (static_cast<Index>(processTableOrderbys[i].iColumn)) {
132fb726d48Sopenharmony_ci            case Index::ID:
133fb726d48Sopenharmony_ci            case Index::IPID:
134fb726d48Sopenharmony_ci                indexMap_->SortBy(processTableOrderbys[i].desc);
135fb726d48Sopenharmony_ci                break;
136fb726d48Sopenharmony_ci            default:
137fb726d48Sopenharmony_ci                break;
138fb726d48Sopenharmony_ci        }
139fb726d48Sopenharmony_ci    }
140fb726d48Sopenharmony_ci
141fb726d48Sopenharmony_ci    return SQLITE_OK;
142fb726d48Sopenharmony_ci}
143fb726d48Sopenharmony_ci
144fb726d48Sopenharmony_ciint32_t ProcessTable::Cursor::Column(int32_t col) const
145fb726d48Sopenharmony_ci{
146fb726d48Sopenharmony_ci    const auto &process = dataCache_->GetConstProcessData(CurrentRow());
147fb726d48Sopenharmony_ci    switch (static_cast<Index>(col)) {
148fb726d48Sopenharmony_ci        case Index::ID:
149fb726d48Sopenharmony_ci        case Index::IPID:
150fb726d48Sopenharmony_ci            sqlite3_result_int64(context_, CurrentRow());
151fb726d48Sopenharmony_ci            break;
152fb726d48Sopenharmony_ci        case Index::PID:
153fb726d48Sopenharmony_ci            sqlite3_result_int64(context_, process.pid_);
154fb726d48Sopenharmony_ci            break;
155fb726d48Sopenharmony_ci        case Index::NAME:
156fb726d48Sopenharmony_ci            if (process.cmdLine_.size()) {
157fb726d48Sopenharmony_ci                sqlite3_result_text(context_, process.cmdLine_.c_str(), static_cast<int32_t>(process.cmdLine_.length()),
158fb726d48Sopenharmony_ci                                    nullptr);
159fb726d48Sopenharmony_ci            }
160fb726d48Sopenharmony_ci            break;
161fb726d48Sopenharmony_ci        case Index::START_TS:
162fb726d48Sopenharmony_ci            if (process.startT_) {
163fb726d48Sopenharmony_ci                sqlite3_result_int64(context_, static_cast<int64_t>(process.startT_));
164fb726d48Sopenharmony_ci            }
165fb726d48Sopenharmony_ci            break;
166fb726d48Sopenharmony_ci        case Index::SWITCH_COUNT:
167fb726d48Sopenharmony_ci            sqlite3_result_int64(context_, process.switchCount_);
168fb726d48Sopenharmony_ci            break;
169fb726d48Sopenharmony_ci        case Index::THREAD_COUNT:
170fb726d48Sopenharmony_ci            sqlite3_result_int64(context_, process.threadCount_);
171fb726d48Sopenharmony_ci            break;
172fb726d48Sopenharmony_ci        case Index::SLICE_COUNT:
173fb726d48Sopenharmony_ci            sqlite3_result_int64(context_, process.sliceSize_);
174fb726d48Sopenharmony_ci            break;
175fb726d48Sopenharmony_ci        case Index::MEM_COUNT:
176fb726d48Sopenharmony_ci            sqlite3_result_int64(context_, process.memSize_);
177fb726d48Sopenharmony_ci            break;
178fb726d48Sopenharmony_ci        default:
179fb726d48Sopenharmony_ci            TS_LOGF("Unregistered column : %d", col);
180fb726d48Sopenharmony_ci            break;
181fb726d48Sopenharmony_ci    }
182fb726d48Sopenharmony_ci    return SQLITE_OK;
183fb726d48Sopenharmony_ci}
184fb726d48Sopenharmony_ci
185fb726d48Sopenharmony_civoid ProcessTable::Cursor::FilterPid(unsigned char op, uint64_t value)
186fb726d48Sopenharmony_ci{
187fb726d48Sopenharmony_ci    bool remove = false;
188fb726d48Sopenharmony_ci    if (indexMap_->HasData()) {
189fb726d48Sopenharmony_ci        indexMap_->ConvertToIndexMap();
190fb726d48Sopenharmony_ci        remove = true;
191fb726d48Sopenharmony_ci    }
192fb726d48Sopenharmony_ci    switch (op) {
193fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_EQ:
194fb726d48Sopenharmony_ci            HandleIndexConstraintEQ(remove, value);
195fb726d48Sopenharmony_ci            break;
196fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_NE:
197fb726d48Sopenharmony_ci            HandleIndexConstraintNQ(remove, value);
198fb726d48Sopenharmony_ci            break;
199fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
200fb726d48Sopenharmony_ci            break;
201fb726d48Sopenharmony_ci        default:
202fb726d48Sopenharmony_ci            break;
203fb726d48Sopenharmony_ci    } // end of switch (op)
204fb726d48Sopenharmony_ci}
205fb726d48Sopenharmony_civoid ProcessTable::Cursor::HandleIndexConstraintEQ(bool remove, uint64_t value)
206fb726d48Sopenharmony_ci{
207fb726d48Sopenharmony_ci    if (remove) {
208fb726d48Sopenharmony_ci        for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) {
209fb726d48Sopenharmony_ci            if (dataCache_->GetConstProcessData()[*i].pid_ != value) {
210fb726d48Sopenharmony_ci                i = indexMap_->rowIndex_.erase(i);
211fb726d48Sopenharmony_ci            } else {
212fb726d48Sopenharmony_ci                i++;
213fb726d48Sopenharmony_ci            }
214fb726d48Sopenharmony_ci        }
215fb726d48Sopenharmony_ci    } else {
216fb726d48Sopenharmony_ci        for (auto i = 0; i < dataCache_->GetConstProcessData().size(); i++) {
217fb726d48Sopenharmony_ci            if (dataCache_->GetConstProcessData()[i].pid_ == value) {
218fb726d48Sopenharmony_ci                indexMap_->rowIndex_.push_back(i);
219fb726d48Sopenharmony_ci            }
220fb726d48Sopenharmony_ci        }
221fb726d48Sopenharmony_ci    }
222fb726d48Sopenharmony_ci    indexMap_->FixSize();
223fb726d48Sopenharmony_ci}
224fb726d48Sopenharmony_civoid ProcessTable::Cursor::HandleIndexConstraintNQ(bool remove, uint64_t value)
225fb726d48Sopenharmony_ci{
226fb726d48Sopenharmony_ci    if (remove) {
227fb726d48Sopenharmony_ci        for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) {
228fb726d48Sopenharmony_ci            if (dataCache_->GetConstProcessData()[*i].pid_ == value) {
229fb726d48Sopenharmony_ci                i = indexMap_->rowIndex_.erase(i);
230fb726d48Sopenharmony_ci            } else {
231fb726d48Sopenharmony_ci                i++;
232fb726d48Sopenharmony_ci            }
233fb726d48Sopenharmony_ci        }
234fb726d48Sopenharmony_ci    } else {
235fb726d48Sopenharmony_ci        for (auto i = 0; i < dataCache_->GetConstProcessData().size(); i++) {
236fb726d48Sopenharmony_ci            if (dataCache_->GetConstProcessData()[i].pid_ != value) {
237fb726d48Sopenharmony_ci                indexMap_->rowIndex_.push_back(i);
238fb726d48Sopenharmony_ci            }
239fb726d48Sopenharmony_ci        }
240fb726d48Sopenharmony_ci    }
241fb726d48Sopenharmony_ci    indexMap_->FixSize();
242fb726d48Sopenharmony_ci}
243fb726d48Sopenharmony_civoid ProcessTable::Cursor::FilterIndex(int32_t col, unsigned char op, sqlite3_value *argv)
244fb726d48Sopenharmony_ci{
245fb726d48Sopenharmony_ci    switch (static_cast<Index>(col)) {
246fb726d48Sopenharmony_ci        case Index::PID:
247fb726d48Sopenharmony_ci            /* code */
248fb726d48Sopenharmony_ci            FilterPid(op, static_cast<uint64_t>(sqlite3_value_int64(argv)));
249fb726d48Sopenharmony_ci            break;
250fb726d48Sopenharmony_ci
251fb726d48Sopenharmony_ci        default:
252fb726d48Sopenharmony_ci            break;
253fb726d48Sopenharmony_ci    }
254fb726d48Sopenharmony_ci}
255fb726d48Sopenharmony_civoid ProcessTable::Cursor::FilterId(unsigned char op, sqlite3_value *argv)
256fb726d48Sopenharmony_ci{
257fb726d48Sopenharmony_ci    auto procArgv = static_cast<TableRowId>(sqlite3_value_int64(argv));
258fb726d48Sopenharmony_ci    switch (op) {
259fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_EQ:
260fb726d48Sopenharmony_ci            indexMap_->Intersect(procArgv, procArgv + 1);
261fb726d48Sopenharmony_ci            break;
262fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_GE:
263fb726d48Sopenharmony_ci            indexMap_->Intersect(procArgv, rowCount_);
264fb726d48Sopenharmony_ci            break;
265fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_GT:
266fb726d48Sopenharmony_ci            procArgv++;
267fb726d48Sopenharmony_ci            indexMap_->Intersect(procArgv, rowCount_);
268fb726d48Sopenharmony_ci            break;
269fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_LE:
270fb726d48Sopenharmony_ci            procArgv++;
271fb726d48Sopenharmony_ci            indexMap_->Intersect(0, procArgv);
272fb726d48Sopenharmony_ci            break;
273fb726d48Sopenharmony_ci        case SQLITE_INDEX_CONSTRAINT_LT:
274fb726d48Sopenharmony_ci            indexMap_->Intersect(0, procArgv);
275fb726d48Sopenharmony_ci            break;
276fb726d48Sopenharmony_ci        default:
277fb726d48Sopenharmony_ci            // can't filter, all rows
278fb726d48Sopenharmony_ci            break;
279fb726d48Sopenharmony_ci    }
280fb726d48Sopenharmony_ci}
281fb726d48Sopenharmony_ci
282fb726d48Sopenharmony_civoid ProcessTable::GetOrbyes(FilterConstraints &processfc, EstimatedIndexInfo &processei)
283fb726d48Sopenharmony_ci{
284fb726d48Sopenharmony_ci    auto processorderbys = processfc.GetOrderBys();
285fb726d48Sopenharmony_ci    for (auto i = 0; i < processorderbys.size(); i++) {
286fb726d48Sopenharmony_ci        switch (static_cast<Index>(processorderbys[i].iColumn)) {
287fb726d48Sopenharmony_ci            case Index::IPID:
288fb726d48Sopenharmony_ci            case Index::ID:
289fb726d48Sopenharmony_ci                break;
290fb726d48Sopenharmony_ci            default: // other columns can be sorted by SQLite
291fb726d48Sopenharmony_ci                processei.isOrdered = false;
292fb726d48Sopenharmony_ci                break;
293fb726d48Sopenharmony_ci        }
294fb726d48Sopenharmony_ci    }
295fb726d48Sopenharmony_ci}
296fb726d48Sopenharmony_ci} // namespace TraceStreamer
297fb726d48Sopenharmony_ci} // namespace SysTuning
298