1 /*
2 * Copyright (C) 2024 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/perfetto_sql/intrinsics/operators/counter_mipmap_operator.h"
18
19 #include <sqlite3.h>
20 #include <algorithm>
21 #include <cstddef>
22 #include <cstdint>
23 #include <functional>
24 #include <iterator>
25 #include <memory>
26 #include <string>
27 #include <utility>
28
29 #include "perfetto/base/logging.h"
30 #include "perfetto/base/status.h"
31 #include "perfetto/ext/base/status_or.h"
32 #include "src/trace_processor/containers/implicit_segment_forest.h"
33 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
34 #include "src/trace_processor/sqlite/module_lifecycle_manager.h"
35 #include "src/trace_processor/sqlite/sql_source.h"
36 #include "src/trace_processor/sqlite/sqlite_utils.h"
37
38 namespace perfetto::trace_processor {
39 namespace {
40
41 constexpr char kSchema[] = R"(
42 CREATE TABLE x(
43 in_window_start BIGINT HIDDEN,
44 in_window_end BIGINT HIDDEN,
45 in_window_step BIGINT HIDDEN,
46 min_value DOUBLE,
47 max_value DOUBLE,
48 last_ts BIGINT,
49 last_value DOUBLE,
50 PRIMARY KEY(last_ts)
51 ) WITHOUT ROWID
52 )";
53
54 enum ColumnIndex : size_t {
55 kInWindowStart = 0,
56 kInWindowEnd,
57 kInWindowStep,
58
59 kMinValue,
60 kMaxValue,
61 kLastTs,
62 kLastValue,
63 };
64
65 constexpr size_t kArgCount = kInWindowStep + 1;
66
IsArgColumn(size_t index)67 bool IsArgColumn(size_t index) {
68 return index < kArgCount;
69 }
70
71 using Counter = CounterMipmapOperator::Counter;
72 using Agg = CounterMipmapOperator::Agg;
73 using Forest = ImplicitSegmentForest<Counter, Agg>;
74
75 } // namespace
76
Create(sqlite3 * db,void * raw_ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char ** zErr)77 int CounterMipmapOperator::Create(sqlite3* db,
78 void* raw_ctx,
79 int argc,
80 const char* const* argv,
81 sqlite3_vtab** vtab,
82 char** zErr) {
83 if (argc != 4) {
84 *zErr = sqlite3_mprintf("counter_mipmap: wrong number of arguments");
85 return SQLITE_ERROR;
86 }
87
88 if (int ret = sqlite3_declare_vtab(db, kSchema); ret != SQLITE_OK) {
89 return ret;
90 }
91
92 auto* ctx = GetContext(raw_ctx);
93 auto state = std::make_unique<State>();
94
95 std::string sql = "SELECT ts, value FROM ";
96 sql.append(argv[3]);
97 auto res = ctx->engine->ExecuteUntilLastStatement(
98 SqlSource::FromTraceProcessorImplementation(std::move(sql)));
99 if (!res.ok()) {
100 *zErr = sqlite3_mprintf("%s", res.status().c_message());
101 return SQLITE_ERROR;
102 }
103 do {
104 int64_t ts = sqlite3_column_int64(res->stmt.sqlite_stmt(), 0);
105 auto value = sqlite3_column_double(res->stmt.sqlite_stmt(), 1);
106 state->timestamps.push_back(ts);
107 state->forest.Push(Counter{value, value});
108 } while (res->stmt.Step());
109 if (!res->stmt.status().ok()) {
110 *zErr = sqlite3_mprintf("%s", res->stmt.status().c_message());
111 return SQLITE_ERROR;
112 }
113
114 std::unique_ptr<Vtab> vtab_res = std::make_unique<Vtab>();
115 vtab_res->state = ctx->manager.OnCreate(argv, std::move(state));
116 *vtab = vtab_res.release();
117 return SQLITE_OK;
118 }
119
Destroy(sqlite3_vtab * vtab)120 int CounterMipmapOperator::Destroy(sqlite3_vtab* vtab) {
121 std::unique_ptr<Vtab> tab(GetVtab(vtab));
122 sqlite::ModuleStateManager<CounterMipmapOperator>::OnDestroy(tab->state);
123 return SQLITE_OK;
124 }
125
Connect(sqlite3 * db,void * raw_ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char **)126 int CounterMipmapOperator::Connect(sqlite3* db,
127 void* raw_ctx,
128 int argc,
129 const char* const* argv,
130 sqlite3_vtab** vtab,
131 char**) {
132 PERFETTO_CHECK(argc == 4);
133 if (int ret = sqlite3_declare_vtab(db, kSchema); ret != SQLITE_OK) {
134 return ret;
135 }
136 auto* ctx = GetContext(raw_ctx);
137 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
138 res->state = ctx->manager.OnConnect(argv);
139 *vtab = res.release();
140 return SQLITE_OK;
141 }
142
Disconnect(sqlite3_vtab * vtab)143 int CounterMipmapOperator::Disconnect(sqlite3_vtab* vtab) {
144 std::unique_ptr<Vtab> tab(GetVtab(vtab));
145 sqlite::ModuleStateManager<CounterMipmapOperator>::OnDisconnect(tab->state);
146 return SQLITE_OK;
147 }
148
BestIndex(sqlite3_vtab *,sqlite3_index_info * info)149 int CounterMipmapOperator::BestIndex(sqlite3_vtab*, sqlite3_index_info* info) {
150 base::Status status =
151 sqlite::utils::ValidateFunctionArguments(info, kArgCount, IsArgColumn);
152 if (!status.ok()) {
153 return SQLITE_CONSTRAINT;
154 }
155 if (info->nConstraint != kArgCount) {
156 return SQLITE_CONSTRAINT;
157 }
158 return SQLITE_OK;
159 }
160
Open(sqlite3_vtab *,sqlite3_vtab_cursor ** cursor)161 int CounterMipmapOperator::Open(sqlite3_vtab*, sqlite3_vtab_cursor** cursor) {
162 std::unique_ptr<Cursor> c = std::make_unique<Cursor>();
163 *cursor = c.release();
164 return SQLITE_OK;
165 }
166
Close(sqlite3_vtab_cursor * cursor)167 int CounterMipmapOperator::Close(sqlite3_vtab_cursor* cursor) {
168 std::unique_ptr<Cursor> c(GetCursor(cursor));
169 return SQLITE_OK;
170 }
171
Filter(sqlite3_vtab_cursor * cursor,int,const char *,int argc,sqlite3_value ** argv)172 int CounterMipmapOperator::Filter(sqlite3_vtab_cursor* cursor,
173 int,
174 const char*,
175 int argc,
176 sqlite3_value** argv) {
177 auto* c = GetCursor(cursor);
178 auto* t = GetVtab(c->pVtab);
179 auto* state =
180 sqlite::ModuleStateManager<CounterMipmapOperator>::GetState(t->state);
181 PERFETTO_CHECK(argc == kArgCount);
182
183 int64_t start_ts = sqlite3_value_int64(argv[0]);
184 int64_t end_ts = sqlite3_value_int64(argv[1]);
185 int64_t step_ts = sqlite3_value_int64(argv[2]);
186
187 c->index = 0;
188 c->counters.clear();
189
190 // If there is a counter value before the start of this window, include it in
191 // the aggregation as well becaue it contributes to what should be rendered
192 // here.
193 auto ts_lb = std::lower_bound(state->timestamps.begin(),
194 state->timestamps.end(), start_ts);
195 if (ts_lb != state->timestamps.begin() &&
196 (ts_lb == state->timestamps.end() || *ts_lb != start_ts)) {
197 --ts_lb;
198 }
199 int64_t start_idx = std::distance(state->timestamps.begin(), ts_lb);
200 for (int64_t s = start_ts; s < end_ts; s += step_ts) {
201 int64_t end_idx =
202 std::distance(state->timestamps.begin(),
203 std::lower_bound(state->timestamps.begin() +
204 static_cast<int64_t>(start_idx),
205 state->timestamps.end(), s + step_ts));
206 if (start_idx == end_idx) {
207 continue;
208 }
209 c->counters.emplace_back(Cursor::Result{
210 state->forest.Query(static_cast<uint32_t>(start_idx),
211 static_cast<uint32_t>(end_idx)),
212 state->forest[static_cast<uint32_t>(end_idx) - 1],
213 state->timestamps[static_cast<uint32_t>(end_idx) - 1],
214 });
215 start_idx = end_idx;
216 }
217 return SQLITE_OK;
218 }
219
Next(sqlite3_vtab_cursor * cursor)220 int CounterMipmapOperator::Next(sqlite3_vtab_cursor* cursor) {
221 GetCursor(cursor)->index++;
222 return SQLITE_OK;
223 }
224
Eof(sqlite3_vtab_cursor * cursor)225 int CounterMipmapOperator::Eof(sqlite3_vtab_cursor* cursor) {
226 auto* c = GetCursor(cursor);
227 return c->index >= c->counters.size();
228 }
229
Column(sqlite3_vtab_cursor * cursor,sqlite3_context * ctx,int N)230 int CounterMipmapOperator::Column(sqlite3_vtab_cursor* cursor,
231 sqlite3_context* ctx,
232 int N) {
233 auto* t = GetVtab(cursor->pVtab);
234 auto* c = GetCursor(cursor);
235 const auto& res = c->counters[c->index];
236 switch (N) {
237 case ColumnIndex::kMinValue:
238 sqlite::result::Double(ctx, res.min_max_counter.min);
239 return SQLITE_OK;
240 case ColumnIndex::kMaxValue:
241 sqlite::result::Double(ctx, res.min_max_counter.max);
242 return SQLITE_OK;
243 case ColumnIndex::kLastTs:
244 sqlite::result::Long(ctx, res.last_ts);
245 return SQLITE_OK;
246 case ColumnIndex::kLastValue:
247 PERFETTO_DCHECK(
248 std::equal_to<>()(res.last_counter.min, res.last_counter.max));
249 sqlite::result::Double(ctx, res.last_counter.min);
250 return SQLITE_OK;
251 default:
252 return sqlite::utils::SetError(t, "Bad column");
253 }
254 PERFETTO_FATAL("For GCC");
255 }
256
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)257 int CounterMipmapOperator::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
258 return SQLITE_ERROR;
259 }
260
261 } // namespace perfetto::trace_processor
262