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