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