blob: 000891f13de7d8719ee50131750c2135b560edc6 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/counters_table.h"
#include "perfetto/base/logging.h"
#include "src/trace_processor/query_constraints.h"
#include "src/trace_processor/sqlite_utils.h"
namespace perfetto {
namespace trace_processor {
namespace {
using namespace sqlite_utils;
PERFETTO_ALWAYS_INLINE int CompareCountersOnColumn(
const TraceStorage* storage,
size_t f_idx,
size_t s_idx,
const QueryConstraints::OrderBy& ob) {
const auto& co = storage->counters();
switch (ob.iColumn) {
case CountersTable::Column::kTimestamp:
return CompareValues(co.timestamps(), f_idx, s_idx, ob.desc);
case CountersTable::Column::kValue:
return CompareValues(co.values(), f_idx, s_idx, ob.desc);
case CountersTable::Column::kName:
return CompareValues(co.name_ids(), f_idx, s_idx, ob.desc);
case CountersTable::Column::kRef:
return CompareValues(co.refs(), f_idx, s_idx, ob.desc);
case CountersTable::Column::kDuration:
return CompareValues(co.durations(), f_idx, s_idx, ob.desc);
case CountersTable::Column::kValueDelta:
return CompareValues(co.value_deltas(), f_idx, s_idx, ob.desc);
case CountersTable::Column::kRefType:
return CompareValues(co.types(), f_idx, s_idx, ob.desc);
default:
PERFETTO_FATAL("Unexpected column %d", ob.iColumn);
}
}
PERFETTO_ALWAYS_INLINE int CompareCounters(
const TraceStorage* storage,
size_t f_idx,
size_t s_idx,
const std::vector<QueryConstraints::OrderBy>& order_by) {
for (const auto& ob : order_by) {
int c = CompareCountersOnColumn(storage, f_idx, s_idx, ob);
if (c != 0)
return c;
}
return 0;
}
} // namespace
CountersTable::CountersTable(sqlite3*, const TraceStorage* storage)
: storage_(storage) {}
void CountersTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
Table::Register<CountersTable>(db, storage, "counters");
}
Table::Schema CountersTable::CreateSchema(int, const char* const*) {
return Schema(
{
Table::Column(Column::kTimestamp, "ts", ColumnType::kUlong),
Table::Column(Column::kName, "name", ColumnType::kString),
Table::Column(Column::kValue, "value", ColumnType::kUlong),
Table::Column(Column::kDuration, "dur", ColumnType::kUlong),
Table::Column(Column::kValueDelta, "value_delta", ColumnType::kUlong),
Table::Column(Column::kRef, "ref", ColumnType::kUint),
Table::Column(Column::kRefType, "ref_type", ColumnType::kString),
},
{Column::kName, Column::kTimestamp, Column::kRef});
}
std::unique_ptr<Table::Cursor> CountersTable::CreateCursor(
const QueryConstraints& qc,
sqlite3_value** argv) {
return std::unique_ptr<Table::Cursor>(new Cursor(storage_, qc, argv));
}
int CountersTable::BestIndex(const QueryConstraints&, BestIndexInfo* info) {
// TODO(taylori): Work out cost dependant on constraints.
info->estimated_cost =
static_cast<uint32_t>(storage_->counters().counter_count());
info->order_by_consumed = true;
return SQLITE_OK;
}
CountersTable::Cursor::Cursor(const TraceStorage* storage,
const QueryConstraints& qc,
sqlite3_value** argv)
: storage_(storage) {
const auto& counters = storage->counters();
std::vector<bool> filter(counters.counter_count(), true);
for (size_t i = 0; i < qc.constraints().size(); i++) {
const auto& cs = qc.constraints()[i];
auto* v = argv[i];
switch (cs.iColumn) {
case CountersTable::Column::kTimestamp:
FilterColumn(counters.timestamps(), 0, cs, v, &filter);
break;
case CountersTable::Column::kValue:
FilterColumn(counters.values(), 0, cs, v, &filter);
break;
case CountersTable::Column::kName:
FilterColumn(counters.name_ids(), 0, cs, v, &filter);
break;
case CountersTable::Column::kRef:
FilterColumn(counters.refs(), 0, cs, v, &filter);
break;
case CountersTable::Column::kDuration:
FilterColumn(counters.durations(), 0, cs, v, &filter);
break;
case CountersTable::Column::kValueDelta:
FilterColumn(counters.value_deltas(), 0, cs, v, &filter);
break;
case CountersTable::Column::kRefType: {
// TODO(lalitm): add support for filtering here.
}
}
}
sorted_rows_ = CreateSortedIndexFromFilter(
0, filter, [this, &qc](uint32_t f, uint32_t s) {
return CompareCounters(storage_, f, s, qc.order_by()) < 0;
});
}
int CountersTable::Cursor::Column(sqlite3_context* context, int N) {
size_t row = sorted_rows_[next_row_idx_];
switch (N) {
case Column::kTimestamp: {
sqlite3_result_int64(
context,
static_cast<int64_t>(storage_->counters().timestamps()[row]));
break;
}
case Column::kValue: {
sqlite3_result_int64(
context, static_cast<int64_t>(storage_->counters().values()[row]));
break;
}
case Column::kName: {
sqlite3_result_text(
context,
storage_->GetString(storage_->counters().name_ids()[row]).c_str(), -1,
nullptr);
break;
}
case Column::kRef: {
sqlite3_result_int64(
context, static_cast<int64_t>(storage_->counters().refs()[row]));
break;
}
case Column::kRefType: {
switch (storage_->counters().types()[row]) {
case RefType::kCPU_ID: {
sqlite3_result_text(context, "cpu", -1, nullptr);
break;
}
case RefType::kUTID: {
sqlite3_result_text(context, "utid", -1, nullptr);
break;
}
case RefType::kNoRef: {
sqlite3_result_null(context);
break;
}
case RefType::kIrq: {
sqlite3_result_text(context, "irq", -1, nullptr);
break;
}
case RefType::kSoftIrq: {
sqlite3_result_text(context, "softirq", -1, nullptr);
break;
}
}
break;
}
case Column::kDuration: {
sqlite3_result_int64(
context, static_cast<int64_t>(storage_->counters().durations()[row]));
break;
}
case Column::kValueDelta: {
sqlite3_result_int64(
context,
static_cast<int64_t>(storage_->counters().value_deltas()[row]));
break;
}
default:
PERFETTO_FATAL("Unknown column %d", N);
break;
}
return SQLITE_OK;
}
int CountersTable::Cursor::Next() {
next_row_idx_++;
return SQLITE_OK;
}
int CountersTable::Cursor::Eof() {
return next_row_idx_ >= sorted_rows_.size();
}
} // namespace trace_processor
} // namespace perfetto