| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- #
- # Copyright (c) 2021 Project CHIP Authors
- #
- # 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.
- #
- """DataFrame utilities."""
- from typing import Dict
- import numpy as np # type: ignore
- import pandas as pd # type: ignore
- class DF(pd.DataFrame): # pylint: disable=too-many-ancestors
- """DataFrame builder with default columns and types."""
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- for c in self.required:
- if c not in self.columns:
- self[c] = pd.Series()
- types = {c: self.dtype[c] for c in self.columns if c in self.dtype}
- typed_columns = list(types.keys())
- self[typed_columns] = self.astype(types, copy=False)[typed_columns]
- self.attrs['name'] = self.name
- class SymbolSourceDF(DF): # pylint: disable=too-many-ancestors
- """Maps symbol to compilation unit"""
- name: str = 'symbolsource'
- required = frozenset(['symbol', 'address', 'cu'])
- dtype = {
- 'symbol': 'string',
- 'address': np.int64,
- 'cu': 'string',
- 'line': np.int64,
- }
- class SegmentDF(DF): # pylint: disable=too-many-ancestors
- """Segment memory map"""
- name: str = 'segment'
- required = frozenset(['type', 'vaddress', 'paddress', 'size'])
- dtype = {
- 'type': 'string',
- 'vaddress': np.int64,
- 'paddress': np.int64,
- 'size': np.int64,
- 'flags': np.int32
- }
- class SectionDF(DF): # pylint: disable=too-many-ancestors
- """Section memory map"""
- name: str = 'section'
- required = frozenset(['section', 'type', 'address', 'size'])
- dtype = {
- 'section': 'string',
- 'type': 'string',
- 'address': np.int64,
- 'size': np.int64,
- 'flags': np.int32,
- 'segment': np.int32,
- }
- class SymbolDF(DF): # pylint: disable=too-many-ancestors
- """Symbol table"""
- name: str = 'symbol'
- required = frozenset(['symbol', 'type', 'address', 'size'])
- dtype = {
- 'symbol': 'string',
- 'type': 'string',
- 'address': np.int64,
- 'size': np.int64,
- 'shndx': 'string'
- }
- class ExtentDF(DF): # pylint: disable=too-many-ancestors
- """Gaps between symbols"""
- name: str = 'gap'
- required = frozenset(['address', 'size', 'section'])
- dtype = {
- 'address': np.int64,
- 'size': np.int64,
- 'section': 'string'
- }
- class StackDF(DF): # pylint: disable=too-many-ancestors
- """Stack usage table"""
- name: str = 'stack'
- required = frozenset(['symbol', 'type', 'size'])
- dtype = {
- 'symbol': 'string',
- 'type': 'string',
- 'size': np.int64,
- 'file': 'string',
- 'line': np.int64,
- }
- def find_class(df: pd.DataFrame):
- """Find a core DF subclass for a data frame.
- Given a arbitrary pandas DataFrame, determine whether it is usable
- as one of the main memory map tables (symbol, section, segment)
- by checking whether the required columns are present.
- """
- if isinstance(df, DF):
- return type(df)
- for c in [SymbolDF, SectionDF, SegmentDF]:
- if c.required.issubset(df.columns):
- return c
- return None
- DFs = Dict[str, DF]
|