mirror of
https://github.com/esphome/esphome.git
synced 2025-10-22 11:43:51 +01:00
merge
This commit is contained in:
@@ -13,6 +13,7 @@ from .const import (
|
|||||||
CORE_SUBCATEGORY_PATTERNS,
|
CORE_SUBCATEGORY_PATTERNS,
|
||||||
DEMANGLED_PATTERNS,
|
DEMANGLED_PATTERNS,
|
||||||
ESPHOME_COMPONENT_PATTERN,
|
ESPHOME_COMPONENT_PATTERN,
|
||||||
|
SECTION_TO_ATTR,
|
||||||
SYMBOL_PATTERNS,
|
SYMBOL_PATTERNS,
|
||||||
)
|
)
|
||||||
from .helpers import map_section_name, parse_symbol_line
|
from .helpers import map_section_name, parse_symbol_line
|
||||||
@@ -219,14 +220,9 @@ class MemoryAnalyzer:
|
|||||||
comp_mem = self.components[component]
|
comp_mem = self.components[component]
|
||||||
comp_mem.symbol_count += 1
|
comp_mem.symbol_count += 1
|
||||||
|
|
||||||
if section_name == ".text":
|
# Update the appropriate size attribute based on section
|
||||||
comp_mem.text_size += size
|
if attr_name := SECTION_TO_ATTR.get(section_name):
|
||||||
elif section_name == ".rodata":
|
setattr(comp_mem, attr_name, getattr(comp_mem, attr_name) + size)
|
||||||
comp_mem.rodata_size += size
|
|
||||||
elif section_name == ".data":
|
|
||||||
comp_mem.data_size += size
|
|
||||||
elif section_name == ".bss":
|
|
||||||
comp_mem.bss_size += size
|
|
||||||
|
|
||||||
# Track uncategorized symbols
|
# Track uncategorized symbols
|
||||||
if component == "other" and size > 0:
|
if component == "other" and size > 0:
|
||||||
|
@@ -10,37 +10,24 @@ from . import MemoryAnalyzer
|
|||||||
class MemoryAnalyzerCLI(MemoryAnalyzer):
|
class MemoryAnalyzerCLI(MemoryAnalyzer):
|
||||||
"""Memory analyzer with CLI-specific report generation."""
|
"""Memory analyzer with CLI-specific report generation."""
|
||||||
|
|
||||||
def generate_report(self, detailed: bool = False) -> str:
|
|
||||||
"""Generate a formatted memory report."""
|
|
||||||
components = sorted(
|
|
||||||
self.components.items(), key=lambda x: x[1].flash_total, reverse=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Calculate totals
|
|
||||||
total_flash = sum(c.flash_total for _, c in components)
|
|
||||||
total_ram = sum(c.ram_total for _, c in components)
|
|
||||||
|
|
||||||
# Build report
|
|
||||||
lines = []
|
|
||||||
|
|
||||||
# Column width constants
|
# Column width constants
|
||||||
COL_COMPONENT = 29
|
COL_COMPONENT: int = 29
|
||||||
COL_FLASH_TEXT = 14
|
COL_FLASH_TEXT: int = 14
|
||||||
COL_FLASH_DATA = 14
|
COL_FLASH_DATA: int = 14
|
||||||
COL_RAM_DATA = 12
|
COL_RAM_DATA: int = 12
|
||||||
COL_RAM_BSS = 12
|
COL_RAM_BSS: int = 12
|
||||||
COL_TOTAL_FLASH = 15
|
COL_TOTAL_FLASH: int = 15
|
||||||
COL_TOTAL_RAM = 12
|
COL_TOTAL_RAM: int = 12
|
||||||
COL_SEPARATOR = 3 # " | "
|
COL_SEPARATOR: int = 3 # " | "
|
||||||
|
|
||||||
# Core analysis column widths
|
# Core analysis column widths
|
||||||
COL_CORE_SUBCATEGORY = 30
|
COL_CORE_SUBCATEGORY: int = 30
|
||||||
COL_CORE_SIZE = 12
|
COL_CORE_SIZE: int = 12
|
||||||
COL_CORE_COUNT = 6
|
COL_CORE_COUNT: int = 6
|
||||||
COL_CORE_PERCENT = 10
|
COL_CORE_PERCENT: int = 10
|
||||||
|
|
||||||
# Calculate the exact table width
|
# Calculate table width once at class level
|
||||||
table_width = (
|
TABLE_WIDTH: int = (
|
||||||
COL_COMPONENT
|
COL_COMPONENT
|
||||||
+ COL_SEPARATOR
|
+ COL_SEPARATOR
|
||||||
+ COL_FLASH_TEXT
|
+ COL_FLASH_TEXT
|
||||||
@@ -56,59 +43,74 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
+ COL_TOTAL_RAM
|
+ COL_TOTAL_RAM
|
||||||
)
|
)
|
||||||
|
|
||||||
lines.append("=" * table_width)
|
@staticmethod
|
||||||
lines.append("Component Memory Analysis".center(table_width))
|
def _make_separator_line(*widths: int) -> str:
|
||||||
lines.append("=" * table_width)
|
"""Create a separator line with given column widths.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
widths: Column widths to create separators for
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Separator line like "----+---------+-----"
|
||||||
|
"""
|
||||||
|
return "-+-".join("-" * width for width in widths)
|
||||||
|
|
||||||
|
# Pre-computed separator lines
|
||||||
|
MAIN_TABLE_SEPARATOR: str = _make_separator_line(
|
||||||
|
COL_COMPONENT,
|
||||||
|
COL_FLASH_TEXT,
|
||||||
|
COL_FLASH_DATA,
|
||||||
|
COL_RAM_DATA,
|
||||||
|
COL_RAM_BSS,
|
||||||
|
COL_TOTAL_FLASH,
|
||||||
|
COL_TOTAL_RAM,
|
||||||
|
)
|
||||||
|
|
||||||
|
CORE_TABLE_SEPARATOR: str = _make_separator_line(
|
||||||
|
COL_CORE_SUBCATEGORY,
|
||||||
|
COL_CORE_SIZE,
|
||||||
|
COL_CORE_COUNT,
|
||||||
|
COL_CORE_PERCENT,
|
||||||
|
)
|
||||||
|
|
||||||
|
def generate_report(self, detailed: bool = False) -> str:
|
||||||
|
"""Generate a formatted memory report."""
|
||||||
|
components = sorted(
|
||||||
|
self.components.items(), key=lambda x: x[1].flash_total, reverse=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Calculate totals
|
||||||
|
total_flash = sum(c.flash_total for _, c in components)
|
||||||
|
total_ram = sum(c.ram_total for _, c in components)
|
||||||
|
|
||||||
|
# Build report
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
|
lines.append("Component Memory Analysis".center(self.TABLE_WIDTH))
|
||||||
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
# Main table - fixed column widths
|
# Main table - fixed column widths
|
||||||
lines.append(
|
lines.append(
|
||||||
f"{'Component':<{COL_COMPONENT}} | {'Flash (text)':>{COL_FLASH_TEXT}} | {'Flash (data)':>{COL_FLASH_DATA}} | {'RAM (data)':>{COL_RAM_DATA}} | {'RAM (bss)':>{COL_RAM_BSS}} | {'Total Flash':>{COL_TOTAL_FLASH}} | {'Total RAM':>{COL_TOTAL_RAM}}"
|
f"{'Component':<{self.COL_COMPONENT}} | {'Flash (text)':>{self.COL_FLASH_TEXT}} | {'Flash (data)':>{self.COL_FLASH_DATA}} | {'RAM (data)':>{self.COL_RAM_DATA}} | {'RAM (bss)':>{self.COL_RAM_BSS}} | {'Total Flash':>{self.COL_TOTAL_FLASH}} | {'Total RAM':>{self.COL_TOTAL_RAM}}"
|
||||||
)
|
|
||||||
lines.append(
|
|
||||||
"-" * COL_COMPONENT
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_FLASH_TEXT
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_FLASH_DATA
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_RAM_DATA
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_RAM_BSS
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_TOTAL_FLASH
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_TOTAL_RAM
|
|
||||||
)
|
)
|
||||||
|
lines.append(self.MAIN_TABLE_SEPARATOR)
|
||||||
|
|
||||||
for name, mem in components:
|
for name, mem in components:
|
||||||
if mem.flash_total > 0 or mem.ram_total > 0:
|
if mem.flash_total > 0 or mem.ram_total > 0:
|
||||||
flash_rodata = mem.rodata_size + mem.data_size
|
flash_rodata = mem.rodata_size + mem.data_size
|
||||||
lines.append(
|
lines.append(
|
||||||
f"{name:<{COL_COMPONENT}} | {mem.text_size:>{COL_FLASH_TEXT - 2},} B | {flash_rodata:>{COL_FLASH_DATA - 2},} B | "
|
f"{name:<{self.COL_COMPONENT}} | {mem.text_size:>{self.COL_FLASH_TEXT - 2},} B | {flash_rodata:>{self.COL_FLASH_DATA - 2},} B | "
|
||||||
f"{mem.data_size:>{COL_RAM_DATA - 2},} B | {mem.bss_size:>{COL_RAM_BSS - 2},} B | "
|
f"{mem.data_size:>{self.COL_RAM_DATA - 2},} B | {mem.bss_size:>{self.COL_RAM_BSS - 2},} B | "
|
||||||
f"{mem.flash_total:>{COL_TOTAL_FLASH - 2},} B | {mem.ram_total:>{COL_TOTAL_RAM - 2},} B"
|
f"{mem.flash_total:>{self.COL_TOTAL_FLASH - 2},} B | {mem.ram_total:>{self.COL_TOTAL_RAM - 2},} B"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
lines.append(self.MAIN_TABLE_SEPARATOR)
|
||||||
lines.append(
|
lines.append(
|
||||||
"-" * COL_COMPONENT
|
f"{'TOTAL':<{self.COL_COMPONENT}} | {' ':>{self.COL_FLASH_TEXT}} | {' ':>{self.COL_FLASH_DATA}} | "
|
||||||
+ "-+-"
|
f"{' ':>{self.COL_RAM_DATA}} | {' ':>{self.COL_RAM_BSS}} | "
|
||||||
+ "-" * COL_FLASH_TEXT
|
f"{total_flash:>{self.COL_TOTAL_FLASH - 2},} B | {total_ram:>{self.COL_TOTAL_RAM - 2},} B"
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_FLASH_DATA
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_RAM_DATA
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_RAM_BSS
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_TOTAL_FLASH
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_TOTAL_RAM
|
|
||||||
)
|
|
||||||
lines.append(
|
|
||||||
f"{'TOTAL':<{COL_COMPONENT}} | {' ':>{COL_FLASH_TEXT}} | {' ':>{COL_FLASH_DATA}} | "
|
|
||||||
f"{' ':>{COL_RAM_DATA}} | {' ':>{COL_RAM_BSS}} | "
|
|
||||||
f"{total_flash:>{COL_TOTAL_FLASH - 2},} B | {total_ram:>{COL_TOTAL_RAM - 2},} B"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Top consumers
|
# Top consumers
|
||||||
@@ -137,14 +139,14 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
lines.append(
|
lines.append(
|
||||||
"Note: This analysis covers symbols in the ELF file. Some runtime allocations may not be included."
|
"Note: This analysis covers symbols in the ELF file. Some runtime allocations may not be included."
|
||||||
)
|
)
|
||||||
lines.append("=" * table_width)
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
|
|
||||||
# Add ESPHome core detailed analysis if there are core symbols
|
# Add ESPHome core detailed analysis if there are core symbols
|
||||||
if self._esphome_core_symbols:
|
if self._esphome_core_symbols:
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append("=" * table_width)
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
lines.append("[esphome]core Detailed Analysis".center(table_width))
|
lines.append("[esphome]core Detailed Analysis".center(self.TABLE_WIDTH))
|
||||||
lines.append("=" * table_width)
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
# Group core symbols by subcategory
|
# Group core symbols by subcategory
|
||||||
@@ -168,26 +170,18 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
lines.append(
|
lines.append(
|
||||||
f"{'Subcategory':<{COL_CORE_SUBCATEGORY}} | {'Size':>{COL_CORE_SIZE}} | "
|
f"{'Subcategory':<{self.COL_CORE_SUBCATEGORY}} | {'Size':>{self.COL_CORE_SIZE}} | "
|
||||||
f"{'Count':>{COL_CORE_COUNT}} | {'% of Core':>{COL_CORE_PERCENT}}"
|
f"{'Count':>{self.COL_CORE_COUNT}} | {'% of Core':>{self.COL_CORE_PERCENT}}"
|
||||||
)
|
|
||||||
lines.append(
|
|
||||||
"-" * COL_CORE_SUBCATEGORY
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_CORE_SIZE
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_CORE_COUNT
|
|
||||||
+ "-+-"
|
|
||||||
+ "-" * COL_CORE_PERCENT
|
|
||||||
)
|
)
|
||||||
|
lines.append(self.CORE_TABLE_SEPARATOR)
|
||||||
|
|
||||||
core_total = sum(size for _, _, size in self._esphome_core_symbols)
|
core_total = sum(size for _, _, size in self._esphome_core_symbols)
|
||||||
|
|
||||||
for subcategory, symbols, total_size in sorted_subcategories:
|
for subcategory, symbols, total_size in sorted_subcategories:
|
||||||
percentage = (total_size / core_total * 100) if core_total > 0 else 0
|
percentage = (total_size / core_total * 100) if core_total > 0 else 0
|
||||||
lines.append(
|
lines.append(
|
||||||
f"{subcategory:<{COL_CORE_SUBCATEGORY}} | {total_size:>{COL_CORE_SIZE - 2},} B | "
|
f"{subcategory:<{self.COL_CORE_SUBCATEGORY}} | {total_size:>{self.COL_CORE_SIZE - 2},} B | "
|
||||||
f"{len(symbols):>{COL_CORE_COUNT}} | {percentage:>{COL_CORE_PERCENT - 1}.1f}%"
|
f"{len(symbols):>{self.COL_CORE_COUNT}} | {percentage:>{self.COL_CORE_PERCENT - 1}.1f}%"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Top 10 largest core symbols
|
# Top 10 largest core symbols
|
||||||
@@ -200,7 +194,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
for i, (symbol, demangled, size) in enumerate(sorted_core_symbols[:15]):
|
for i, (symbol, demangled, size) in enumerate(sorted_core_symbols[:15]):
|
||||||
lines.append(f"{i + 1}. {demangled} ({size:,} B)")
|
lines.append(f"{i + 1}. {demangled} ({size:,} B)")
|
||||||
|
|
||||||
lines.append("=" * table_width)
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
|
|
||||||
# Add detailed analysis for top ESPHome and external components
|
# Add detailed analysis for top ESPHome and external components
|
||||||
esphome_components = [
|
esphome_components = [
|
||||||
@@ -240,9 +234,11 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
comp_symbols = self._component_symbols.get(comp_name, [])
|
comp_symbols = self._component_symbols.get(comp_name, [])
|
||||||
if comp_symbols:
|
if comp_symbols:
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append("=" * table_width)
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
lines.append(f"{comp_name} Detailed Analysis".center(table_width))
|
lines.append(
|
||||||
lines.append("=" * table_width)
|
f"{comp_name} Detailed Analysis".center(self.TABLE_WIDTH)
|
||||||
|
)
|
||||||
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
# Sort symbols by size
|
# Sort symbols by size
|
||||||
@@ -267,7 +263,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
for i, (symbol, demangled, size) in enumerate(large_symbols):
|
for i, (symbol, demangled, size) in enumerate(large_symbols):
|
||||||
lines.append(f"{i + 1}. {demangled} ({size:,} B)")
|
lines.append(f"{i + 1}. {demangled} ({size:,} B)")
|
||||||
|
|
||||||
lines.append("=" * table_width)
|
lines.append("=" * self.TABLE_WIDTH)
|
||||||
|
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
@@ -14,6 +14,15 @@ SECTION_MAPPING = {
|
|||||||
".bss": frozenset([".bss"]),
|
".bss": frozenset([".bss"]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Section to ComponentMemory attribute mapping
|
||||||
|
# Maps section names to the attribute name in ComponentMemory dataclass
|
||||||
|
SECTION_TO_ATTR = {
|
||||||
|
".text": "text_size",
|
||||||
|
".rodata": "rodata_size",
|
||||||
|
".data": "data_size",
|
||||||
|
".bss": "bss_size",
|
||||||
|
}
|
||||||
|
|
||||||
# Component identification rules
|
# Component identification rules
|
||||||
# Symbol patterns: patterns found in raw symbol names
|
# Symbol patterns: patterns found in raw symbol names
|
||||||
SYMBOL_PATTERNS = {
|
SYMBOL_PATTERNS = {
|
||||||
|
Reference in New Issue
Block a user