blob: 43ca5cdee7658bc33627eea64d59689a616822f9 [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 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})
: macros_internal::RootParentTable::Row(nullptr),
{row_init} {{
type_ = "{self.table.sql_name}";
}}
{self.foreach_col(ColumnSerializer.row_field)}
}};
'''
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;
}};
struct ColumnFlag {{
{self.foreach_col(ColumnSerializer.flag)}
}};
{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)}
}}
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}};
}}
{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()