import datetime
import logging
import os
import pathlib
import sys
import memdf.collect
import memdf.report
import memdf.select
import memdf.util
from memdf import Config, ConfigDescription, DFs, SectionDF
PLATFORM_CONFIG_DIR = pathlib.Path('scripts/tools/memory/platform')
CONFIG: ConfigDescription = {
'event': {
'help': 'Github workflow event name',
'metavar': 'NAME',
'default': os.environ.get('GITHUB_EVENT_NAME'),
},
'pr': {
'help': 'Github PR number',
'metavar': 'NUMBER',
'default': int(os.environ.get('GH_EVENT_PR', '0')),
},
'hash': {
'help': 'Current commit hash',
'metavar': 'HASH',
'default': os.environ.get('GH_EVENT_HASH'),
},
'parent': {
'help': 'Parent commit hash',
'metavar': 'HASH',
'default': os.environ.get('GH_EVENT_PARENT'),
},
'ref': {
'help': 'Target ref',
'metavar': 'REF',
'default': os.environ.get('GH_EVENT_REF'),
},
'timestamp': {
'help': 'Build timestamp',
'metavar': 'TIME',
'default': int(float(
os.environ.get('GH_EVENT_TIMESTAMP')
or datetime.datetime.now().timestamp())),
},
}
def main(argv):
status = 0
try:
_, platform, config_name, target_name, binary, *args = argv
except ValueError:
program = pathlib.Path(argv[0])
logging.error(
"""
Usage: %s platform config target binary [output] [options]
This is intended for use in github workflows.
For other purposes, a general program for the same operations is
%s/report_summary.py
""", program.name, program.parent)
return 1
try:
config_file = pathlib.Path(platform)
if config_file.is_file():
platform = config_file.stem
else:
config_file = (PLATFORM_CONFIG_DIR / platform).with_suffix('.cfg')
output_base = f'{platform}-{config_name}-{target_name}-sizes.json'
if args and not args[0].startswith('-'):
out, *args = args
output = pathlib.Path(out)
if out.endswith('/') and not output.exists():
output.mkdir(parents=True)
if output.is_dir():
output = output / output_base
else:
output = pathlib.Path(binary).parent / output_base
config_desc = {
**memdf.util.config.CONFIG,
**memdf.collect.CONFIG,
**memdf.select.CONFIG,
**memdf.report.OUTPUT_CONFIG,
**CONFIG,
}
config_desc['section.select']['default'] = [
'.text', '.rodata', '.data', '.bss']
config = Config().init(config_desc)
config.put('output.file', output)
config.put('output.format', 'json_records')
if config_file.is_file():
config.read_config_file(config_file)
else:
logging.warning('Missing config file: %s', config_file)
config.parse([argv[0]] + args)
config.put('output.metadata.platform', platform)
config.put('output.metadata.config', config_name)
config.put('output.metadata.target', target_name)
config.put('output.metadata.time', config['timestamp'])
config.put('output.metadata.input', binary)
config.put('output.metadata.by', 'section')
for key in ['event', 'hash', 'parent', 'pr', 'ref']:
if value := config[key]:
config.putl(['output', 'metadata', key], value)
if not config.get('region.sections'):
sections = {'FLASH': [], 'RAM': []}
for section in config.get('section.select'):
print('section:', section)
for substring, region in [('text', 'FLASH'), ('rodata', 'FLASH'), ('data', 'RAM'), ('bss', 'RAM')]:
if substring in section:
sections[region].append(section)
break
config.put('region.sections', sections)
collected: DFs = memdf.collect.collect_files(config, [binary])
sections = collected[SectionDF.name]
section_summary = sections[['section',
'size']].sort_values(by='section')
section_summary.attrs['name'] = "section"
region_summary = memdf.select.groupby(
config, collected['section'], 'region')
region_summary.attrs['name'] = "region"
summaries = {
'section': section_summary,
'region': region_summary,
}
memdf.report.write_dfs(config, summaries)
memdf.report.write_dfs(config,
summaries,
sys.stdout,
'simple',
floatfmt='.0f')
except Exception as exception:
raise exception
return status
if __name__ == '__main__':
sys.exit(main(sys.argv))