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