• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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_DB_TYPED_COLUMN_H_
18 #define SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_
19 
20 #include "src/trace_processor/db/column.h"
21 #include "src/trace_processor/db/typed_column_internal.h"
22 
23 namespace perfetto {
24 namespace trace_processor {
25 
26 // TypedColumn<T>
27 //
28 // Introduction:
29 // TypedColumn exists to allow efficient access to the data in a Column without
30 // having to go through dynamic type checking. There are two main reasons for
31 // this:
32 // 1. Performance: dynamic type checking is not free and so if this is used
33 //    in a particularily hot codepath, the typechecking can be a significant
34 //    overhead.
35 // 2. Ergonomics: having to convert back and forth from/to SqlValue causes
36 //    signifcant clutter in parts of the code which can already be quite hard
37 //    to follow (e.g. trackers like SequenceStackProfileTracker which perform
38 //    cross checking of various ids).
39 //
40 // Implementation:
41 // TypedColumn is implemented as a memberless subclass of Column. This allows
42 // us to static cast from a Column* to a TypedColumn<T> where we know the
43 // type T. The methods of TypedColumn are type-specialized methods of Column
44 // which allow callers to pass real types instead of using SqlValue.
45 //
46 // There are two helper classes (tc_internal::TypeHandler and
47 // tc_internal::Serializer) where we specialize behaviour which needs to be
48 // different based on T. See their class documentation and below for details
49 // on their purpose.
50 template <typename T>
51 class TypedColumn : public Column {
52  private:
53   using TH = tc_internal::TypeHandler<T>;
54 
55  public:
56   // The type of the data in this column.
57   using type = T;
58 
59   // The non-optional type of the data in this column.
60   using non_optional_type = typename TH::non_optional_type;
61 
62   // The type which should be passed to SqlValue functions.
63   using sql_value_type = typename TH::sql_value_type;
64 
65   // The type of which is actually stored inside ColumnStorage. Can be different
66   // from T because we treat table ids to just be uint32_t inside the storage
67   // (handling ids would add an extra type to consider when filtering for no
68   // benefit.
69   using stored_type = typename TH::stored_type;
70 
71  private:
72   using Serializer = tc_internal::Serializer<non_optional_type>;
73 
74  public:
75   T operator[](uint32_t row) const { return GetAtIdx(overlay().Get(row)); }
76 
77   // Special function only for string types to allow retrieving the string
78   // directly from the column.
79   template <bool is_string = TH::is_string>
GetString(uint32_t row)80   typename std::enable_if<is_string, NullTermStringView>::type GetString(
81       uint32_t row) const {
82     return GetStringAtIdx(overlay().Get(row));
83   }
84 
85   // Sets the data in the column at index |row|.
Set(uint32_t row,non_optional_type v)86   void Set(uint32_t row, non_optional_type v) {
87     SetAtIdx(overlay().Get(row), v);
88   }
89 
90   // Inserts the value at the end of the column.
Append(T v)91   void Append(T v) { mutable_storage()->Append(Serializer::Serialize(v)); }
92 
93   // Returns the row containing the given value in the Column.
IndexOf(sql_value_type v)94   std::optional<uint32_t> IndexOf(sql_value_type v) const {
95     return Column::IndexOf(ToSqlValue(v));
96   }
97 
ToVectorForTesting()98   std::vector<T> ToVectorForTesting() const {
99     std::vector<T> result(overlay().size());
100     for (uint32_t i = 0; i < overlay().size(); ++i)
101       result[i] = (*this)[i];
102     return result;
103   }
104 
105   // Helper functions to create constraints for the given value.
eq(sql_value_type v)106   Constraint eq(sql_value_type v) const { return eq_value(ToSqlValue(v)); }
gt(sql_value_type v)107   Constraint gt(sql_value_type v) const { return gt_value(ToSqlValue(v)); }
lt(sql_value_type v)108   Constraint lt(sql_value_type v) const { return lt_value(ToSqlValue(v)); }
ne(sql_value_type v)109   Constraint ne(sql_value_type v) const { return ne_value(ToSqlValue(v)); }
ge(sql_value_type v)110   Constraint ge(sql_value_type v) const { return ge_value(ToSqlValue(v)); }
le(sql_value_type v)111   Constraint le(sql_value_type v) const { return le_value(ToSqlValue(v)); }
112 
113   // Implements equality between two items of type |T|.
Equals(T a,T b)114   static constexpr bool Equals(T a, T b) { return TH::Equals(a, b); }
115 
116   // Encodes the default flags for a column of the current type.
default_flags()117   static constexpr uint32_t default_flags() {
118     return TH::is_optional ? Flag::kNoFlag : Flag::kNonNull;
119   }
120 
121   // Converts the static type T into the dynamic SqlValue type of this column.
SqlValueType()122   static SqlValue::Type SqlValueType() {
123     return Column::ToSqlValueType<stored_type>();
124   }
125 
126   // Cast a Column to TypedColumn or crash if that is unsafe.
FromColumn(Column * column)127   static TypedColumn<T>* FromColumn(Column* column) {
128     return FromColumnInternal<TypedColumn<T>>(column);
129   }
130 
131   // Cast a Column to TypedColumn or crash if that is unsafe.
FromColumn(const Column * column)132   static const TypedColumn<T>* FromColumn(const Column* column) {
133     return FromColumnInternal<const TypedColumn<T>>(column);
134   }
135 
136   // Public for use by macro tables.
SetAtIdx(uint32_t idx,non_optional_type v)137   void SetAtIdx(uint32_t idx, non_optional_type v) {
138     auto serialized = Serializer::Serialize(v);
139     mutable_storage()->Set(idx, serialized);
140   }
141 
142   // Public for use by macro tables.
GetAtIdx(uint32_t idx)143   T GetAtIdx(uint32_t idx) const {
144     return Serializer::Deserialize(TH::Get(storage(), idx));
145   }
146 
147   template <bool is_string = TH::is_string>
GetStringAtIdx(uint32_t idx)148   typename std::enable_if<is_string, NullTermStringView>::type GetStringAtIdx(
149       uint32_t idx) const {
150     return string_pool().Get(storage().Get(idx));
151   }
152 
153  private:
154   friend class Table;
155 
156   template <typename Output, typename Input>
FromColumnInternal(Input * column)157   static Output* FromColumnInternal(Input* column) {
158     // While casting from a base to derived without constructing as a derived is
159     // technically UB, in practice, this is at the heart of protozero (see
160     // Message::BeginNestedMessage) so we use it here.
161     static_assert(sizeof(TypedColumn<T>) == sizeof(Column),
162                   "TypedColumn cannot introduce extra state.");
163 
164     if (column->template IsColumnType<stored_type>() &&
165         (column->IsNullable() == TH::is_optional) && !column->IsId()) {
166       return static_cast<Output*>(column);
167     } else {
168       PERFETTO_FATAL("Unsafe to convert Column TypedColumn (%s)",
169                      column->name());
170     }
171   }
172 
storage()173   const ColumnStorage<stored_type>& storage() const {
174     return Column::storage<stored_type>();
175   }
mutable_storage()176   ColumnStorage<stored_type>* mutable_storage() {
177     return Column::mutable_storage<stored_type>();
178   }
179 };
180 
181 // Represents a column containing ids.
182 template <typename Id>
183 class IdColumn : public Column {
184  public:
185   // The type of the data in this column.
186   using type = Id;
187 
188   // The underlying type used when comparing ids.
189   using stored_type = uint32_t;
190 
191   Id operator[](uint32_t row) const { return Id(overlay().Get(row)); }
192 
IndexOf(Id id)193   std::optional<uint32_t> IndexOf(Id id) const {
194     return overlay().RowOf(id.value);
195   }
196 
197   // Public for use by macro tables.
GetAtIdx(uint32_t idx)198   Id GetAtIdx(uint32_t idx) const { return Id(idx); }
199 
200   // Static cast a Column to IdColumn or crash if that is likely to be
201   // unsafe.
FromColumn(const Column * column)202   static const IdColumn<Id>* FromColumn(const Column* column) {
203     // While casting from a base to derived without constructing as a derived is
204     // technically UB, in practice, this is at the heart of protozero (see
205     // Message::BeginNestedMessage) so we use it here.
206     static_assert(sizeof(IdColumn<Id>) == sizeof(Column),
207                   "TypedColumn cannot introduce extra state.");
208 
209     if (column->IsId()) {
210       return static_cast<const IdColumn<Id>*>(column);
211     } else {
212       PERFETTO_FATAL("Unsafe to convert Column to IdColumn (%s)",
213                      column->name());
214     }
215   }
216 
217   // Helper functions to create constraints for the given value.
eq(uint32_t v)218   Constraint eq(uint32_t v) const { return eq_value(SqlValue::Long(v)); }
gt(uint32_t v)219   Constraint gt(uint32_t v) const { return gt_value(SqlValue::Long(v)); }
lt(uint32_t v)220   Constraint lt(uint32_t v) const { return lt_value(SqlValue::Long(v)); }
ne(uint32_t v)221   Constraint ne(uint32_t v) const { return ne_value(SqlValue::Long(v)); }
ge(uint32_t v)222   Constraint ge(uint32_t v) const { return ge_value(SqlValue::Long(v)); }
le(uint32_t v)223   Constraint le(uint32_t v) const { return le_value(SqlValue::Long(v)); }
224 
225  private:
226   friend class Table;
227 };
228 
229 }  // namespace trace_processor
230 }  // namespace perfetto
231 
232 #endif  // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_
233