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/functions/counter_intervals.h"
18 
19 #include <algorithm>
20 #include <cinttypes>
21 #include <cstdint>
22 #include <iterator>
23 #include <memory>
24 #include <numeric>
25 #include <string>
26 #include <string_view>
27 #include <utility>
28 #include <variant>
29 #include <vector>
30 
31 #include "perfetto/base/compiler.h"
32 #include "perfetto/base/logging.h"
33 #include "perfetto/base/status.h"
34 #include "perfetto/ext/base/flat_hash_map.h"
35 #include "perfetto/ext/base/status_or.h"
36 #include "perfetto/ext/base/string_utils.h"
37 #include "perfetto/trace_processor/basic_types.h"
38 #include "src/trace_processor/containers/string_pool.h"
39 #include "src/trace_processor/db/runtime_table.h"
40 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
41 #include "src/trace_processor/perfetto_sql/intrinsics/types/counter.h"
42 #include "src/trace_processor/perfetto_sql/intrinsics/types/partitioned_intervals.h"
43 #include "src/trace_processor/perfetto_sql/parser/function_util.h"
44 #include "src/trace_processor/sqlite/bindings/sqlite_bind.h"
45 #include "src/trace_processor/sqlite/bindings/sqlite_column.h"
46 #include "src/trace_processor/sqlite/bindings/sqlite_function.h"
47 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
48 #include "src/trace_processor/sqlite/bindings/sqlite_stmt.h"
49 #include "src/trace_processor/sqlite/bindings/sqlite_type.h"
50 #include "src/trace_processor/sqlite/bindings/sqlite_value.h"
51 #include "src/trace_processor/sqlite/sqlite_utils.h"
52 #include "src/trace_processor/util/status_macros.h"
53 
54 namespace perfetto::trace_processor::perfetto_sql {
55 namespace {
56 
57 struct CounterIntervals : public SqliteFunction<CounterIntervals> {
58   static constexpr char kName[] = "__intrinsic_counter_intervals";
59   static constexpr int kArgCount = 3;
60 
61   struct UserDataContext {
62     PerfettoSqlEngine* engine;
63     StringPool* pool;
64   };
65 
Stepperfetto::trace_processor::perfetto_sql::__anonf40574020111::CounterIntervals66   static void Step(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
67     PERFETTO_DCHECK(argc == kArgCount);
68     const char* leading_str = sqlite::value::Text(argv[0]);
69     if (!leading_str) {
70       return sqlite::result::Error(
71           ctx, "interval intersect: column list cannot be null");
72     }
73 
74     // TODO(mayzner): Support 'lagging'.
75     if (base::CaseInsensitiveEqual("lagging", leading_str)) {
76       return sqlite::result::Error(
77           ctx, "interval intersect: 'lagging' is not implemented");
78     }
79     if (!base::CaseInsensitiveEqual("leading", leading_str)) {
80       return sqlite::result::Error(ctx,
81                                    "interval intersect: second argument has to "
82                                    "be either 'leading' or 'lagging");
83     }
84 
85     int64_t trace_end = sqlite::value::Int64(argv[1]);
86 
87     // Get column names of return columns.
88     std::vector<std::string> ret_col_names{
89         "id", "ts", "dur", "track_id", "value", "next_value", "delta_value"};
90     std::vector<RuntimeTable::BuilderColumnType> col_types{
91         RuntimeTable::kInt,         // id
92         RuntimeTable::kInt,         // ts,
93         RuntimeTable::kInt,         // dur
94         RuntimeTable::kInt,         // track_id
95         RuntimeTable::kDouble,      // value
96         RuntimeTable::kNullDouble,  // next_value
97         RuntimeTable::kNullDouble,  // delta_value
98     };
99 
100     auto partitioned_counter = sqlite::value::Pointer<PartitionedCounter>(
101         argv[2], PartitionedCounter::kName);
102     if (!partitioned_counter) {
103       SQLITE_ASSIGN_OR_RETURN(
104           ctx, std::unique_ptr<RuntimeTable> ret_table,
105           RuntimeTable::Builder(GetUserData(ctx)->pool, ret_col_names)
106               .Build(0));
107       return sqlite::result::UniquePointer(ctx, std::move(ret_table), "TABLE");
108     }
109 
110     RuntimeTable::Builder builder(GetUserData(ctx)->pool, ret_col_names,
111                                   col_types);
112 
113     uint32_t rows_count = 0;
114     for (auto track_counter = partitioned_counter->partitions_map.GetIterator();
115          track_counter; ++track_counter) {
116       int64_t track_id = track_counter.key();
117       const auto& cols = track_counter.value();
118       size_t r_count = cols.id.size();
119       rows_count += r_count;
120 
121       // Id
122       builder.AddNonNullIntegersUnchecked(0, cols.id);
123       // Ts
124       builder.AddNonNullIntegersUnchecked(1, cols.ts);
125 
126       // Dur
127       std::vector<int64_t> dur(r_count);
128       for (size_t i = 0; i < r_count - 1; i++) {
129         dur[i] = cols.ts[i + 1] - cols.ts[i];
130       }
131       dur[r_count - 1] = trace_end - cols.ts.back();
132       builder.AddNonNullIntegersUnchecked(2, dur);
133 
134       // Track id
135       builder.AddIntegers(3, track_id, static_cast<uint32_t>(r_count));
136       // Value
137       builder.AddNonNullDoublesUnchecked(4, cols.val);
138 
139       // Next value
140       std::vector<double> next_vals(cols.val.begin() + 1, cols.val.end());
141       builder.AddNullDoublesUnchecked(5, next_vals);
142       builder.AddNull(5);
143 
144       // Delta value
145       std::vector<double> deltas(r_count - 1);
146       for (size_t i = 0; i < r_count - 1; i++) {
147         deltas[i] = cols.val[i + 1] - cols.val[i];
148       }
149       builder.AddNull(6);
150       builder.AddNullDoublesUnchecked(6, deltas);
151     }
152 
153     SQLITE_ASSIGN_OR_RETURN(ctx, std::unique_ptr<RuntimeTable> ret_tab,
154                             std::move(builder).Build(rows_count));
155 
156     return sqlite::result::UniquePointer(ctx, std::move(ret_tab), "TABLE");
157   }
158 };
159 
160 }  // namespace
161 
RegisterCounterIntervalsFunctions(PerfettoSqlEngine & engine,StringPool * pool)162 base::Status RegisterCounterIntervalsFunctions(PerfettoSqlEngine& engine,
163                                                StringPool* pool) {
164   return engine.RegisterSqliteFunction<CounterIntervals>(
165       std::make_unique<CounterIntervals::UserDataContext>(
166           CounterIntervals::UserDataContext{&engine, pool}));
167 }
168 
169 }  // namespace perfetto::trace_processor::perfetto_sql
170