• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     int64_t rawId = sqlite3_column_int64(res->stmt.sqlite_stmt(), 0);
101     uint32_t id = static_cast<uint32_t>(rawId);
102     if (PERFETTO_UNLIKELY(rawId != id)) {
103       *zErr = sqlite3_mprintf(
104           "slice_mipmap: id %lld is too large to fit in 32 bits", rawId);
105       return SQLITE_ERROR;
106     }
107     int64_t ts = sqlite3_column_int64(res->stmt.sqlite_stmt(), 1);
108     int64_t dur = sqlite3_column_int64(res->stmt.sqlite_stmt(), 2);
109     auto depth =
110         static_cast<uint32_t>(sqlite3_column_int64(res->stmt.sqlite_stmt(), 3));
111     if (PERFETTO_UNLIKELY(depth >= state->by_depth.size())) {
112       state->by_depth.resize(depth + 1);
113     }
114     auto& by_depth = state->by_depth[depth];
115     by_depth.forest.Push(
116         Slice{dur, id, static_cast<uint32_t>(by_depth.forest.size())});
117     by_depth.timestamps.push_back(ts);
118   } while (res->stmt.Step());
119   if (!res->stmt.status().ok()) {
120     *zErr = sqlite3_mprintf("%s", res->stmt.status().c_message());
121     return SQLITE_ERROR;
122   }
123 
124   std::unique_ptr<Vtab> vtab_res = std::make_unique<Vtab>();
125   vtab_res->state = ctx->manager.OnCreate(argv, std::move(state));
126   *vtab = vtab_res.release();
127   return SQLITE_OK;
128 }
129 
Destroy(sqlite3_vtab * vtab)130 int SliceMipmapOperator::Destroy(sqlite3_vtab* vtab) {
131   std::unique_ptr<Vtab> tab(GetVtab(vtab));
132   sqlite::ModuleStateManager<SliceMipmapOperator>::OnDestroy(tab->state);
133   return SQLITE_OK;
134 }
135 
Connect(sqlite3 * db,void * raw_ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char **)136 int SliceMipmapOperator::Connect(sqlite3* db,
137                                  void* raw_ctx,
138                                  int argc,
139                                  const char* const* argv,
140                                  sqlite3_vtab** vtab,
141                                  char**) {
142   PERFETTO_CHECK(argc == 4);
143   if (int ret = sqlite3_declare_vtab(db, kSliceSchema); ret != SQLITE_OK) {
144     return ret;
145   }
146   auto* ctx = GetContext(raw_ctx);
147   std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
148   res->state = ctx->manager.OnConnect(argv);
149   *vtab = res.release();
150   return SQLITE_OK;
151 }
152 
Disconnect(sqlite3_vtab * vtab)153 int SliceMipmapOperator::Disconnect(sqlite3_vtab* vtab) {
154   std::unique_ptr<Vtab> tab(GetVtab(vtab));
155   sqlite::ModuleStateManager<SliceMipmapOperator>::OnDisconnect(tab->state);
156   return SQLITE_OK;
157 }
158 
BestIndex(sqlite3_vtab *,sqlite3_index_info * info)159 int SliceMipmapOperator::BestIndex(sqlite3_vtab*, sqlite3_index_info* info) {
160   base::Status status =
161       sqlite::utils::ValidateFunctionArguments(info, kArgCount, IsArgColumn);
162   if (!status.ok()) {
163     return SQLITE_CONSTRAINT;
164   }
165   if (info->nConstraint != kArgCount) {
166     return SQLITE_CONSTRAINT;
167   }
168   return SQLITE_OK;
169 }
170 
Open(sqlite3_vtab *,sqlite3_vtab_cursor ** cursor)171 int SliceMipmapOperator::Open(sqlite3_vtab*, sqlite3_vtab_cursor** cursor) {
172   std::unique_ptr<Cursor> c = std::make_unique<Cursor>();
173   *cursor = c.release();
174   return SQLITE_OK;
175 }
176 
Close(sqlite3_vtab_cursor * cursor)177 int SliceMipmapOperator::Close(sqlite3_vtab_cursor* cursor) {
178   std::unique_ptr<Cursor> c(GetCursor(cursor));
179   return SQLITE_OK;
180 }
181 
Filter(sqlite3_vtab_cursor * cursor,int,const char *,int argc,sqlite3_value ** argv)182 int SliceMipmapOperator::Filter(sqlite3_vtab_cursor* cursor,
183                                 int,
184                                 const char*,
185                                 int argc,
186                                 sqlite3_value** argv) {
187   auto* c = GetCursor(cursor);
188   auto* t = GetVtab(c->pVtab);
189   auto* state =
190       sqlite::ModuleStateManager<SliceMipmapOperator>::GetState(t->state);
191   PERFETTO_CHECK(argc == kArgCount);
192 
193   c->results.clear();
194   c->index = 0;
195 
196   int64_t start = sqlite3_value_int64(argv[0]);
197   int64_t end = sqlite3_value_int64(argv[1]);
198   int64_t step = sqlite3_value_int64(argv[2]);
199 
200   for (uint32_t depth = 0; depth < state->by_depth.size(); ++depth) {
201     auto& by_depth = state->by_depth[depth];
202     const auto& tses = by_depth.timestamps;
203 
204     // If the slice before this window overlaps with the current window, move
205     // the iterator back one to consider it as well.
206     auto start_idx = static_cast<uint32_t>(std::distance(
207         tses.begin(), std::lower_bound(tses.begin(), tses.end(), start)));
208     if (start_idx != 0 &&
209         (static_cast<size_t>(start_idx) == tses.size() ||
210          (tses[start_idx] != start &&
211           tses[start_idx] + by_depth.forest[start_idx].dur > start))) {
212       --start_idx;
213     }
214 
215     for (int64_t s = start; s < end; s += step) {
216       auto end_idx = static_cast<uint32_t>(std::distance(
217           tses.begin(),
218           std::lower_bound(tses.begin() + static_cast<int64_t>(start_idx),
219                            tses.end(), s + step)));
220       if (start_idx == end_idx) {
221         continue;
222       }
223       auto res = by_depth.forest.Query(start_idx, end_idx);
224       c->results.emplace_back(Cursor::Result{
225           tses[res.idx],
226           res.dur,
227           res.id,
228           depth,
229       });
230       start_idx = end_idx;
231     }
232   }
233   return SQLITE_OK;
234 }
235 
Next(sqlite3_vtab_cursor * cursor)236 int SliceMipmapOperator::Next(sqlite3_vtab_cursor* cursor) {
237   GetCursor(cursor)->index++;
238   return SQLITE_OK;
239 }
240 
Eof(sqlite3_vtab_cursor * cursor)241 int SliceMipmapOperator::Eof(sqlite3_vtab_cursor* cursor) {
242   auto* c = GetCursor(cursor);
243   return c->index >= c->results.size();
244 }
245 
Column(sqlite3_vtab_cursor * cursor,sqlite3_context * ctx,int N)246 int SliceMipmapOperator::Column(sqlite3_vtab_cursor* cursor,
247                                 sqlite3_context* ctx,
248                                 int N) {
249   auto* t = GetVtab(cursor->pVtab);
250   auto* c = GetCursor(cursor);
251   switch (N) {
252     case ColumnIndex::kTs:
253       sqlite::result::Long(ctx, c->results[c->index].timestamp);
254       return SQLITE_OK;
255     case ColumnIndex::kId:
256       sqlite::result::Long(ctx, c->results[c->index].id);
257       return SQLITE_OK;
258     case ColumnIndex::kDur:
259       sqlite::result::Long(ctx, c->results[c->index].dur);
260       return SQLITE_OK;
261     case ColumnIndex::kDepth:
262       sqlite::result::Long(ctx, c->results[c->index].depth);
263       return SQLITE_OK;
264     default:
265       return sqlite::utils::SetError(t, "Bad column");
266   }
267   PERFETTO_FATAL("For GCC");
268 }
269 
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)270 int SliceMipmapOperator::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
271   return SQLITE_ERROR;
272 }
273 
274 }  // namespace perfetto::trace_processor
275