blob: 30d3bb2918aa591bdd673651f4c1584ae1149b80 [file] [log] [blame]
# Copyright 2022 The Pigweed 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
#
# https://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.
"""Size reporting utilities."""
import argparse
import logging
from pathlib import Path
import sys
from typing import Iterable
from pw_bloat import bloat
from pw_bloat.label import DataSourceMap
from pw_bloat.label_output import BloatTableOutput
import pw_cli.log
_LOG = logging.getLogger(__name__)
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'binary',
help='Path to the ELF file to analyze',
metavar='BINARY',
type=Path,
)
parser.add_argument(
'-d',
'--data-sources',
help='Comma-separated list of Bloaty data sources to report',
type=lambda s: s.split(','),
default=('memoryregions,sections'),
)
parser.add_argument(
'--diff',
metavar='BINARY',
help='Run a size diff against a base binary file',
type=Path,
)
parser.add_argument(
'-v',
'--verbose',
help=('Print all log messages ' '(only errors are printed by default)'),
action='store_true',
)
return parser.parse_args()
def _run_size_report(
elf: Path, data_sources: Iterable[str] = ()
) -> DataSourceMap:
"""Runs a size analysis on an ELF file, returning a pw_bloat size map.
Returns:
A size map of the labels in the binary under the provided data sources.
Raises:
NoMemoryRegions: The binary does not define bloat memory region symbols.
"""
bloaty_tsv = bloat.memory_regions_size_report(
elf, data_sources=data_sources, extra_args=('--tsv',)
)
return DataSourceMap.from_bloaty_tsv(bloaty_tsv)
def _no_memory_regions_error(elf: Path) -> None:
_LOG.error('Executable %s does not define any bloat memory regions', elf)
_LOG.error(
'Refer to https://pigweed.dev/pw_bloat/#memoryregions-data-source'
)
_LOG.error('for information on how to configure them.')
def _single_binary_report(elf: Path, data_sources: Iterable[str] = ()) -> int:
try:
data_source_map = _run_size_report(elf, data_sources)
except bloat.NoMemoryRegions:
_no_memory_regions_error(elf)
return 1
print(BloatTableOutput(data_source_map).create_table())
return 0
def _diff_report(
target: Path, base: Path, data_sources: Iterable[str] = ()
) -> int:
try:
base_map = _run_size_report(base, data_sources)
target_map = _run_size_report(target, data_sources)
except bloat.NoMemoryRegions as err:
_no_memory_regions_error(err.elf)
return 1
diff = target_map.diff(base_map)
print(BloatTableOutput(diff).create_table())
return 0
def main() -> int:
"""Run binary size reports."""
args = _parse_args()
if not args.verbose:
pw_cli.log.set_all_loggers_minimum_level(logging.ERROR)
if args.diff is not None:
return _diff_report(
args.binary, args.diff, data_sources=args.data_sources
)
return _single_binary_report(args.binary, data_sources=args.data_sources)
if __name__ == '__main__':
sys.exit(main())