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_TABLES_MACROS_INTERNAL_H_ 18 #define SRC_TRACE_PROCESSOR_TABLES_MACROS_INTERNAL_H_ 19 20 #include <type_traits> 21 22 #include "src/trace_processor/db/table.h" 23 #include "src/trace_processor/db/typed_column.h" 24 25 namespace perfetto { 26 namespace trace_processor { 27 namespace macros_internal { 28 29 // We define this class to allow the table macro below to compile without 30 // needing templates; in reality none of the methods will be called because the 31 // pointer to this class will always be null. 32 class RootParentTable : public Table { 33 public: 34 struct Row { 35 public: RowRow36 Row(std::nullptr_t) {} 37 typeRow38 const char* type() const { return type_; } 39 40 protected: 41 const char* type_ = nullptr; 42 }; 43 // This class only exists to allow typechecking to work correctly in Insert 44 // below. If we had C++17 and if constexpr, we could statically verify that 45 // this was never created but for now, we still need to define it to satisfy 46 // the typechecker. 47 struct IdAndRow { 48 uint32_t id; 49 uint32_t row; 50 }; Insert(const Row &)51 IdAndRow Insert(const Row&) { PERFETTO_FATAL("Should not be called"); } 52 }; 53 54 // IdHelper is used to figure out the Id type for a table. 55 // 56 // We do this using templates with the following algorithm: 57 // 1. If the parent class is anything but RootParentTable, the Id of the 58 // table is the same as the Id of the parent. 59 // 2. If the parent class is RootParentTable (i.e. the table is a root 60 // table), then the Id is the one defined in the table itself. 61 // The net result of this is that all tables in the hierarchy get the 62 // same type of Id - the one defined in the root table of that hierarchy. 63 // 64 // Reasoning: We do this because using uint32_t is very overloaded and 65 // having a wrapper type for ids is very helpful to avoid confusion with 66 // row indices (especially because ids and row indices often appear in 67 // similar places in the codebase - that is at insertion in parsers and 68 // in trackers). 69 template <typename ParentClass, typename Class> 70 struct IdHelper { 71 using Id = typename ParentClass::Id; 72 }; 73 template <typename Class> 74 struct IdHelper<RootParentTable, Class> { 75 using Id = typename Class::DefinedId; 76 }; 77 78 // The parent class for all macro generated tables. 79 // This class is used to extract common code from the macro tables to reduce 80 // code size. 81 class MacroTable : public Table { 82 public: 83 MacroTable(const char* name, StringPool* pool, Table* parent) 84 : Table(pool, parent), name_(name), parent_(parent) { 85 row_maps_.emplace_back(); 86 if (!parent) { 87 columns_.emplace_back( 88 Column::IdColumn(this, static_cast<uint32_t>(columns_.size()), 89 static_cast<uint32_t>(row_maps_.size()) - 1)); 90 columns_.emplace_back( 91 Column("type", &type_, Column::kNoFlag, this, 92 static_cast<uint32_t>(columns_.size()), 93 static_cast<uint32_t>(row_maps_.size()) - 1)); 94 } 95 } 96 ~MacroTable() override; 97 98 // We don't want a move or copy constructor because we store pointers to 99 // fields of macro tables which will be invalidated if we move/copy them. 100 MacroTable(const MacroTable&) = delete; 101 MacroTable& operator=(const MacroTable&) = delete; 102 103 MacroTable(MacroTable&&) = delete; 104 MacroTable& operator=(MacroTable&&) noexcept = delete; 105 106 const char* table_name() const { return name_; } 107 108 protected: 109 void UpdateRowMapsAfterParentInsert() { 110 if (parent_ != nullptr) { 111 // If there is a parent table, add the last inserted row in each of the 112 // parent row maps to the corresponding row map in the child. 113 for (uint32_t i = 0; i < parent_->row_maps().size(); ++i) { 114 const RowMap& parent_rm = parent_->row_maps()[i]; 115 row_maps_[i].Insert(parent_rm.Get(parent_rm.size() - 1)); 116 } 117 } 118 // Also add the index of the new row to the identity row map and increment 119 // the size. 120 row_maps_.back().Insert(row_count_++); 121 } 122 123 // Stores the most specific "derived" type of this row in the table. 124 // 125 // For example, suppose a row is inserted into the gpu_slice table. This will 126 // also cause a row to be inserted into the slice table. For users querying 127 // the slice table, they will want to know the "real" type of this slice (i.e. 128 // they will want to see that the type is gpu_slice). This sparse vector 129 // stores precisely the real type. 130 // 131 // Only relevant for parentless tables. Will be empty and unreferenced by 132 // tables with parents. 133 NullableVector<StringPool::Id> type_; 134 135 private: 136 const char* name_ = nullptr; 137 Table* parent_ = nullptr; 138 }; 139 140 } // namespace macros_internal 141 142 // Ignore GCC warning about a missing argument for a variadic macro parameter. 143 #if defined(__GNUC__) || defined(__clang__) 144 #pragma GCC system_header 145 #endif 146 147 // Basic helper macros. 148 #define PERFETTO_TP_NOOP(...) 149 150 // Gets the class name from a table definition. 151 #define PERFETTO_TP_EXTRACT_TABLE_CLASS(class_name, ...) class_name 152 #define PERFETTO_TP_TABLE_CLASS(DEF) \ 153 DEF(PERFETTO_TP_EXTRACT_TABLE_CLASS, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP) 154 155 // Gets the table name from the table definition. 156 #define PERFETTO_TP_EXTRACT_TABLE_NAME(_, table_name) table_name 157 #define PERFETTO_TP_TABLE_NAME(DEF) \ 158 DEF(PERFETTO_TP_EXTRACT_TABLE_NAME, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP) 159 160 // Gets the parent definition from a table definition. 161 #define PERFETTO_TP_EXTRACT_PARENT_DEF(PARENT_DEF, _) PARENT_DEF 162 #define PERFETTO_TP_PARENT_DEF(DEF) \ 163 DEF(PERFETTO_TP_NOOP, PERFETTO_TP_EXTRACT_PARENT_DEF, PERFETTO_TP_NOOP) 164 165 // Invokes FN on each column in the definition of the table. We define a 166 // recursive macro as we need to walk up the hierarchy until we hit the root. 167 // Currently, we hardcode 5 levels but this can be increased as necessary. 168 #define PERFETTO_TP_ALL_COLUMNS_0(DEF, arg) \ 169 static_assert(false, "Macro recursion depth exceeded"); 170 #define PERFETTO_TP_ALL_COLUMNS_1(DEF, arg) \ 171 DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_0, arg) 172 #define PERFETTO_TP_ALL_COLUMNS_2(DEF, arg) \ 173 DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_1, arg) 174 #define PERFETTO_TP_ALL_COLUMNS_3(DEF, arg) \ 175 DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_2, arg) 176 #define PERFETTO_TP_ALL_COLUMNS_4(DEF, arg) \ 177 DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_3, arg) 178 #define PERFETTO_TP_ALL_COLUMNS(DEF, arg) \ 179 DEF(PERFETTO_TP_NOOP, PERFETTO_TP_ALL_COLUMNS_4, arg) 180 181 // Invokes FN on each column in the table definition. 182 #define PERFETTO_TP_TABLE_COLUMNS(DEF, FN) \ 183 DEF(PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, FN) 184 185 // Invokes FN on each column in every ancestor of the table. 186 #define PERFETTO_TP_PARENT_COLUMNS(DEF, FN) \ 187 PERFETTO_TP_ALL_COLUMNS(PERFETTO_TP_PARENT_DEF(DEF), FN) 188 189 // Basic macros for extracting column info from a schema. 190 #define PERFETTO_TP_NAME_COMMA(type, name, ...) name, 191 #define PERFETTO_TP_TYPE_NAME_COMMA(type, name, ...) type name, 192 193 // Constructor parameters of Table::Row. 194 // We name this name_c to avoid a clash with the field names of 195 // Table::Row. 196 #define PERFETTO_TP_ROW_CONSTRUCTOR(type, name, ...) type name##_c = {}, 197 198 // Constructor parameters for parent of Row. 199 #define PERFETTO_TP_PARENT_ROW_CONSTRUCTOR(type, name, ...) name##_c, 200 201 // Initializes the members of Table::Row. 202 #define PERFETTO_TP_ROW_INITIALIZER(type, name, ...) name = name##_c; 203 204 // Defines the variable in Table::Row. 205 #define PERFETTO_TP_ROW_DEFINITION(type, name, ...) type name = {}; 206 207 // Used to generate an equality implementation on Table::Row. 208 #define PERFETTO_TP_ROW_EQUALS(type, name, ...) \ 209 TypedColumn<type>::Equals(other.name, name)&& 210 211 // Defines the parent row field in Insert. 212 #define PERFETTO_TP_PARENT_ROW_INSERT(type, name, ...) row.name, 213 214 // Defines the member variable in the Table. 215 #define PERFETTO_TP_TABLE_MEMBER(type, name, ...) \ 216 NullableVector<TypedColumn<type>::serialized_type> name##_; 217 218 #define PERFETTO_TP_COLUMN_FLAG_HAS_FLAG_COL(type, name, flags) \ 219 case ColumnIndex::name: \ 220 return static_cast<uint32_t>(flags) | TypedColumn<type>::default_flags(); 221 222 #define PERFETTO_TP_COLUMN_FLAG_NO_FLAG_COL(type, name) \ 223 case ColumnIndex::name: \ 224 return TypedColumn<type>::default_flags(); 225 226 #define PERFETTO_TP_COLUMN_FLAG_CHOOSER(type, name, maybe_flags, fn, ...) fn 227 228 // MSVC has slightly different rules about __VA_ARGS__ expansion. This makes it 229 // behave similarly to GCC/Clang. 230 // See https://stackoverflow.com/q/5134523/14028266 . 231 #define PERFETTO_TP_EXPAND_VA_ARGS(x) x 232 233 #define PERFETTO_TP_COLUMN_FLAG(...) \ 234 PERFETTO_TP_EXPAND_VA_ARGS(PERFETTO_TP_COLUMN_FLAG_CHOOSER( \ 235 __VA_ARGS__, PERFETTO_TP_COLUMN_FLAG_HAS_FLAG_COL, \ 236 PERFETTO_TP_COLUMN_FLAG_NO_FLAG_COL)(__VA_ARGS__)) 237 238 // Creates the sparse vector with the given flags. 239 #define PERFETTO_TP_TABLE_CONSTRUCTOR_SV(type, name, ...) \ 240 name##_ = \ 241 (FlagsForColumn(ColumnIndex::name) & Column::Flag::kDense) \ 242 ? NullableVector<TypedColumn<type>::serialized_type>::Dense() \ 243 : NullableVector<TypedColumn<type>::serialized_type>::Sparse(); 244 245 // Invokes the chosen column constructor by passing the given args. 246 #define PERFETTO_TP_TABLE_CONSTRUCTOR_COLUMN(type, name, ...) \ 247 columns_.emplace_back(#name, &name##_, FlagsForColumn(ColumnIndex::name), \ 248 this, columns_.size(), row_maps_.size() - 1); 249 250 // Inserts the value into the corresponding column. 251 #define PERFETTO_TP_COLUMN_APPEND(type, name, ...) \ 252 mutable_##name()->Append(std::move(row.name)); 253 254 // Creates a schema entry for the corresponding column. 255 #define PERFETTO_TP_COLUMN_SCHEMA(type, name, ...) \ 256 schema.columns.emplace_back(Table::Schema::Column{ \ 257 #name, TypedColumn<type>::SqlValueType(), false, \ 258 static_cast<bool>(FlagsForColumn(ColumnIndex::name) & \ 259 Column::Flag::kSorted), \ 260 static_cast<bool>(FlagsForColumn(ColumnIndex::name) & \ 261 Column::Flag::kHidden)}); 262 263 // Defines the accessors for a column. 264 #define PERFETTO_TP_TABLE_COL_ACCESSOR(type, name, ...) \ 265 const TypedColumn<type>& name() const { \ 266 return static_cast<const TypedColumn<type>&>( \ 267 columns_[static_cast<uint32_t>(ColumnIndex::name)]); \ 268 } \ 269 \ 270 TypedColumn<type>* mutable_##name() { \ 271 return static_cast<TypedColumn<type>*>( \ 272 &columns_[static_cast<uint32_t>(ColumnIndex::name)]); \ 273 } 274 275 // Definition used as the parent of root tables. 276 #define PERFETTO_TP_ROOT_TABLE_PARENT_DEF(NAME, PARENT, C) \ 277 NAME(macros_internal::RootParentTable, "root") 278 279 // For more general documentation, see PERFETTO_TP_TABLE in macros.h. 280 #define PERFETTO_TP_TABLE_INTERNAL(table_name, class_name, parent_class_name, \ 281 DEF) \ 282 class class_name : public macros_internal::MacroTable { \ 283 private: \ 284 /* \ 285 * Allows IdHelper to access DefinedId for root tables. \ 286 * Needs to be defined here to allow the public using declaration of Id \ 287 * below to work correctly. \ 288 */ \ 289 friend struct macros_internal::IdHelper<parent_class_name, class_name>; \ 290 \ 291 /* \ 292 * Defines a new id type for a heirarchy of tables. \ 293 * We define it here as we need this type to be visible for the public \ 294 * using declaration of Id below. \ 295 * Note: This type will only used if this table is a root table. \ 296 */ \ 297 struct DefinedId : public BaseId { \ 298 DefinedId() = default; \ 299 explicit constexpr DefinedId(uint32_t v) : BaseId(v) {} \ 300 }; \ 301 \ 302 public: \ 303 /* \ 304 * This defines the type of the id to be the type of the root \ 305 * table of the hierarchy - see IdHelper for more details. \ 306 */ \ 307 using Id = macros_internal::IdHelper<parent_class_name, class_name>::Id; \ 308 struct Row : parent_class_name::Row { \ 309 /* \ 310 * Expands to Row(col_type1 col1_c, base::Optional<col_type2> col2_c, \ 311 * ...) \ 312 */ \ 313 Row(PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_ROW_CONSTRUCTOR) \ 314 std::nullptr_t = nullptr) \ 315 : parent_class_name::Row(PERFETTO_TP_PARENT_COLUMNS( \ 316 DEF, \ 317 PERFETTO_TP_PARENT_ROW_CONSTRUCTOR) nullptr) { \ 318 type_ = table_name; \ 319 \ 320 /* \ 321 * Expands to \ 322 * col1 = col1_c; \ 323 * col2 = col2_c; \ 324 * ... \ 325 */ \ 326 PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_ROW_INITIALIZER) \ 327 } \ 328 \ 329 bool operator==(const class_name::Row& other) const { \ 330 return PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_ROW_EQUALS) true; \ 331 } \ 332 \ 333 /* \ 334 * Expands to \ 335 * col_type1 col1 = {}; \ 336 * base::Optional<col_type2> col2 = {}; \ 337 * ... \ 338 */ \ 339 PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_ROW_DEFINITION) \ 340 }; \ 341 \ 342 enum class ColumnIndex : uint32_t { \ 343 id, \ 344 type, /* Expands to col1, col2, ... */ \ 345 PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_NAME_COMMA) kNumCols \ 346 }; \ 347 \ 348 /* Return value of Insert giving access to id and row number */ \ 349 struct IdAndRow { \ 350 Id id; \ 351 uint32_t row; \ 352 }; \ 353 \ 354 class_name(StringPool* pool, parent_class_name* parent) \ 355 : macros_internal::MacroTable(table_name, pool, parent), \ 356 parent_(parent) { \ 357 /* \ 358 * Expands to \ 359 * col1_ = NullableVector<col1_type>(mode) \ 360 * ... \ 361 */ \ 362 PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_CONSTRUCTOR_SV); \ 363 /* \ 364 * Expands to \ 365 * columns_.emplace_back("col1", col1_, Column::kNoFlag, this, \ 366 * columns_.size(), row_maps_.size() - 1); \ 367 * columns_.emplace_back("col2", col2_, Column::kNoFlag, this, \ 368 * columns_.size(), row_maps_.size() - 1); \ 369 * ... \ 370 */ \ 371 PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_CONSTRUCTOR_COLUMN); \ 372 } \ 373 ~class_name() override; \ 374 \ 375 IdAndRow Insert(const Row& row) { \ 376 Id id; \ 377 uint32_t row_number = row_count(); \ 378 if (parent_ == nullptr) { \ 379 id = Id{row_number}; \ 380 type_.Append(string_pool_->InternString(row.type())); \ 381 } else { \ 382 id = Id{parent_->Insert(row).id}; \ 383 } \ 384 UpdateRowMapsAfterParentInsert(); \ 385 \ 386 /* \ 387 * Expands to \ 388 * col1_.Append(row.col1); \ 389 * col2_.Append(row.col2); \ 390 * ... \ 391 */ \ 392 PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_COLUMN_APPEND); \ 393 return {id, row_number}; \ 394 } \ 395 \ 396 const IdColumn<Id>& id() const { \ 397 return static_cast<const IdColumn<Id>&>( \ 398 columns_[static_cast<uint32_t>(ColumnIndex::id)]); \ 399 } \ 400 \ 401 const TypedColumn<StringPool::Id>& type() const { \ 402 return static_cast<const TypedColumn<StringPool::Id>&>( \ 403 columns_[static_cast<uint32_t>(ColumnIndex::type)]); \ 404 } \ 405 \ 406 static Table::Schema Schema() { \ 407 Table::Schema schema; \ 408 schema.columns.emplace_back(Table::Schema::Column{ \ 409 "id", SqlValue::Type::kLong, true, true, false}); \ 410 schema.columns.emplace_back(Table::Schema::Column{ \ 411 "type", SqlValue::Type::kString, false, false, false}); \ 412 PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_COLUMN_SCHEMA); \ 413 return schema; \ 414 } \ 415 \ 416 /* \ 417 * Expands to \ 418 * const TypedColumn<col1_type>& col1() { return col1_; } \ 419 * TypedColumn<col1_type>* mutable_col1() { return &col1_; } \ 420 * const TypedColumn<col2_type>& col2() { return col2_; } \ 421 * TypedColumn<col2_type>* mutable_col2() { return &col2_; } \ 422 * ... \ 423 */ \ 424 PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_TABLE_COL_ACCESSOR) \ 425 \ 426 private: \ 427 static uint32_t FlagsForColumn(const ColumnIndex index) { \ 428 switch (index) { \ 429 case ColumnIndex::kNumCols: \ 430 PERFETTO_FATAL("Invalid index"); \ 431 case ColumnIndex::id: \ 432 return Column::kIdFlags; \ 433 case ColumnIndex::type: \ 434 return Column::kNoFlag; \ 435 /* \ 436 * Expands to: \ 437 * case ColumnIndex::col1: \ 438 * return TypedColumn<col_type1>::default_flags(); \ 439 * ... \ 440 */ \ 441 PERFETTO_TP_ALL_COLUMNS(DEF, PERFETTO_TP_COLUMN_FLAG) \ 442 } \ 443 PERFETTO_FATAL("For GCC"); \ 444 } \ 445 \ 446 parent_class_name* parent_; \ 447 \ 448 /* \ 449 * Expands to \ 450 * NullableVector<col1_type> col1_; \ 451 * NullableVector<col2_type> col2_; \ 452 * ... \ 453 */ \ 454 PERFETTO_TP_TABLE_COLUMNS(DEF, PERFETTO_TP_TABLE_MEMBER) \ 455 } 456 457 } // namespace trace_processor 458 } // namespace perfetto 459 460 #endif // SRC_TRACE_PROCESSOR_TABLES_MACROS_INTERNAL_H_ 461