blob: 5b3cb92631e44ddba08cb181a5e5c40f0172195a [file] [log] [blame]
# 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.
from typing import List
from typing import Optional
from python.generators.trace_processor_table.public import Alias
from python.generators.trace_processor_table.public import Column
from python.generators.trace_processor_table.public import ColumnFlag
from python.generators.trace_processor_table.public import Table
from python.generators.trace_processor_table.util import parse_type
from python.generators.trace_processor_table.util import typed_column_type
from python.generators.trace_processor_table.util import to_cpp_flags
class ColumnSerializer:
"""Functions for serializing a single Column in a table into C++."""
def __init__(self, table: Table, col_index: int):
self.col_index = col_index
self.col = table.columns[col_index]
self.name = self.col.name
self.flags = self.col.flags
self.typed_column_type = typed_column_type(table, self.col)
self.cpp_type = parse_type(table, self.col.type).cpp_type_with_optionality()
def colindex(self) -> str:
return f' static constexpr uint32_t {self.name} = {self.col_index};'
def coltype_enum(self) -> str:
return f' using {self.name} = {self.typed_column_type};'
def row_field(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
return f' {self.cpp_type} {self.name};'
def row_param(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
return f'{self.cpp_type} in_{self.name} = {{}}'
def row_initializer(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
return f'{self.name}(std::move(in_{self.name}))'
def const_row_ref_getter(self) -> Optional[str]:
return f'''ColumnType::{self.name}::type {self.name}() const {{
return table_->{self.name}()[row_number_];
}}'''
def row_ref_getter(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
return f'''void set_{self.name}(
ColumnType::{self.name}::non_optional_type v) {{
return mutable_table()->mutable_{self.name}()->Set(row_number_, v);
}}'''
def flag(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
default = f'ColumnType::{self.name}::default_flags()'
if self.flags == ColumnFlag.NONE:
flags = default
else:
flags = f'static_cast<uint32_t>({to_cpp_flags(self.flags)}) | {default}'
return f'''
static constexpr uint32_t {self.name} = {flags};
'''
def storage_init(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
storage = f'ColumnStorage<ColumnType::{self.name}::stored_type>'
# TODO(lalitm): add support for dense columns.
return f'''{self.name}_({storage}::Create<false>())'''
def column_init(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
return f'''
columns_.emplace_back("{self.name}", &{self.name}_, ColumnFlag::{self.name},
this, static_cast<uint32_t>(columns_.size()),
overlay_count);
'''
def shrink_to_fit(self) -> Optional[str]:
if self.col._is_auto_added_id:
return None
return f' {self.name}_.ShrinkToFit();'
def append(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
return f' mutable_{self.name}()->Append(std::move(row.{self.name}));'
def accessor(self) -> Optional[str]:
inner = f'columns_[ColumnIndex::{self.name}]'
return f'''
const {self.typed_column_type}& {self.name}() const {{
return static_cast<const ColumnType::{self.name}&>({inner});
}}
'''
def mutable_accessor(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
return f'''
{self.typed_column_type}* mutable_{self.name}() {{
return static_cast<ColumnType::{self.name}*>(
&columns_[ColumnIndex::{self.name}]);
}}
'''
def storage(self) -> Optional[str]:
if self.col._is_auto_added_id or self.col._is_auto_added_type:
return None
name = self.name
return f' ColumnStorage<ColumnType::{name}::stored_type> {name}_;'
class TableSerializer(object):
"""Functions for seralizing a single Table into C++."""
def __init__(self, table: Table):
self.table = table
self.table_name = table.class_name
self.column_serializers = [
ColumnSerializer(table, i) for i in range(len(table.columns))
]
def foreach_col(self, serialize_fn, delimiter='\n') -> str:
lines = []
for c in self.column_serializers:
serialized = serialize_fn(c)
if serialized:
lines.append(serialized.lstrip('\n').rstrip())
return delimiter.join(lines).strip()
def id_defn(self) -> str:
return '''
struct Id : public BaseId {
Id() = default;
explicit constexpr Id(uint32_t v) : BaseId(v) {}
};
static_assert(std::is_trivially_destructible<Id>::value,
"Inheritance used without trivial destruction");
'''
def row_struct(self) -> str:
param = self.foreach_col(
ColumnSerializer.row_param, delimiter=',\n ')
row_init = self.foreach_col(
ColumnSerializer.row_initializer, delimiter=',\n ')
return f'''
struct Row : public macros_internal::RootParentTable::Row {{
Row({param},
std::nullptr_t = nullptr)
: macros_internal::RootParentTable::Row(nullptr),
{row_init} {{
type_ = "{self.table.sql_name}";
}}
{self.foreach_col(ColumnSerializer.row_field)}
}};
'''
def const_row_reference_struct(self) -> str:
row_ref_getters = self.foreach_col(
ColumnSerializer.const_row_ref_getter, delimiter='\n ')
return f'''
class ConstRowReference : public macros_internal::AbstractConstRowReference<
{self.table_name}, RowNumber> {{
public:
ConstRowReference(const {self.table_name}* table, uint32_t row_number)
: AbstractConstRowReference(table, row_number) {{}}
{row_ref_getters}
}};
static_assert(std::is_trivially_destructible<ConstRowReference>::value,
"Inheritance used without trivial destruction");
'''
def row_reference_struct(self) -> str:
row_ref_getters = self.foreach_col(
ColumnSerializer.row_ref_getter, delimiter='\n ')
return f'''
class RowReference : public ConstRowReference {{
public:
RowReference(const {self.table_name}* table, uint32_t row_number)
: ConstRowReference(table, row_number) {{}}
{row_ref_getters}
private:
{self.table_name}* mutable_table() const {{
return const_cast<{self.table_name}*>(table_);
}}
}};
static_assert(std::is_trivially_destructible<RowReference>::value,
"Inheritance used without trivial destruction");
'''
def constructor(self) -> str:
col_init = self.foreach_col(
ColumnSerializer.storage_init, delimiter=',\n ')
return f'''
explicit {self.table_name}(StringPool* pool)
: macros_internal::MacroTable(pool, nullptr),
{col_init} {{
uint32_t overlay_count = static_cast<uint32_t>(overlays_.size()) - 1;
{self.foreach_col(ColumnSerializer.column_init)}
}}
'''
def serialize(self) -> str:
return f'''
class {self.table_name} : public macros_internal::MacroTable {{
public:
{self.id_defn().lstrip()}
struct ColumnIndex {{
{self.foreach_col(ColumnSerializer.colindex)}
}};
struct ColumnType {{
{self.foreach_col(ColumnSerializer.coltype_enum)}
}};
{self.row_struct().strip()}
struct IdAndRow {{
uint32_t row;
Id id;
}};
struct ColumnFlag {{
{self.foreach_col(ColumnSerializer.flag)}
}};
class RowNumber;
class ConstRowReference;
class RowReference;
class RowNumber : public macros_internal::AbstractRowNumber<
{self.table_name}, ConstRowReference, RowReference> {{
public:
explicit RowNumber(uint32_t row_number)
: AbstractRowNumber(row_number) {{}}
}};
static_assert(std::is_trivially_destructible<RowNumber>::value,
"Inheritance used without trivial destruction");
{self.const_row_reference_struct().strip()}
{self.row_reference_struct().strip()}
{self.constructor().strip()}
~{self.table_name}() override;
static const char* Name() {{ return "{self.table.sql_name}"; }}
void ShrinkToFit() {{
{self.foreach_col(ColumnSerializer.shrink_to_fit)}
}}
base::Optional<ConstRowReference> FindById(Id find_id) const {{
base::Optional<uint32_t> row = id().IndexOf(find_id);
if (!row)
return base::nullopt;
return ConstRowReference(this, *row);
}}
base::Optional<RowReference> FindById(Id find_id) {{
base::Optional<uint32_t> row = id().IndexOf(find_id);
if (!row)
return base::nullopt;
return RowReference(this, *row);
}}
IdAndRow Insert(const Row& row) {{
uint32_t row_number = row_count();
type_.Append(string_pool_->InternString(row.type()));
{self.foreach_col(ColumnSerializer.append)}
UpdateSelfOverlayAfterInsert();
return IdAndRow{{row_number, Id{{row_number}}}};
}}
{self.foreach_col(ColumnSerializer.accessor)}
{self.foreach_col(ColumnSerializer.mutable_accessor)}
private:
{self.foreach_col(ColumnSerializer.storage)}
}};
'''.strip('\n')
def serialize_header(ifdef_guard: str, tables: List[Table],
include_paths: List[str]) -> str:
"""Serializes a table header file containing the given set of tables."""
include_paths_str = '\n'.join([f'#include "{i}"' for i in include_paths])
tables_str = '\n\n'.join([TableSerializer(t).serialize() for t in tables])
return f'''
#ifndef {ifdef_guard}
#define {ifdef_guard}
#include "src/trace_processor/tables/macros.h"
{include_paths_str}
namespace perfetto {{
namespace trace_processor {{
namespace tables {{
{tables_str.strip()}
}} // namespace tables
}} // namespace trace_processor
}} // namespace perfetto
#endif // {ifdef_guard}
'''.strip()