| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "src/trace_processor/db/view.h" |
| |
| #ifndef SRC_TRACE_PROCESSOR_VIEWS_MACROS_INTERNAL_H_ |
| #define SRC_TRACE_PROCESSOR_VIEWS_MACROS_INTERNAL_H_ |
| |
| namespace perfetto { |
| namespace trace_processor { |
| namespace macros_internal { |
| |
| template <typename T> |
| class ViewColumnBlueprint { |
| public: |
| using sql_value_type = typename TypedColumn<T>::sql_value_type; |
| |
| explicit ViewColumnBlueprint(uint32_t index_in_view) |
| : index_in_view_(index_in_view) {} |
| |
| // Returns an Order for each Order type for this ColumnBlueprint. |
| Constraint eq(sql_value_type v) const { |
| return Constraint{index_in_view_, FilterOp::kEq, ToValue(v)}; |
| } |
| Constraint gt(sql_value_type v) const { |
| return Constraint{index_in_view_, FilterOp::kGt, ToValue(v)}; |
| } |
| Constraint lt(sql_value_type v) const { |
| return Constraint{index_in_view_, FilterOp::kLt, ToValue(v)}; |
| } |
| Constraint ne(sql_value_type v) const { |
| return Constraint{index_in_view_, FilterOp::kNe, ToValue(v)}; |
| } |
| Constraint ge(sql_value_type v) const { |
| return Constraint{index_in_view_, FilterOp::kGe, ToValue(v)}; |
| } |
| Constraint le(sql_value_type v) const { |
| return Constraint{index_in_view_, FilterOp::kLe, ToValue(v)}; |
| } |
| |
| // Returns an Order for each Order type for this ColumnBlueprint. |
| Order ascending() const { return Order{index_in_view_, false}; } |
| Order descending() const { return Order{index_in_view_, true}; } |
| |
| private: |
| static SqlValue ToValue(double value) { return SqlValue::Double(value); } |
| static SqlValue ToValue(uint32_t value) { return SqlValue::Long(value); } |
| static SqlValue ToValue(int64_t value) { return SqlValue::Long(value); } |
| static SqlValue ToValue(NullTermStringView value) { |
| return SqlValue::String(value.c_str()); |
| } |
| |
| uint32_t index_in_view_ = 0; |
| }; |
| |
| // Ignore GCC warning about a missing argument for a variadic macro parameter. |
| #if defined(__GNUC__) || defined(__clang__) |
| #pragma GCC system_header |
| #endif |
| |
| // Basic helper macros. |
| #define PERFETTO_TP_NOOP(...) |
| |
| // Invokes FN on each column in the definition of the table. We define a |
| // recursive macro as we need to walk up the hierarchy until we hit the root. |
| // Currently, we hardcode 5 levels but this can be increased as necessary. |
| #define PERFETTO_TP_ALL_COLUMNS(DEF, arg) \ |
| DEF(PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, arg) |
| |
| // Invokes a View column function using data from a table column definition. |
| #define PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE(FN, col_name) \ |
| FN(col_name, from_table, col_name) |
| |
| // Invokes FN on the name and class name declaration of the view. |
| #define PERFETTO_TP_VIEW_NAME(DEF, FN) \ |
| DEF(FN, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, \ |
| PERFETTO_TP_NOOP) |
| |
| // Invokes FN on every table which is part of the view definition. |
| #define PERFETTO_TP_VIEW_FROM(DEF, FN) \ |
| DEF(PERFETTO_TP_NOOP, FN, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, \ |
| PERFETTO_TP_NOOP) |
| |
| // Invokes FN on every join which is part of the view definition. |
| #define PERFETTO_TP_VIEW_JOINS(DEF, FN) \ |
| DEF(PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, FN, PERFETTO_TP_NOOP, \ |
| PERFETTO_TP_NOOP) |
| |
| // Invokes FN on every column which is part of the view definition. |
| #define PERFETTO_TP_VIEW_COLUMNS(DEF, FROM_FROM_COLUMN_FN, FN) \ |
| DEF(PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, \ |
| FROM_FROM_COLUMN_FN) \ |
| DEF(PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, PERFETTO_TP_NOOP, FN, \ |
| PERFETTO_TP_NOOP) |
| |
| // Gets the class name from a view definition. |
| #define PERFETTO_TP_VIEW_CLASS_EXTRACT(class_name, ...) class_name |
| |
| // Gets the view name from the view definition. |
| #define PERFETTO_TP_VIEW_NAME_EXTRACT(_, view_name) view_name |
| |
| // Defines a table pointer for the macro constructor. |
| #define PERFETTO_TP_VIEW_CLASS_TABLE_COMMA_FROM(class_name, table_name, ...) \ |
| class_name *table_name, |
| |
| // Defines a table pointer for the macro constructor. |
| #define PERFETTO_TP_VIEW_CLASS_TABLE_COMMA_JOIN(class_name, table_name, ...) \ |
| class_name *table_name, |
| |
| // Defines a View table for the FROM table. |
| #define PERFETTO_TP_VIEW_FROM_PTR_NAME(_, table_name, ...) \ |
| table_name, #table_name |
| |
| // Defines a View::Join struct for a join defined in the macro. |
| #define PERFETTO_TP_VIEW_JOIN_DEFN(_, join_table, join_col, prev_table, \ |
| prev_col, flags) \ |
| View::JoinTable{join_table, #join_table, #join_col, \ |
| #prev_table, #prev_col, flags}, |
| |
| // Defines a View::Column struct for a column defined in the macro. |
| #define PERFETTO_TP_VIEW_COLUMN_DEFN(col_name, source_table, source_col) \ |
| View::OutputColumn{#col_name, TableName::source_table(), #source_col}, |
| |
| // Defines a View::Column struct for a column defined in the FROM table. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_DEFN(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE(PERFETTO_TP_VIEW_COLUMN_DEFN, \ |
| col_name) |
| |
| // Define a TableType alias for the FROM table. |
| #define PERFETTO_TP_VIEW_TABLE_TYPE(class_name, table_name, ...) \ |
| using table_name = class_name; |
| |
| // Define a special "from_table" TableType alias for the "FROM" table. |
| #define PERFETTO_TP_VIEW_TABLE_TYPE_FROM_ALIAS(_, table_name, ...) \ |
| using from_table = table_name; |
| |
| // Defines the table name for each table in the view. |
| #define PERFETTO_TP_VIEW_TABLE_NAME(_, table_name, ...) \ |
| static constexpr const char* table_name() { return #table_name; } |
| |
| // Define a special "from_table" TableType alias for the "FROM" table. |
| #define PERFETTO_TP_VIEW_TABLE_NAME_FROM_ALIAS(_, table_name, ...) \ |
| static constexpr const char* from_table() { return #table_name; } |
| |
| // Define a ColumnType alias for each column. |
| #define PERFETTO_TP_VIEW_COLUMN_TYPE(col_name, source_table, source_col) \ |
| using col_name = typename TableType::source_table::ColumnType::source_col; |
| |
| // Define a ColumnType alias for each column in the FROM table. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_TYPE(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE(PERFETTO_TP_VIEW_COLUMN_TYPE, \ |
| col_name) |
| |
| // Define a ColumnDataType alias for each column. |
| #define PERFETTO_TP_VIEW_COLUMN_DATA_TYPE(col_name, ...) \ |
| using col_name = typename ColumnType::col_name::type; |
| |
| // Define a ColumnDataType alias for each column in the FROM table. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_DATA_TYPE(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE( \ |
| PERFETTO_TP_VIEW_COLUMN_DATA_TYPE, col_name) |
| |
| // Defines an enum member for each column name. |
| #define PERFETTO_TP_VIEW_COLUMN_ENUM_INDEX(col_name, ...) col_name, |
| |
| // Defines an enum member for each column name in the FROM table.. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_ENUM_INDEX(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE( \ |
| PERFETTO_TP_VIEW_COLUMN_ENUM_INDEX, col_name) |
| |
| // Defines a column index alias for a column in the view. |
| #define PERFETTO_TP_VIEW_COLUMN_INDEX(col_name, ...) \ |
| static constexpr uint32_t col_name = \ |
| static_cast<uint32_t>(ColumnEnumIndex::col_name); |
| |
| // Defines a column index alias for a column in the FROM table. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_INDEX(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE( \ |
| PERFETTO_TP_VIEW_COLUMN_INDEX, col_name) |
| |
| // Defines a getter in QueryResult for a column in the view. |
| #define PERFETTO_TP_VIEW_COLUMN_QUERY_RESULT_GETTER(col_name, ...) \ |
| const ColumnType::col_name& col_name() const { \ |
| return *ColumnType::col_name::FromColumn( \ |
| &columns()[ColumnIndex::col_name]); \ |
| } |
| |
| // Defines a getter in QueryResult for a column in the FROM table. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_QUERY_RESULT_GETTER(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE( \ |
| PERFETTO_TP_VIEW_COLUMN_QUERY_RESULT_GETTER, col_name) |
| |
| // Defines a getter for the blueprint for each column. |
| #define PERFETTO_TP_VIEW_COL_BLUEPRINT_GETTER(col_name, ...) \ |
| macros_internal::ViewColumnBlueprint<ColumnDataType::col_name> col_name() \ |
| const { \ |
| return macros_internal::ViewColumnBlueprint<ColumnDataType::col_name>( \ |
| ColumnIndex::col_name); \ |
| } |
| |
| // Defines a getter for the blueprint for each column in the FROM table. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_BLUEPRINT_GETTER(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE( \ |
| PERFETTO_TP_VIEW_COL_BLUEPRINT_GETTER, col_name) |
| |
| // Defines a getter for a column in the RowReference. |
| #define PERFETTO_TP_VIEW_COLUMN_ROW_REF_GETTER(col_name, ...) \ |
| ColumnDataType::col_name col_name() const { \ |
| return table_->col_name()[row_number_]; \ |
| } |
| // Defines a getter for a FROM column in the RowReference. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_ROW_REF_GETTER(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE( \ |
| PERFETTO_TP_VIEW_COLUMN_ROW_REF_GETTER, col_name) |
| |
| // Defines a getter for a column in the Iterator. |
| #define PERFETTO_TP_VIEW_COLUMN_IT_GETTER(col_name, ...) \ |
| ColumnDataType::col_name col_name() const { \ |
| const auto& col = table_->col_name(); \ |
| return col.GetAtIdx(its_[col.overlay_index()].index()); \ |
| } |
| // Defines a getter for a FROM column in the RowReference. |
| #define PERFETTO_TP_VIEW_FROM_COLUMN_IT_GETTER(_, col_name, ...) \ |
| PERFETTO_TP_VIEW_INVOKE_VIEW_COL_FN_FROM_TABLE( \ |
| PERFETTO_TP_VIEW_COLUMN_IT_GETTER, col_name) |
| |
| // Defines a static assert for ensuring a given join clause is valid. |
| #define PERFETTO_TP_VIEW_JOIN_STATIC_ASSERT(_, join_table, join_col, \ |
| prev_table, prev_col, flags) \ |
| static_assert( \ |
| std::is_same< \ |
| TableType::join_table::ColumnType::join_col::type, \ |
| TableType::prev_table::ColumnType::prev_col::type>::value || \ |
| (((flags)&View::JoinFlag::kTypeCheckSerialized) != 0 && \ |
| std::is_same< \ |
| TableType::join_table::ColumnType::join_col::stored_type, \ |
| TableType::prev_table::ColumnType::prev_col::stored_type>:: \ |
| value), \ |
| "Both sides of join do not have the same type; check that you are " \ |
| "joining the correct tables and columns."); |
| |
| #define PERFETTO_TP_VIEW_INTERNAL(view_name, class_name, DEF) \ |
| class class_name : public View { \ |
| public: \ |
| class RowReference; \ |
| class RowNumber; \ |
| class Iterator; \ |
| class QueryResult; \ |
| \ |
| private: \ |
| struct TableType { \ |
| PERFETTO_TP_VIEW_FROM(DEF, PERFETTO_TP_VIEW_TABLE_TYPE) \ |
| PERFETTO_TP_VIEW_JOINS(DEF, PERFETTO_TP_VIEW_TABLE_TYPE) \ |
| PERFETTO_TP_VIEW_FROM(DEF, PERFETTO_TP_VIEW_TABLE_TYPE_FROM_ALIAS) \ |
| }; \ |
| \ |
| struct TableName { \ |
| PERFETTO_TP_VIEW_FROM(DEF, PERFETTO_TP_VIEW_TABLE_NAME) \ |
| PERFETTO_TP_VIEW_JOINS(DEF, PERFETTO_TP_VIEW_TABLE_NAME) \ |
| PERFETTO_TP_VIEW_FROM(DEF, PERFETTO_TP_VIEW_TABLE_NAME_FROM_ALIAS) \ |
| }; \ |
| \ |
| enum class ColumnEnumIndex { \ |
| PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_ENUM_INDEX, \ |
| PERFETTO_TP_VIEW_COLUMN_ENUM_INDEX) \ |
| }; \ |
| struct ColumnType { \ |
| PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_TYPE, \ |
| PERFETTO_TP_VIEW_COLUMN_TYPE) \ |
| }; \ |
| struct ColumnDataType { \ |
| PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_DATA_TYPE, \ |
| PERFETTO_TP_VIEW_COLUMN_DATA_TYPE) \ |
| }; \ |
| \ |
| /* Aliases to reduce clutter in class defintions below. */ \ |
| using AbstractRowNumber = \ |
| macros_internal::AbstractRowNumber<QueryResult, RowReference>; \ |
| using AbstractConstRowReference = \ |
| macros_internal::AbstractConstRowReference<QueryResult, RowNumber>; \ |
| using AbstractConstIterator = macros_internal:: \ |
| AbstractConstIterator<Iterator, QueryResult, RowNumber, RowReference>; \ |
| \ |
| public: \ |
| struct ColumnIndex { \ |
| PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_INDEX, \ |
| PERFETTO_TP_VIEW_COLUMN_INDEX) \ |
| }; \ |
| class RowNumber : public AbstractRowNumber { \ |
| public: \ |
| explicit RowNumber(uint32_t row_number) \ |
| : AbstractRowNumber(row_number) {} \ |
| }; \ |
| static_assert(std::is_trivially_destructible<RowNumber>::value, \ |
| "Inheritance used without trivial destruction"); \ |
| \ |
| class RowReference : public AbstractConstRowReference { \ |
| public: \ |
| RowReference(const QueryResult* table, uint32_t row_number) \ |
| : AbstractConstRowReference(table, row_number) {} \ |
| \ |
| PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_ROW_REF_GETTER, \ |
| PERFETTO_TP_VIEW_COLUMN_ROW_REF_GETTER) \ |
| }; \ |
| static_assert(std::is_trivially_destructible<RowReference>::value, \ |
| "Inheritance used without trivial destruction"); \ |
| \ |
| class Iterator : public AbstractConstIterator { \ |
| public: \ |
| PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_IT_GETTER, \ |
| PERFETTO_TP_VIEW_COLUMN_IT_GETTER) \ |
| \ |
| Iterator& operator++() { \ |
| row_number_++; \ |
| return AbstractConstIterator::operator++(); \ |
| } \ |
| \ |
| protected: \ |
| /* \ |
| * Must not be public to avoid buggy code because of inheritance \ |
| * without virtual destructor. \ |
| */ \ |
| explicit Iterator(const QueryResult* table, \ |
| std::vector<ColumnStorageOverlay> overlays) \ |
| : AbstractConstIterator(table, std::move(overlays)) {} \ |
| \ |
| private: \ |
| friend class QueryResult; \ |
| friend class AbstractConstIterator; \ |
| \ |
| uint32_t CurrentRowNumber() const { return row_number_; } \ |
| \ |
| uint32_t row_number_ = 0; \ |
| }; \ |
| \ |
| class QueryResult : public Table { \ |
| public: \ |
| QueryResult(QueryResult&& other) = default; \ |
| QueryResult& operator=(QueryResult&& other) noexcept = default; \ |
| \ |
| ~QueryResult() override; \ |
| \ |
| PERFETTO_TP_VIEW_COLUMNS( \ |
| DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_QUERY_RESULT_GETTER, \ |
| PERFETTO_TP_VIEW_COLUMN_QUERY_RESULT_GETTER) \ |
| \ |
| class_name::Iterator IterateRows() { \ |
| return class_name::Iterator(this, CopyOverlays()); \ |
| } \ |
| \ |
| private: \ |
| friend class class_name; \ |
| \ |
| QueryResult() = default; \ |
| QueryResult(Table&& table) : Table(std::move(table)) {} \ |
| }; \ |
| \ |
| class_name( \ |
| PERFETTO_TP_VIEW_FROM(DEF, PERFETTO_TP_VIEW_CLASS_TABLE_COMMA_FROM) \ |
| PERFETTO_TP_VIEW_JOINS(DEF, \ |
| PERFETTO_TP_VIEW_CLASS_TABLE_COMMA_JOIN) \ |
| std::nullptr_t = nullptr) \ |
| : View(PERFETTO_TP_VIEW_FROM(DEF, PERFETTO_TP_VIEW_FROM_PTR_NAME), \ |
| {PERFETTO_TP_VIEW_JOINS(DEF, PERFETTO_TP_VIEW_JOIN_DEFN)}, \ |
| {PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_DEFN, \ |
| PERFETTO_TP_VIEW_COLUMN_DEFN)}) { \ |
| PERFETTO_TP_VIEW_JOINS(DEF, PERFETTO_TP_VIEW_JOIN_STATIC_ASSERT) \ |
| } \ |
| ~class_name() override; \ |
| \ |
| QueryResult Query(const std::vector<Constraint>& cs, \ |
| const std::vector<Order>& ob, \ |
| const BitVector& cols_used) const { \ |
| QueryResult result; \ |
| new (&result) QueryResult(View::Query(cs, ob, cols_used)); \ |
| return result; \ |
| } \ |
| \ |
| PERFETTO_TP_VIEW_COLUMNS(DEF, \ |
| PERFETTO_TP_VIEW_FROM_COLUMN_BLUEPRINT_GETTER, \ |
| PERFETTO_TP_VIEW_COL_BLUEPRINT_GETTER) \ |
| \ |
| static const char* Name() { return view_name; } \ |
| } |
| |
| } // namespace macros_internal |
| } // namespace trace_processor |
| } // namespace perfetto |
| |
| #endif // SRC_TRACE_PROCESSOR_VIEWS_MACROS_INTERNAL_H_ |