1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-21 10:26:06 +03:00

Table output for segment size script (#8551)

* Table output for segment size script
Also include maximum aka total for every segment key
Re-format the file and clean-up the resulting data dict
* revert to line output
* used, percentage
* unicodes
* shorter desc, headers
This commit is contained in:
Max Prokhorov 2022-05-12 00:25:39 +03:00 committed by GitHub
parent 8d5dda02f6
commit da4a19fdac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -17,74 +17,156 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import print_function
import argparse import argparse
import os import os
import subprocess import subprocess
import sys
def get_segment_hints(iram):
hints = {}
hints['ICACHE'] = ' - flash instruction cache'
hints['IROM'] = ' - code in flash (default or ICACHE_FLASH_ATTR)'
hints['IRAM'] = ' / ' + str(iram) + ' - code in IRAM (IRAM_ATTR, ISRs...)'
hints['DATA'] = ') - initialized variables (global, static) in RAM/HEAP'
hints['RODATA'] = ') / 81920 - constants (global, static) in RAM/HEAP'
hints['BSS'] = ') - zeroed variables (global, static) in RAM/HEAP'
return hints
def get_segment_sizes(elf, path): def get_segment_sizes(elf, path, mmu):
sizes = {} iram_size = 0
sizes['ICACHE'] = 0 iheap_size = 0
sizes['IROM'] = 0 icache_size = 32168
sizes['IRAM'] = 0
sizes['DATA'] = 0 for line in mmu.split():
sizes['RODATA'] = 0 words = line.split("=")
sizes['BSS'] = 0 if line.startswith("-DMMU_IRAM_SIZE"):
p = subprocess.Popen([path + "/xtensa-lx106-elf-size", '-A', elf], stdout=subprocess.PIPE, universal_newlines=True ) iram_size = int(words[1], 16)
lines = p.stdout.readlines() elif line.startswith("-DMMU_ICACHE_SIZE"):
for line in lines: icache_size = int(words[1], 16)
words = line.split() elif line.startswith("-DMMU_SEC_HEAP_SIZE"):
if line.startswith('.irom0.text'): iheap_size = int(words[1], 16)
sizes['IROM'] = sizes['IROM'] + int(words[1])
elif line.startswith('.text'): # Gets .text and .text1 sizes = [
sizes['IRAM'] = sizes['IRAM'] + int(words[1]) [
elif line.startswith('.data'): # Gets .text and .text1 "Variables and constants in RAM (global, static)",
sizes['DATA'] = sizes['DATA'] + int(words[1]) [
elif line.startswith('.rodata'): # Gets .text and .text1 {
sizes['RODATA'] = sizes['RODATA'] + int(words[1]) "DATA": 0,
elif line.startswith('.bss'): # Gets .text and .text1 "RODATA": 0,
sizes['BSS'] = sizes['BSS'] + int(words[1]) "BSS": 0,
},
80192,
],
],
[
"Instruction RAM (IRAM_ATTR, ICACHE_RAM_ATTR)",
[
{
"ICACHE": icache_size,
"IHEAP": iheap_size,
"IRAM": 0,
},
65536,
],
],
["Code in flash (default, ICACHE_FLASH_ATTR)", [{"IROM": 0}, 1048576]],
]
section_mapping = (
(".irom0.text", "IROM"),
(".text", "IRAM"),
(".data", "DATA"),
(".rodata", "RODATA"),
(".bss", "BSS"),
)
cmd = [os.path.join(path, "xtensa-lx106-elf-size"), "-A", elf]
with subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) as proc:
lines = proc.stdout.readlines()
for line in lines:
words = line.split()
for section, target in section_mapping:
if not line.startswith(section):
continue
for group, (segments, total) in sizes:
if target in segments:
segments[target] += int(words[1])
assert segments[target] <= total
return sizes return sizes
def get_mmu_sizes(mmu, sizes):
iram = 0x8000 def percentage(lhs, rhs):
sizes['ICACHE'] = 0x8000 return "{}%".format(int(100.0 * float(lhs) / float(rhs)))
lines = mmu.split(' ')
for line in lines:
words = line.split('=') HINTS = {
if line.startswith('-DMMU_IRAM_SIZE'): "ICACHE": "reserved space for flash instruction cache",
iram = int(words[1], 16) "IRAM": "code in IRAM",
elif line.startswith('-DMMU_ICACHE_SIZE'): "IHEAP": "secondary heap space",
sizes['ICACHE'] = int(words[1], 16) "IROM": "code in flash",
return [iram, sizes] "DATA": "initialized variables",
"RODATA": "constants",
"BSS": "zeroed variables",
}
def safe_prefix(n, length):
if n == length:
return "`--"
return "|--"
def prefix(n, length):
if n == length:
return "└──"
return "├──"
def filter_segments(segments):
used = 0
number = 0
available = []
for (segment, size) in segments.items():
if not size:
continue
used += size
number += 1
available.append((number, segment, size))
return (number, used, available)
def main(): def main():
parser = argparse.ArgumentParser(description='Report the different segment sizes of a compiled ELF file') parser = argparse.ArgumentParser(
parser.add_argument('-e', '--elf', action='store', required=True, help='Path to the Arduino sketch ELF') description="Report the different segment sizes of a compiled ELF file"
parser.add_argument('-p', '--path', action='store', required=True, help='Path to Xtensa toolchain binaries') )
parser.add_argument('-i', '--mmu', action='store', required=False, help='MMU build options') parser.add_argument(
"-e",
"--elf",
action="store",
required=True,
help="Path to the Arduino sketch ELF",
)
parser.add_argument(
"-p",
"--path",
action="store",
required=True,
help="Path to Xtensa toolchain binaries",
)
parser.add_argument(
"-i", "--mmu", action="store", required=False, help="MMU build options"
)
args = parser.parse_args() args = parser.parse_args()
sizes = get_segment_sizes(args.elf, args.path) sizes = get_segment_sizes(args.elf, args.path, args.mmu)
[iram, sizes] = get_mmu_sizes(args.mmu, sizes)
hints = get_segment_hints(iram)
sys.stderr.write("Executable segment sizes:" + os.linesep) for group, (segments, total) in sizes:
for k in sizes.keys(): number, used, segments = filter_segments(segments)
sys.stderr.write("%-7s: %-5d %s %s" % (k, sizes[k], hints[k], os.linesep))
return 0 print(f". {group:<8}, used {used} / {total} bytes ({percentage(used, total)})")
print("| SEGMENT BYTES DESCRIPTION")
for n, segment, size in segments:
try:
print(f"{prefix(n, number)} ", end="")
except UnicodeEncodeError:
print(f"{safe_prefix(n, number)} ", end="")
print(f"{segment:<8} {size:<8} {HINTS[segment]:<16}")
if __name__ == '__main__':
sys.exit(main()) if __name__ == "__main__":
main()