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/slice_mipmap_operator.h"
18
19 #include <sqlite3.h>
20 #include <algorithm>
21 #include <cstddef>
22 #include <cstdint>
23 #include <iterator>
24 #include <memory>
25 #include <string>
26 #include <utility>
27
28 #include "perfetto/base/logging.h"
29 #include "perfetto/base/status.h"
30 #include "perfetto/ext/base/status_or.h"
31 #include "perfetto/public/compiler.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 kSliceSchema[] = R"(
42 CREATE TABLE x(
43 in_window_start BIGINT HIDDEN,
44 in_window_end BIGINT HIDDEN,
45 in_window_step BIGINT HIDDEN,
46 ts BIGINT,
47 id BIGINT,
48 dur BIGINT,
49 depth INTEGER,
50 PRIMARY KEY(id)
51 ) WITHOUT ROWID
52 )";
53
54 enum ColumnIndex : size_t {
55 kInWindowStart = 0,
56 kInWindowEnd,
57 kInWindowStep,
58
59 kTs,
60 kId,
61 kDur,
62 kDepth,
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 } // namespace
72
Create(sqlite3 * db,void * raw_ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char ** zErr)73 int SliceMipmapOperator::Create(sqlite3* db,
74 void* raw_ctx,
75 int argc,
76 const char* const* argv,
77 sqlite3_vtab** vtab,
78 char** zErr) {
79 if (argc != 4) {
80 *zErr = sqlite3_mprintf("slice_mipmap: wrong number of arguments");
81 return SQLITE_ERROR;
82 }
83
84 if (int ret = sqlite3_declare_vtab(db, kSliceSchema); ret != SQLITE_OK) {
85 return ret;
86 }
87
88 auto* ctx = GetContext(raw_ctx);
89 auto state = std::make_unique<State>();
90
91 std::string sql = "SELECT * FROM ";
92 sql.append(argv[3]);
93 auto res = ctx->engine->ExecuteUntilLastStatement(
94 SqlSource::FromTraceProcessorImplementation(std::move(sql)));
95 if (!res.ok()) {
96 *zErr = sqlite3_mprintf("%s", res.status().c_message());
97 return SQLITE_ERROR;
98 }
99 do {
100 auto id =
101 static_cast<uint32_t>(sqlite3_column_int64(res->stmt.sqlite_stmt(), 0));
102 int64_t ts = sqlite3_column_int64(res->stmt.sqlite_stmt(), 1);
103 int64_t dur = sqlite3_column_int64(res->stmt.sqlite_stmt(), 2);
104 auto depth =
105 static_cast<uint32_t>(sqlite3_column_int64(res->stmt.sqlite_stmt(), 3));
106 if (PERFETTO_UNLIKELY(depth >= state->by_depth.size())) {
107 state->by_depth.resize(depth + 1);
108 }
109 auto& by_depth = state->by_depth[depth];
110 by_depth.forest.Push(
111 Slice{dur, id, static_cast<uint32_t>(by_depth.forest.size())});
112 by_depth.timestamps.push_back(ts);
113 } while (res->stmt.Step());
114 if (!res->stmt.status().ok()) {
115 *zErr = sqlite3_mprintf("%s", res->stmt.status().c_message());
116 return SQLITE_ERROR;
117 }
118
119 std::unique_ptr<Vtab> vtab_res = std::make_unique<Vtab>();
120 vtab_res->state = ctx->manager.OnCreate(argv, std::move(state));
121 *vtab = vtab_res.release();
122 return SQLITE_OK;
123 }
124
Destroy(sqlite3_vtab * vtab)125 int SliceMipmapOperator::Destroy(sqlite3_vtab* vtab) {
126 std::unique_ptr<Vtab> tab(GetVtab(vtab));
127 sqlite::ModuleStateManager<SliceMipmapOperator>::OnDestroy(tab->state);
128 return SQLITE_OK;
129 }
130
Connect(sqlite3 * db,void * raw_ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char **)131 int SliceMipmapOperator::Connect(sqlite3* db,
132 void* raw_ctx,
133 int argc,
134 const char* const* argv,
135 sqlite3_vtab** vtab,
136 char**) {
137 PERFETTO_CHECK(argc == 4);
138 if (int ret = sqlite3_declare_vtab(db, kSliceSchema); ret != SQLITE_OK) {
139 return ret;
140 }
141 auto* ctx = GetContext(raw_ctx);
142 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
143 res->state = ctx->manager.OnConnect(argv);
144 *vtab = res.release();
145 return SQLITE_OK;
146 }
147
Disconnect(sqlite3_vtab * vtab)148 int SliceMipmapOperator::Disconnect(sqlite3_vtab* vtab) {
149 std::unique_ptr<Vtab> tab(GetVtab(vtab));
150 sqlite::ModuleStateManager<SliceMipmapOperator>::OnDisconnect(tab->state);
151 return SQLITE_OK;
152 }
153
BestIndex(sqlite3_vtab *,sqlite3_index_info * info)154 int SliceMipmapOperator::BestIndex(sqlite3_vtab*, sqlite3_index_info* info) {
155 base::Status status =
156 sqlite::utils::ValidateFunctionArguments(info, kArgCount, IsArgColumn);
157 if (!status.ok()) {
158 return SQLITE_CONSTRAINT;
159 }
160 if (info->nConstraint != kArgCount) {
161 return SQLITE_CONSTRAINT;
162 }
163 return SQLITE_OK;
164 }
165
Open(sqlite3_vtab *,sqlite3_vtab_cursor ** cursor)166 int SliceMipmapOperator::Open(sqlite3_vtab*, sqlite3_vtab_cursor** cursor) {
167 std::unique_ptr<Cursor> c = std::make_unique<Cursor>();
168 *cursor = c.release();
169 return SQLITE_OK;
170 }
171
Close(sqlite3_vtab_cursor * cursor)172 int SliceMipmapOperator::Close(sqlite3_vtab_cursor* cursor) {
173 std::unique_ptr<Cursor> c(GetCursor(cursor));
174 return SQLITE_OK;
175 }
176
Filter(sqlite3_vtab_cursor * cursor,int,const char *,int argc,sqlite3_value ** argv)177 int SliceMipmapOperator::Filter(sqlite3_vtab_cursor* cursor,
178 int,
179 const char*,
180 int argc,
181 sqlite3_value** argv) {
182 auto* c = GetCursor(cursor);
183 auto* t = GetVtab(c->pVtab);
184 auto* state =
185 sqlite::ModuleStateManager<SliceMipmapOperator>::GetState(t->state);
186 PERFETTO_CHECK(argc == kArgCount);
187
188 c->results.clear();
189 c->index = 0;
190
191 int64_t start = sqlite3_value_int64(argv[0]);
192 int64_t end = sqlite3_value_int64(argv[1]);
193 int64_t step = sqlite3_value_int64(argv[2]);
194
195 if (start == end) {
196 return sqlite::utils::SetError(t, "slice_mipmap: empty range provided");
197 }
198
199 for (uint32_t depth = 0; depth < state->by_depth.size(); ++depth) {
200 auto& by_depth = state->by_depth[depth];
201 const auto& tses = by_depth.timestamps;
202
203 // If the slice before this window overlaps with the current window, move
204 // the iterator back one to consider it as well.
205 auto start_idx = static_cast<uint32_t>(std::distance(
206 tses.begin(), std::lower_bound(tses.begin(), tses.end(), start)));
207 if (start_idx != 0 &&
208 (static_cast<size_t>(start_idx) == tses.size() ||
209 (tses[start_idx] != start &&
210 tses[start_idx] + by_depth.forest[start_idx].dur > start))) {
211 --start_idx;
212 }
213
214 for (int64_t s = start; s < end; s += step) {
215 auto end_idx = static_cast<uint32_t>(std::distance(
216 tses.begin(),
217 std::lower_bound(tses.begin() + static_cast<int64_t>(start_idx),
218 tses.end(), s + step)));
219 if (start_idx == end_idx) {
220 continue;
221 }
222 auto res = by_depth.forest.Query(start_idx, end_idx);
223 c->results.emplace_back(Cursor::Result{
224 tses[res.idx],
225 res.dur,
226 res.id,
227 depth,
228 });
229 start_idx = end_idx;
230 }
231 }
232 return SQLITE_OK;
233 }
234
Next(sqlite3_vtab_cursor * cursor)235 int SliceMipmapOperator::Next(sqlite3_vtab_cursor* cursor) {
236 GetCursor(cursor)->index++;
237 return SQLITE_OK;
238 }
239
Eof(sqlite3_vtab_cursor * cursor)240 int SliceMipmapOperator::Eof(sqlite3_vtab_cursor* cursor) {
241 auto* c = GetCursor(cursor);
242 return c->index >= c->results.size();
243 }
244
Column(sqlite3_vtab_cursor * cursor,sqlite3_context * ctx,int N)245 int SliceMipmapOperator::Column(sqlite3_vtab_cursor* cursor,
246 sqlite3_context* ctx,
247 int N) {
248 auto* t = GetVtab(cursor->pVtab);
249 auto* c = GetCursor(cursor);
250 switch (N) {
251 case ColumnIndex::kTs:
252 sqlite::result::Long(ctx, c->results[c->index].timestamp);
253 return SQLITE_OK;
254 case ColumnIndex::kId:
255 sqlite::result::Long(ctx, c->results[c->index].id);
256 return SQLITE_OK;
257 case ColumnIndex::kDur:
258 sqlite::result::Long(ctx, c->results[c->index].dur);
259 return SQLITE_OK;
260 case ColumnIndex::kDepth:
261 sqlite::result::Long(ctx, c->results[c->index].depth);
262 return SQLITE_OK;
263 default:
264 return sqlite::utils::SetError(t, "Bad column");
265 }
266 PERFETTO_FATAL("For GCC");
267 }
268
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)269 int SliceMipmapOperator::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
270 return SQLITE_ERROR;
271 }
272
273 } // namespace perfetto::trace_processor
274