tools: Add proper multi-chip support for idf_size.py
This commit is contained in:
parent
e6a99f0506
commit
1821ee8851
3 changed files with 146 additions and 18 deletions
|
@ -465,7 +465,7 @@ macro(project project_name)
|
||||||
idf_build_get_property(idf_path IDF_PATH)
|
idf_build_get_property(idf_path IDF_PATH)
|
||||||
idf_build_get_property(python PYTHON)
|
idf_build_get_property(python PYTHON)
|
||||||
|
|
||||||
set(idf_size ${python} ${idf_path}/tools/idf_size.py)
|
set(idf_size ${python} ${idf_path}/tools/idf_size.py --target ${IDF_TARGET})
|
||||||
if(DEFINED OUTPUT_JSON AND OUTPUT_JSON)
|
if(DEFINED OUTPUT_JSON AND OUTPUT_JSON)
|
||||||
list(APPEND idf_size "--json")
|
list(APPEND idf_size "--json")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# Includes information which is not shown in "xtensa-esp32-elf-size",
|
# Includes information which is not shown in "xtensa-esp32-elf-size",
|
||||||
# or easy to parse from "xtensa-esp32-elf-objdump" or raw map files.
|
# or easy to parse from "xtensa-esp32-elf-objdump" or raw map files.
|
||||||
#
|
#
|
||||||
# Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
|
# Copyright 2017-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
from future.utils import iteritems
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
import json
|
import json
|
||||||
|
@ -35,6 +36,126 @@ GLOBAL_JSON_INDENT = 4
|
||||||
GLOBAL_JSON_SEPARATORS = (',', ': ')
|
GLOBAL_JSON_SEPARATORS = (',', ': ')
|
||||||
|
|
||||||
|
|
||||||
|
class MemRegions(object):
|
||||||
|
(DRAM_ID, IRAM_ID, DIRAM_ID) = range(3)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_mem_regions(target):
|
||||||
|
# The target specific memory structure is deduced from soc_memory_types defined in
|
||||||
|
# $IDF_PATH/components/soc/**/soc_memory_layout.c files.
|
||||||
|
|
||||||
|
# The order of variables in the tuple is the same as in the soc_memory_layout.c files
|
||||||
|
MemRegDef = collections.namedtuple('MemRegDef', ['primary_addr', 'length', 'type', 'secondary_addr'])
|
||||||
|
|
||||||
|
if target == 'esp32':
|
||||||
|
return sorted([
|
||||||
|
# TODO comment this
|
||||||
|
MemRegDef(0x3FFAE000, 17 * 0x2000 + 2 * 0x8000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFAE000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFB0000, 0x8000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFB8000, 0x8000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFC0000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFC2000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFC4000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFC6000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFC8000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFCA000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFCC000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFCE000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFD0000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFD2000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFD4000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFD6000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFD8000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFDA000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFDC000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
# MemRegDef(0x3FFDE000, 0x2000, MemRegions.DRAM_ID, 0),
|
||||||
|
#
|
||||||
|
MemRegDef(0x3FFE0000, 4 * 0x4000 + 2 * 0x8000, MemRegions.DIRAM_ID, 0x400BC000),
|
||||||
|
# MemRegDef(0x3FFE0000, 0x4000, MemRegions.DIRAM_ID, 0x400BC000),
|
||||||
|
# MemRegDef(0x3FFE4000, 0x4000, MemRegions.DIRAM_ID, 0x400B8000),
|
||||||
|
# MemRegDef(0x3FFE8000, 0x8000, MemRegions.DIRAM_ID, 0x400B0000),
|
||||||
|
# MemRegDef(0x3FFF0000, 0x8000, MemRegions.DIRAM_ID, 0x400A8000),
|
||||||
|
# MemRegDef(0x3FFF8000, 0x4000, MemRegions.DIRAM_ID, 0x400A4000),
|
||||||
|
# MemRegDef(0x3FFFC000, 0x4000, MemRegions.DIRAM_ID, 0x400A0000),
|
||||||
|
#
|
||||||
|
MemRegDef(0x40070000, 2 * 0x8000 + 16 * 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40070000, 0x8000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40078000, 0x8000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40080000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40082000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40084000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40086000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40088000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x4008A000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x4008C000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x4008E000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40090000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40092000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40094000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40096000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x40098000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x4009A000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x4009C000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
# MemRegDef(0x4009E000, 0x2000, MemRegions.IRAM_ID, 0),
|
||||||
|
])
|
||||||
|
elif target == 'esp32s2':
|
||||||
|
return sorted([
|
||||||
|
# The following one memory region is defined instead of defining all 3 + 11 individually because their
|
||||||
|
# type (MemRegions.DIRAM_ID) is the same
|
||||||
|
MemRegDef(0x3FFB2000, 3 * 0x2000 + 11 * 0x4000, MemRegions.DIRAM_ID, 0x40022000),
|
||||||
|
# MemRegDef(0x3FFB2000, 0x2000, MemRegions.DIRAM_ID, 0x40022000),
|
||||||
|
# MemRegDef(0x3FFB4000, 0x2000, MemRegions.DIRAM_ID, 0x40024000),
|
||||||
|
# MemRegDef(0x3FFB6000, 0x2000, MemRegions.DIRAM_ID, 0x40026000),
|
||||||
|
# MemRegDef(0x3FFB8000, 0x4000, MemRegions.DIRAM_ID, 0x40028000),
|
||||||
|
# MemRegDef(0x3FFBC000, 0x4000, MemRegions.DIRAM_ID, 0x4002C000),
|
||||||
|
# MemRegDef(0x3FFC0000, 0x4000, MemRegions.DIRAM_ID, 0x40030000),
|
||||||
|
# MemRegDef(0x3FFC4000, 0x4000, MemRegions.DIRAM_ID, 0x40034000),
|
||||||
|
# MemRegDef(0x3FFC8000, 0x4000, MemRegions.DIRAM_ID, 0x40038000),
|
||||||
|
# MemRegDef(0x3FFCC000, 0x4000, MemRegions.DIRAM_ID, 0x4003C000),
|
||||||
|
# MemRegDef(0x3FFD0000, 0x4000, MemRegions.DIRAM_ID, 0x40040000),
|
||||||
|
# MemRegDef(0x3FFD4000, 0x4000, MemRegions.DIRAM_ID, 0x40044000),
|
||||||
|
# MemRegDef(0x3FFD8000, 0x4000, MemRegions.DIRAM_ID, 0x40048000),
|
||||||
|
# MemRegDef(0x3FFDC000, 0x4000, MemRegions.DIRAM_ID, 0x4004C000),
|
||||||
|
# MemRegDef(0x3FFE0000, 0x4000, MemRegions.DIRAM_ID, 0x40050000),
|
||||||
|
#
|
||||||
|
# 2nd stage bootloader iram_loader_seg starts at block 15. Therefore, the following blocks are not
|
||||||
|
# defined here and will not be counted in the total amount of available space
|
||||||
|
# MemRegDef(0x3FFE4000, 0x4000, MemRegions.DIRAM_ID, 0x40054000),
|
||||||
|
# MemRegDef(0x3FFE8000, 0x4000, MemRegions.DIRAM_ID, 0x40058000),
|
||||||
|
# MemRegDef(0x3FFEC000, 0x4000, MemRegions.DIRAM_ID, 0x4005C000),
|
||||||
|
# MemRegDef(0x3FFF0000, 0x4000, MemRegions.DIRAM_ID, 0x40060000),
|
||||||
|
# MemRegDef(0x3FFF4000, 0x4000, MemRegions.DIRAM_ID, 0x40064000),
|
||||||
|
# MemRegDef(0x3FFF8000, 0x4000, MemRegions.DIRAM_ID, 0x40068000),
|
||||||
|
# MemRegDef(0x3FFFC000, 0x4000, MemRegions.DIRAM_ID, 0x4006C000),
|
||||||
|
# Note the type of the last block which is in contrast with soc_memory_layout.c. It is used for
|
||||||
|
# startup stack therefore the type is D/IRAM (from the perspective of idf_size) and not DRAM.
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __init__(self, target):
|
||||||
|
self.chip_mem_regions = self.get_mem_regions(target)
|
||||||
|
if not self.chip_mem_regions:
|
||||||
|
raise RuntimeError('Target {} is not implemented in idf_size'.format(target))
|
||||||
|
|
||||||
|
def _address_in_range(address, length, reg_address, reg_length):
|
||||||
|
return address >= reg_address and (address - reg_address) <= (reg_length - length)
|
||||||
|
|
||||||
|
def get_names(self, dictionary, region_id):
|
||||||
|
result = []
|
||||||
|
# TODO alebo origin a length
|
||||||
|
for m in self.chip_mem_regions:
|
||||||
|
result.append([n for (n, c) in iteritems(dictionary) if (self._address_in_range(c.address, c.size,
|
||||||
|
m.primary_addr, m.length) or
|
||||||
|
(m.type == self.DIRAM_ID and
|
||||||
|
self._address_in_range(c.address,
|
||||||
|
c.size,
|
||||||
|
m.secondary_addr,
|
||||||
|
m.length)))])
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def scan_to_header(f, header_line):
|
def scan_to_header(f, header_line):
|
||||||
""" Scan forward in a file until you reach 'header_line', then return """
|
""" Scan forward in a file until you reach 'header_line', then return """
|
||||||
for line in f:
|
for line in f:
|
||||||
|
@ -171,9 +292,10 @@ def sizes_by_key(sections, key):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser("idf_size - a tool to print IDF elf file sizes")
|
parser = argparse.ArgumentParser(description="idf_size - a tool to print size information from an IDF MAP file")
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
# FIXME: toolchain is not used
|
||||||
'--toolchain-prefix',
|
'--toolchain-prefix',
|
||||||
help="Triplet prefix to add before objdump executable",
|
help="Triplet prefix to add before objdump executable",
|
||||||
default=DEFAULT_TOOLCHAIN_PREFIX)
|
default=DEFAULT_TOOLCHAIN_PREFIX)
|
||||||
|
@ -196,6 +318,9 @@ def main():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--files', help='Print per-file sizes', action='store_true')
|
'--files', help='Print per-file sizes', action='store_true')
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--target', help='Set target chip', default='esp32')
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-o',
|
'-o',
|
||||||
'--output-file',
|
'--output-file',
|
||||||
|
@ -205,24 +330,26 @@ def main():
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
mem_regions = MemRegions(args.target)
|
||||||
|
|
||||||
output = ""
|
output = ""
|
||||||
|
|
||||||
memory_config, sections = load_map_data(args.map_file)
|
memory_config, sections = load_map_data(args.map_file)
|
||||||
if not args.json or not (args.archives or args.files or args.archive_details):
|
if not args.json or not (args.archives or args.files or args.archive_details):
|
||||||
output += get_summary(memory_config, sections, args.json)
|
output += get_summary(mem_regions, memory_config, sections, args.json)
|
||||||
|
|
||||||
if args.archives:
|
if args.archives:
|
||||||
output += get_detailed_sizes(sections, "archive", "Archive File", args.json)
|
output += get_detailed_sizes(mem_regions, sections, "archive", "Archive File", args.json)
|
||||||
if args.files:
|
if args.files:
|
||||||
output += get_detailed_sizes(sections, "file", "Object File", args.json)
|
output += get_detailed_sizes(mem_regions, sections, "file", "Object File", args.json)
|
||||||
|
|
||||||
if args.archive_details:
|
if args.archive_details:
|
||||||
output += get_archive_symbols(sections, args.archive_details, args.json)
|
output += get_archive_symbols(mem_regions, sections, args.archive_details, args.json)
|
||||||
|
|
||||||
args.output_file.write(output)
|
args.output_file.write(output)
|
||||||
|
|
||||||
|
|
||||||
def get_summary(memory_config, sections, as_json=False):
|
def get_summary(mem_regions, memory_config, sections, as_json=False):
|
||||||
def get_size(section):
|
def get_size(section):
|
||||||
try:
|
try:
|
||||||
return sections[section]["size"]
|
return sections[section]["size"]
|
||||||
|
@ -278,19 +405,20 @@ def get_summary(memory_config, sections, as_json=False):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def get_detailed_sizes(sections, key, header, as_json=False):
|
def get_detailed_sizes(mem_regions, sections, key, header, as_json=False):
|
||||||
sizes = sizes_by_key(sections, key)
|
sizes = sizes_by_key(sections, key)
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
for k in sizes:
|
for k in sizes:
|
||||||
v = sizes[k]
|
v = sizes[k]
|
||||||
result[k] = collections.OrderedDict()
|
r = collections.OrderedDict()
|
||||||
result[k]["data"] = v.get(".dram0.data", 0)
|
r["data"] = v.get(".dram0.data", 0)
|
||||||
result[k]["bss"] = v.get(".dram0.bss", 0)
|
r["bss"] = v.get(".dram0.bss", 0)
|
||||||
result[k]["iram"] = sum(t for (s,t) in v.items() if s.startswith(".iram0"))
|
r["iram"] = sum(t for (s,t) in v.items() if s.startswith(".iram0"))
|
||||||
result[k]["flash_text"] = v.get(".flash.text", 0)
|
r["flash_text"] = v.get(".flash.text", 0)
|
||||||
result[k]["flash_rodata"] = v.get(".flash.rodata", 0)
|
r["flash_rodata"] = v.get(".flash.rodata", 0)
|
||||||
result[k]["total"] = sum(result[k].values())
|
r["total"] = sum(r.values())
|
||||||
|
result[k] = r
|
||||||
|
|
||||||
def return_total_size(elem):
|
def return_total_size(elem):
|
||||||
val = elem[1]
|
val = elem[1]
|
||||||
|
@ -333,7 +461,7 @@ def get_detailed_sizes(sections, key, header, as_json=False):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def get_archive_symbols(sections, archive, as_json=False):
|
def get_archive_symbols(mem_regions, sections, archive, as_json=False):
|
||||||
interested_sections = [".dram0.data", ".dram0.bss", ".iram0.text", ".iram0.vectors", ".flash.text", ".flash.rodata"]
|
interested_sections = [".dram0.data", ".dram0.bss", ".iram0.text", ".iram0.vectors", ".flash.text", ".flash.rodata"]
|
||||||
result = {}
|
result = {}
|
||||||
for t in interested_sections:
|
for t in interested_sections:
|
||||||
|
|
|
@ -40,4 +40,4 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# This used to crash with a division by zero error but now it just prints nan% due to
|
# This used to crash with a division by zero error but now it just prints nan% due to
|
||||||
# zero lengths
|
# zero lengths
|
||||||
print(idf_size.get_summary({"iram0_0_seg": {"length":0}, "dram0_0_seg": {"length":0}}, {}), end="")
|
print(idf_size.get_summary(idf_size.MemRegions('esp32'), {"iram0_0_seg": {"length":0}, "dram0_0_seg": {"length":0}}, {}), end="")
|
||||||
|
|
Loading…
Reference in a new issue