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