xref: /aosp_15_r20/external/perfetto/src/trace_processor/metrics/metrics.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2019 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 #ifndef SRC_TRACE_PROCESSOR_METRICS_METRICS_H_
18 #define SRC_TRACE_PROCESSOR_METRICS_METRICS_H_
19 
20 #include <sqlite3.h>
21 
22 #include <cstddef>
23 #include <cstdint>
24 #include <optional>
25 #include <string>
26 #include <unordered_map>
27 #include <vector>
28 
29 #include "perfetto/base/status.h"
30 #include "perfetto/ext/base/status_or.h"
31 #include "perfetto/ext/base/string_view.h"
32 #include "perfetto/protozero/message.h"
33 #include "perfetto/protozero/packed_repeated_fields.h"
34 #include "perfetto/protozero/scattered_heap_buffer.h"
35 #include "perfetto/trace_processor/basic_types.h"
36 #include "perfetto/trace_processor/trace_processor.h"
37 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
38 #include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
39 #include "src/trace_processor/sqlite/bindings/sqlite_aggregate_function.h"
40 #include "src/trace_processor/util/descriptors.h"
41 
42 #include "protos/perfetto/trace_processor/metrics_impl.pbzero.h"
43 
44 namespace perfetto::trace_processor::metrics {
45 
46 // A description of a SQL metric in C++.
47 struct SqlMetricFile {
48   // The path of this file with the root at the metrics root.
49   std::string path;
50 
51   // The field in the output proto which will be filled by the result of
52   // querying the table specified by |output_table_name|.
53   // Optional because not all protos need to have a field associated with them
54   // in the root proto; most files will be just be run using RUN_METRIC by
55   // other files.
56   std::optional<std::string> proto_field_name;
57 
58   // The table name which will be created by the SQL below to read the proto
59   // bytes from.
60   // Should only be set when |proto_field_name| is set.
61   std::optional<std::string> output_table_name;
62 
63   // The SQL run by this metric.
64   std::string sql;
65 };
66 
67 // Helper class to build a nested (metric) proto checking the schema against
68 // a descriptor.
69 // Visible for testing.
70 class ProtoBuilder {
71  public:
72   ProtoBuilder(const DescriptorPool*, const ProtoDescriptor*);
73 
74   base::Status AppendSqlValue(const std::string& field_name,
75                               const SqlValue& value);
76 
77   // Returns the serialized |protos::ProtoBuilderResult| with the built proto
78   // as the nested |protobuf| message.
79   // Note: no other functions should be called on this class after this method
80   // is called.
81   std::vector<uint8_t> SerializeToProtoBuilderResult();
82 
83   // Returns the serialized version of the raw message being built.
84   // This function should only be used at the top level where type checking is
85   // no longer important because the proto will be returned as is. In all other
86   // instances, prefer |SerializeToProtoBuilderResult()| instead.
87   // Note: no other functions should be called on this class after this method
88   // is called.
89   std::vector<uint8_t> SerializeRaw();
90 
91  private:
92   base::Status AppendSingleLong(const FieldDescriptor& field, int64_t value);
93   base::Status AppendSingleDouble(const FieldDescriptor& field, double value);
94   base::Status AppendSingleString(const FieldDescriptor& field,
95                                   base::StringView data);
96   base::Status AppendSingleBytes(const FieldDescriptor& field,
97                                  const uint8_t* ptr,
98                                  size_t size);
99   base::Status AppendRepeated(const FieldDescriptor& field,
100                               const uint8_t* ptr,
101                               size_t size);
102 
103   base::StatusOr<const FieldDescriptor*> FindFieldByName(
104       const std::string& field_name);
105 
106   const DescriptorPool* pool_ = nullptr;
107   const ProtoDescriptor* descriptor_ = nullptr;
108   protozero::HeapBuffered<protozero::Message> message_;
109 };
110 
111 // Helper class to combine a set of repeated fields into a single proto blob
112 // to return to SQLite.
113 // Visible for testing.
114 class RepeatedFieldBuilder {
115  public:
116   RepeatedFieldBuilder();
117 
118   base::Status AddSqlValue(SqlValue value);
119 
120   // Returns the serialized |protos::ProtoBuilderResult| with the set of
121   // repeated fields as |repeated_values| in the proto.
122   // Note: no other functions should be called on this class after this method
123   // is called.
124   std::vector<uint8_t> SerializeToProtoBuilderResult();
125 
126  private:
127   base::Status AddLong(int64_t value);
128   base::Status AddDouble(double value);
129   base::Status AddString(base::StringView value);
130   base::Status AddBytes(const uint8_t* data, size_t size);
131 
132   base::Status EnsureType(SqlValue::Type);
133 
134   protozero::HeapBuffered<protos::pbzero::ProtoBuilderResult> message_;
135   std::optional<SqlValue::Type> repeated_field_type_;
136   protos::pbzero::RepeatedBuilderResult* repeated_ = nullptr;
137   protozero::PackedFixedSizeInt<int64_t> int64_packed_repeated_;
138   protozero::PackedFixedSizeInt<double> double_packed_repeated_;
139 };
140 
141 // Replaces templated variables inside |raw_text| using the substitution given
142 // by |substitutions| writing the result to |out|.
143 // The syntax followed is a cut-down variant of Jinja. This means variables that
144 // are to be replaced use {{variable-name}} in the raw text with subsitutions
145 // containing a mapping from (variable-name -> replacement).
146 int TemplateReplace(
147     const std::string& raw_text,
148     const std::unordered_map<std::string, std::string>& substitutions,
149     std::string* out);
150 
151 // Implements the NULL_IF_EMPTY SQL function.
152 struct NullIfEmpty : public SqlFunction {
153   static base::Status Run(void* ctx,
154                           size_t argc,
155                           sqlite3_value** argv,
156                           SqlValue& out,
157                           Destructors&);
158 };
159 
160 // Implements all the proto creation functions.
161 struct BuildProto : public SqlFunction {
162   struct Context {
163     TraceProcessor* tp;
164     const DescriptorPool* pool;
165     uint32_t descriptor_idx;
166   };
167   static base::Status Run(Context* ctx,
168                           size_t argc,
169                           sqlite3_value** argv,
170                           SqlValue& out,
171                           Destructors&);
172 };
173 
174 // Implements the RUN_METRIC SQL function.
175 struct RunMetric : public SqlFunction {
176   struct Context {
177     PerfettoSqlEngine* engine;
178     std::vector<SqlMetricFile>* metrics;
179   };
180   static constexpr bool kVoidReturn = true;
181   static base::Status Run(Context* ctx,
182                           size_t argc,
183                           sqlite3_value** argv,
184                           SqlValue& out,
185                           Destructors&);
186 };
187 
188 // Implements the UNWRAP_METRIC_PROTO SQL function.
189 struct UnwrapMetricProto : public SqlFunction {
190   static base::Status Run(Context* ctx,
191                           size_t argc,
192                           sqlite3_value** argv,
193                           SqlValue& out,
194                           Destructors&);
195 };
196 
197 // These functions implement the RepeatedField SQL aggregate functions.
198 struct RepeatedField : public SqliteAggregateFunction<RepeatedField> {
199   static constexpr char kName[] = "RepeatedField";
200   static constexpr int kArgCount = 1;
201 
202   static void Step(sqlite3_context* ctx, int argc, sqlite3_value** argv);
203   static void Final(sqlite3_context* ctx);
204 };
205 
206 base::Status ComputeMetrics(PerfettoSqlEngine*,
207                             const std::vector<std::string>& metrics_to_compute,
208                             const std::vector<SqlMetricFile>& metrics,
209                             const DescriptorPool& pool,
210                             const ProtoDescriptor& root_descriptor,
211                             std::vector<uint8_t>* metrics_proto);
212 
213 }  // namespace perfetto::trace_processor::metrics
214 
215 #endif  // SRC_TRACE_PROCESSOR_METRICS_METRICS_H_
216