From d23d9c08b5eb992f349bccc149d2cb39f481131f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 15 Sep 2019 12:39:46 -0700 Subject: [PATCH] Add segment size printout to standard build process Since IRAM is such a precious resource on the ESP8266, dump out its size (and all other segments) at the end of the build process. Ex: Executable segment sizes: IROM : 338932 IRAM : 27263 DATA : 1476 RODATA : 2896 BSS : 30304 Sketch uses 370567 bytes (35%) of program storage space. Maximum is 1044464 bytes. Global variables use 34676 bytes (42%) of dynamic memory, leaving 47244 bytes for local variables. Maximum is 81920 bytes. --- platform.txt | 2 ++ tools/sizes.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100755 tools/sizes.py diff --git a/platform.txt b/platform.txt index 25c14c97e8..8bccbe2afc 100644 --- a/platform.txt +++ b/platform.txt @@ -15,6 +15,7 @@ runtime.tools.python3.path={runtime.platform.path}/tools/python3 runtime.tools.esptool.path={runtime.platform.path}/tools/esptool runtime.tools.signing={runtime.platform.path}/tools/signing.py runtime.tools.elf2bin={runtime.platform.path}/tools/elf2bin.py +runtime.tools.sizes={runtime.platform.path}/tools/sizes.py runtime.tools.makecorever={runtime.platform.path}/tools/makecorever.py runtime.tools.eboot={runtime.platform.path}/bootloaders/eboot/eboot.elf @@ -112,6 +113,7 @@ recipe.objcopy.eep.pattern= ## Create hex recipe.objcopy.hex.1.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.elf2bin}" --eboot "{runtime.tools.eboot}" --app "{build.path}/{build.project_name}.elf" --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size {build.flash_size} --path "{runtime.tools.xtensa-lx106-elf-gcc.path}/bin" --out "{build.path}/{build.project_name}.bin" recipe.objcopy.hex.2.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.signing}" --mode sign --privatekey "{build.source.path}/private.key" --bin "{build.path}/{build.project_name}.bin" --out "{build.path}/{build.project_name}.bin.signed" --legacy "{build.path}/{build.project_name}.bin.legacy_sig" +recipe.objcopy.hex.3.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.sizes}" --elf "{build.path}/{build.project_name}.elf" --path "{runtime.tools.xtensa-lx106-elf-gcc.path}/bin" ## Save hex recipe.output.tmp_file={build.project_name}.bin diff --git a/tools/sizes.py b/tools/sizes.py new file mode 100755 index 0000000000..669712c1de --- /dev/null +++ b/tools/sizes.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# Display the segment sizes used by an ELF +# +# Copyright (C) 2019 - Earle F. Philhower, III +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import print_function +import argparse +import os +import subprocess +import sys + +def get_segment_sizes(elf, path): + sizes = {} + sizes['IROM'] = 0 + sizes['IRAM'] = 0 + sizes['DATA'] = 0 + sizes['RODATA'] = 0 + sizes['BSS'] = 0 + p = subprocess.Popen([path + "/xtensa-lx106-elf-size", '-A', elf], stdout=subprocess.PIPE, universal_newlines=True ) + lines = p.stdout.readlines() + for line in lines: + words = line.split() + if line.startswith('.irom0.text'): + sizes['IROM'] = sizes['IROM'] + int(words[1]) + elif line.startswith('.text'): # Gets .text and .text1 + sizes['IRAM'] = sizes['IRAM'] + int(words[1]) + elif line.startswith('.data'): # Gets .text and .text1 + sizes['DATA'] = sizes['DATA'] + int(words[1]) + elif line.startswith('.rodata'): # Gets .text and .text1 + sizes['RODATA'] = sizes['RODATA'] + int(words[1]) + elif line.startswith('.bss'): # Gets .text and .text1 + sizes['BSS'] = sizes['BSS'] + int(words[1]) + return sizes + +def main(): + parser = argparse.ArgumentParser(description='Report the different segment sizes of a compiled ELF file') + 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') + + args = parser.parse_args() + sizes = get_segment_sizes(args.elf, args.path) + + sys.stderr.write("Executable segment sizes:" + os.linesep) + for k in sizes.keys(): + sys.stderr.write("%-7s: %d%s" % (k, sizes[k], os.linesep)) + + return 0 + +if __name__ == '__main__': + sys.exit(main())