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 <sqlite3.h>
20 #include <memory>
21
22 #include "perfetto/base/logging.h"
23 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
24 #include "src/trace_processor/storage/stats.h"
25 #include "src/trace_processor/storage/trace_storage.h"
26
27 namespace perfetto::trace_processor {
28
Connect(sqlite3 * db,void * aux,int,const char * const *,sqlite3_vtab ** vtab,char **)29 int StatsModule::Connect(sqlite3* db,
30 void* aux,
31 int,
32 const char* const*,
33 sqlite3_vtab** vtab,
34 char**) {
35 static constexpr char kSchema[] = R"(
36 CREATE TABLE x(
37 name TEXT,
38 idx BIGINT,
39 severity TEXT,
40 source TEXT,
41 value BIGINT,
42 description TEXT,
43 PRIMARY KEY(name)
44 ) WITHOUT ROWID
45 )";
46 if (int ret = sqlite3_declare_vtab(db, kSchema); ret != SQLITE_OK) {
47 return ret;
48 }
49 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
50 res->storage = GetContext(aux);
51 *vtab = res.release();
52 return SQLITE_OK;
53 }
54
Disconnect(sqlite3_vtab * vtab)55 int StatsModule::Disconnect(sqlite3_vtab* vtab) {
56 delete GetVtab(vtab);
57 return SQLITE_OK;
58 }
59
BestIndex(sqlite3_vtab *,sqlite3_index_info *)60 int StatsModule::BestIndex(sqlite3_vtab*, sqlite3_index_info*) {
61 return SQLITE_OK;
62 }
63
Open(sqlite3_vtab * raw_vtab,sqlite3_vtab_cursor ** cursor)64 int StatsModule::Open(sqlite3_vtab* raw_vtab, sqlite3_vtab_cursor** cursor) {
65 std::unique_ptr<Cursor> c = std::make_unique<Cursor>();
66 c->storage = GetVtab(raw_vtab)->storage;
67 *cursor = c.release();
68 return SQLITE_OK;
69 }
70
Close(sqlite3_vtab_cursor * cursor)71 int StatsModule::Close(sqlite3_vtab_cursor* cursor) {
72 delete GetCursor(cursor);
73 return SQLITE_OK;
74 }
75
Filter(sqlite3_vtab_cursor * cursor,int,const char *,int,sqlite3_value **)76 int StatsModule::Filter(sqlite3_vtab_cursor* cursor,
77 int,
78 const char*,
79 int,
80 sqlite3_value**) {
81 auto* c = GetCursor(cursor);
82 c->key = {};
83 c->it = {};
84 return SQLITE_OK;
85 }
86
Next(sqlite3_vtab_cursor * cursor)87 int StatsModule::Next(sqlite3_vtab_cursor* cursor) {
88 static_assert(stats::kTypes[0] == stats::kSingle,
89 "the first stats entry cannot be indexed");
90
91 auto* c = GetCursor(cursor);
92 const auto* cur_entry = &c->storage->stats()[c->key];
93 if (stats::kTypes[c->key] == stats::kIndexed) {
94 if (++c->it != cur_entry->indexed_values.end()) {
95 return SQLITE_OK;
96 }
97 }
98 while (++c->key < stats::kNumKeys) {
99 cur_entry = &c->storage->stats()[c->key];
100 c->it = cur_entry->indexed_values.begin();
101 if (stats::kTypes[c->key] == stats::kSingle ||
102 !cur_entry->indexed_values.empty()) {
103 break;
104 }
105 }
106 return SQLITE_OK;
107 }
108
Eof(sqlite3_vtab_cursor * cursor)109 int StatsModule::Eof(sqlite3_vtab_cursor* cursor) {
110 return GetCursor(cursor)->key >= stats::kNumKeys;
111 }
112
Column(sqlite3_vtab_cursor * cursor,sqlite3_context * ctx,int N)113 int StatsModule::Column(sqlite3_vtab_cursor* cursor,
114 sqlite3_context* ctx,
115 int N) {
116 auto* c = GetCursor(cursor);
117 switch (N) {
118 case Column::kName:
119 sqlite::result::StaticString(ctx, stats::kNames[c->key]);
120 break;
121 case Column::kIndex:
122 if (stats::kTypes[c->key] == stats::kIndexed) {
123 sqlite::result::Long(ctx, c->it->first);
124 } else {
125 sqlite::result::Null(ctx);
126 }
127 break;
128 case Column::kSeverity:
129 switch (stats::kSeverities[c->key]) {
130 case stats::kInfo:
131 sqlite::result::StaticString(ctx, "info");
132 break;
133 case stats::kDataLoss:
134 sqlite::result::StaticString(ctx, "data_loss");
135 break;
136 case stats::kError:
137 sqlite::result::StaticString(ctx, "error");
138 break;
139 }
140 break;
141 case Column::kSource:
142 switch (stats::kSources[c->key]) {
143 case stats::kTrace:
144 sqlite::result::StaticString(ctx, "trace");
145 break;
146 case stats::kAnalysis:
147 sqlite::result::StaticString(ctx, "analysis");
148 break;
149 }
150 break;
151 case Column::kValue:
152 if (stats::kTypes[c->key] == stats::kIndexed) {
153 sqlite::result::Long(ctx, c->it->second);
154 } else {
155 sqlite::result::Long(ctx, c->storage->stats()[c->key].value);
156 }
157 break;
158 case Column::kDescription:
159 sqlite::result::StaticString(ctx, stats::kDescriptions[c->key]);
160 break;
161 default:
162 PERFETTO_FATAL("Unknown column %d", N);
163 break;
164 }
165 return SQLITE_OK;
166 }
167
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)168 int StatsModule::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
169 return SQLITE_ERROR;
170 }
171
172 } // namespace perfetto::trace_processor
173