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