1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/sqlite/stats_table.h"
18
19 #include "perfetto/base/status.h"
20 #include "src/trace_processor/sqlite/sqlite_utils.h"
21
22 namespace perfetto {
23 namespace trace_processor {
24
StatsTable(sqlite3 *,const TraceStorage * storage)25 StatsTable::StatsTable(sqlite3*, const TraceStorage* storage)
26 : storage_(storage) {}
27
28 StatsTable::~StatsTable() = default;
29
Init(int,const char * const *,Schema * schema)30 util::Status StatsTable::Init(int, const char* const*, Schema* schema) {
31 *schema = Schema(
32 {
33 SqliteTable::Column(Column::kName, "name", SqlValue::Type::kString),
34 // Calling a column "index" causes sqlite to silently fail, hence idx.
35 SqliteTable::Column(Column::kIndex, "idx", SqlValue::Type::kLong),
36 SqliteTable::Column(Column::kSeverity, "severity",
37 SqlValue::Type::kString),
38 SqliteTable::Column(Column::kSource, "source",
39 SqlValue::Type::kString),
40 SqliteTable::Column(Column::kValue, "value", SqlValue::Type::kLong),
41 SqliteTable::Column(Column::kDescription, "description",
42 SqlValue::Type::kString),
43 },
44 {Column::kName});
45 return util::OkStatus();
46 }
47
CreateCursor()48 std::unique_ptr<SqliteTable::BaseCursor> StatsTable::CreateCursor() {
49 return std::unique_ptr<SqliteTable::BaseCursor>(new Cursor(this));
50 }
51
BestIndex(const QueryConstraints &,BestIndexInfo *)52 int StatsTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
53 return SQLITE_OK;
54 }
55
Cursor(StatsTable * table)56 StatsTable::Cursor::Cursor(StatsTable* table)
57 : SqliteTable::BaseCursor(table),
58 table_(table),
59 storage_(table->storage_) {}
60
61 StatsTable::Cursor::~Cursor() = default;
62
Filter(const QueryConstraints &,sqlite3_value **,FilterHistory)63 base::Status StatsTable::Cursor::Filter(const QueryConstraints&,
64 sqlite3_value**,
65 FilterHistory) {
66 *this = Cursor(table_);
67 return base::OkStatus();
68 }
69
Column(sqlite3_context * ctx,int N)70 base::Status StatsTable::Cursor::Column(sqlite3_context* ctx, int N) {
71 const auto kSqliteStatic = sqlite_utils::kSqliteStatic;
72 switch (N) {
73 case Column::kName:
74 sqlite3_result_text(ctx, stats::kNames[key_], -1, kSqliteStatic);
75 break;
76 case Column::kIndex:
77 if (stats::kTypes[key_] == stats::kIndexed) {
78 sqlite3_result_int(ctx, index_->first);
79 } else {
80 sqlite3_result_null(ctx);
81 }
82 break;
83 case Column::kSeverity:
84 switch (stats::kSeverities[key_]) {
85 case stats::kInfo:
86 sqlite3_result_text(ctx, "info", -1, kSqliteStatic);
87 break;
88 case stats::kDataLoss:
89 sqlite3_result_text(ctx, "data_loss", -1, kSqliteStatic);
90 break;
91 case stats::kError:
92 sqlite3_result_text(ctx, "error", -1, kSqliteStatic);
93 break;
94 }
95 break;
96 case Column::kSource:
97 switch (stats::kSources[key_]) {
98 case stats::kTrace:
99 sqlite3_result_text(ctx, "trace", -1, kSqliteStatic);
100 break;
101 case stats::kAnalysis:
102 sqlite3_result_text(ctx, "analysis", -1, kSqliteStatic);
103 break;
104 }
105 break;
106 case Column::kValue:
107 if (stats::kTypes[key_] == stats::kIndexed) {
108 sqlite3_result_int64(ctx, index_->second);
109 } else {
110 sqlite3_result_int64(ctx, storage_->stats()[key_].value);
111 }
112 break;
113 case Column::kDescription:
114 sqlite3_result_text(ctx, stats::kDescriptions[key_], -1, kSqliteStatic);
115 break;
116 default:
117 PERFETTO_FATAL("Unknown column %d", N);
118 break;
119 }
120 return base::OkStatus();
121 }
122
Next()123 base::Status StatsTable::Cursor::Next() {
124 static_assert(stats::kTypes[0] == stats::kSingle,
125 "the first stats entry cannot be indexed");
126 const auto* cur_entry = &storage_->stats()[key_];
127 if (stats::kTypes[key_] == stats::kIndexed) {
128 if (++index_ != cur_entry->indexed_values.end()) {
129 return base::OkStatus();
130 }
131 }
132 while (++key_ < stats::kNumKeys) {
133 cur_entry = &storage_->stats()[key_];
134 index_ = cur_entry->indexed_values.begin();
135 if (stats::kTypes[key_] == stats::kSingle ||
136 !cur_entry->indexed_values.empty()) {
137 break;
138 }
139 }
140 return base::OkStatus();
141 }
142
Eof()143 bool StatsTable::Cursor::Eof() {
144 return key_ >= stats::kNumKeys;
145 }
146
147 } // namespace trace_processor
148 } // namespace perfetto
149