From 4f877bfb1a891e341013df3bc9914defb5d6a1eb Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 3 Nov 2020 17:43:57 +0100 Subject: [PATCH] removed old scripts, so mem optimizations --- CHANGELOG_LATEST.md | 3 +- scripts/analyze_stackdmp.py | 26 --- scripts/build.sh | 169 ---------------- scripts/clean_fw.py | 14 -- scripts/decoder.py | 307 ----------------------------- scripts/decoder_linux.py | 307 ----------------------------- scripts/memanalyzer.py | 383 ------------------------------------ src/version.h | 2 +- 8 files changed, 3 insertions(+), 1208 deletions(-) delete mode 100755 scripts/analyze_stackdmp.py delete mode 100755 scripts/build.sh delete mode 100755 scripts/clean_fw.py delete mode 100755 scripts/decoder.py delete mode 100755 scripts/decoder_linux.py delete mode 100755 scripts/memanalyzer.py diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 77d09e2a2..168f8f142 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -6,7 +6,8 @@ ### Fixed ### Changed +- optimized MQTT for HA to reduce mem fragmentation issues ### Removed - +- old scripts diff --git a/scripts/analyze_stackdmp.py b/scripts/analyze_stackdmp.py deleted file mode 100755 index 9fc8c2a23..000000000 --- a/scripts/analyze_stackdmp.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -from subprocess import call -import os - -# example stackdmp.txt would contain text like below copied & pasted from a 'crash dump' command: - -# >>>stack>>> -# 3fffff20: 3fff32f0 00000003 3fff3028 402101b2 -# 3fffff30: 3fffdad0 3fff3280 0000000d 402148aa -# 3fffff40: 3fffdad0 3fff3280 3fff326c 3fff32f0 -# 3fffff50: 0000000d 3fff326c 3fff3028 402103bd -# 3fffff60: 0000000d 3fff34cc 40211de4 3fff34cc -# 3fffff70: 3fff3028 3fff14c4 3fff301c 3fff34cc -# 3fffff80: 3fffdad0 3fff14c4 3fff3028 40210493 -# 3fffff90: 3fffdad0 00000000 3fff14c4 4020a738 -# 3fffffa0: 3fffdad0 00000000 3fff349c 40211e90 -# 3fffffb0: feefeffe feefeffe 3ffe8558 40100b01 -# <</dev/null 2>&1 || return 1 - command git rev-parse >/dev/null 2>&1 || return 1 - - return 0 -} - -stat_bytes() { - filesize=`du -k "$1" | cut -f1;` - echo 'size:' $filesize 'bytes' -} - -# Available environments -list_envs() { - grep env: platformio.ini | sed 's/\[env:\(.*\)\]/\1/g' -} - -print_available() { - echo "--------------------------------------------------------------" - echo "Available environments:" - for environment in $available; do - echo "-> $environment" - done -} - -print_environments() { - echo "--------------------------------------------------------------" - echo "Current environments:" - for environment in $environments; do - echo "-> $environment" - done -} - -set_default_environments() { - # Hook to build in parallel when using travis - if [[ "${TRAVIS_BUILD_STAGE_NAME}" = "Release" ]] && ${par_build}; then - environments=$(echo ${available} | \ - awk -v par_thread=${par_thread} -v par_total_threads=${par_total_threads} \ - '{ for (i = 1; i <= NF; i++) if (++j % par_total_threads == par_thread ) print $i; }') - return - fi - - # Only build travis target - if [[ "${TRAVIS_BUILD_STAGE_NAME}" = "Test" ]]; then - environments=$travis - return - fi - - # Fallback to all available environments - environments=$available -} - -build_environments() { - echo "--------------------------------------------------------------" - echo "Building firmware images..." - # don't move to firmware folder until Travis fixed (see https://github.com/travis-ci/dpl/issues/846#issuecomment-547157406) - # mkdir -p $destination - - for environment in $environments; do - echo "* EMS-ESP-$version-$environment.bin" - platformio run --silent --environment $environment || exit 1 - stat_bytes .pio/build/$environment/firmware.bin - # mv .pio/build/$environment/firmware.bin $destination/EMS-ESP-$version-$environment.bin - # mv .pio/build/$environment/firmware.bin EMS-ESP-$version-$environment.bin - mv .pio/build/$environment/firmware.bin EMS-ESP-dev-$environment.bin - done - echo "--------------------------------------------------------------" -} - - -####### MAIN - -destination=firmware -version_file=./src/version.h -version=$(grep -E '^#define EMSESP_APP_VERSION' $version_file | awk '{print $3}' | sed 's/"//g') - -if ${TRAVIS:-false}; then - git_revision=${TRAVIS_COMMIT::7} - git_tag=${TRAVIS_TAG} -elif is_git; then - git_revision=$(git rev-parse --short HEAD) - git_tag=$(git tag --contains HEAD) -else - git_revision=unknown - git_tag= -fi - -echo $git_tag - -if [[ -n $git_tag ]]; then - new_version=${version/-*} - sed -i -e "s@$version@$new_version@" $version_file - version=$new_version - trap "git checkout -- $version_file" EXIT -fi - -par_build=false -par_thread=${BUILDER_THREAD:-0} -par_total_threads=${BUILDER_TOTAL_THREADS:-4} -if [ ${par_thread} -ne ${par_thread} -o \ - ${par_total_threads} -ne ${par_total_threads} ]; then - echo "Parallel threads should be a number." - exit -fi -if [ ${par_thread} -ge ${par_total_threads} ]; then - echo "Current thread is greater than total threads. Doesn't make sense" - exit -fi - -# travis platformio target is used for nightly Test -travis=$(list_envs | grep travis | sort) - -# get all taregts, excluding travis and debug -available=$(list_envs | grep -Ev -- 'travis|debug|release' | sort) - -export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS}" - -# get command line Parameters -# l prints environments -# 2 does parallel builds -# d uses next arg as destination folder -while getopts "lpd:" opt; do - case $opt in - l) - print_available - exit - ;; - p) - par_build=true - ;; - d) - destination=$OPTARG - ;; - esac -done - -shift $((OPTIND-1)) - -# Welcome message -echo "--------------------------------------------------------------" -echo "EMS-ESP FIRMWARE BUILDER" -echo "Building for version ${version}" ${git_revision:+($git_revision)} - -# Environments to build -environments=$@ - -if [ $# -eq 0 ]; then - set_default_environments -fi - -if ${CI:-false}; then - print_environments -fi - -# for debugging -echo "* git_revision = $git_revision" -echo "* git_tag = $git_tag" -echo "* TRAVIS_COMMIT = $TRAVIS_COMMIT" -echo "* TRAVIS_TAG = $TRAVIS_TAG" -echo "* TRAVIS_BRANCH = $TRAVIS_BRANCH" -echo "* TRAVIS_BUILD_STAGE_NAME = $TRAVIS_BUILD_STAGE_NAME" - -build_environments - diff --git a/scripts/clean_fw.py b/scripts/clean_fw.py deleted file mode 100755 index 140f23ee4..000000000 --- a/scripts/clean_fw.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python -from subprocess import call -import os -Import("env") - -def clean(source, target, env): - print("\n** Starting clean...") - call(["pio", "run", "-t", "erase"]) - call(["esptool.py", "-p COM6", "write_flash 0x00000", os.getcwd()+"../firmware/*.bin"]) - print("\n** Finished clean.") - -# built in targets: (buildprog, size, upload, program, buildfs, uploadfs, uploadfsota) -env.AddPreAction("buildprog", clean) - diff --git a/scripts/decoder.py b/scripts/decoder.py deleted file mode 100755 index a86ea655c..000000000 --- a/scripts/decoder.py +++ /dev/null @@ -1,307 +0,0 @@ -#!/usr/bin/env python3 - -"""ESP Exception Decoder - -github: https://github.com/janLo/EspArduinoExceptionDecoder -license: GPL v3 -author: Jan Losinski -""" - -import argparse -import re -import subprocess -from collections import namedtuple - -import sys - -import os - -EXCEPTIONS = [ - "Illegal instruction", - "SYSCALL instruction", - "InstructionFetchError: Processor internal physical address or data error during instruction fetch", - "LoadStoreError: Processor internal physical address or data error during load or store", - "Level1Interrupt: Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register", - "Alloca: MOVSP instruction, if caller's registers are not in the register file", - "IntegerDivideByZero: QUOS, QUOU, REMS, or REMU divisor operand is zero", - "reserved", - "Privileged: Attempt to execute a privileged operation when CRING ? 0", - "LoadStoreAlignmentCause: Load or store to an unaligned address", - "reserved", - "reserved", - "InstrPIFDataError: PIF data error during instruction fetch", - "LoadStorePIFDataError: Synchronous PIF data error during LoadStore access", - "InstrPIFAddrError: PIF address error during instruction fetch", - "LoadStorePIFAddrError: Synchronous PIF address error during LoadStore access", - "InstTLBMiss: Error during Instruction TLB refill", - "InstTLBMultiHit: Multiple instruction TLB entries matched", - "InstFetchPrivilege: An instruction fetch referenced a virtual address at a ring level less than CRING", - "reserved", - "InstFetchProhibited: An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch", - "reserved", - "reserved", - "reserved", - "LoadStoreTLBMiss: Error during TLB refill for a load or store", - "LoadStoreTLBMultiHit: Multiple TLB entries matched for a load or store", - "LoadStorePrivilege: A load or store referenced a virtual address at a ring level less than CRING", - "reserved", - "LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads", - "StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores" -] - -PLATFORMS = { - "ESP8266": "lx106", - "ESP32": "esp32" -} - -EXCEPTION_REGEX = re.compile("^Exception \\((?P[0-9]*)\\):$") -COUNTER_REGEX = re.compile('^epc1=(?P0x[0-9a-f]+) epc2=(?P0x[0-9a-f]+) epc3=(?P0x[0-9a-f]+) ' - 'excvaddr=(?P0x[0-9a-f]+) depc=(?P0x[0-9a-f]+)$') -CTX_REGEX = re.compile("^ctx: (?P.+)$") -POINTER_REGEX = re.compile('^sp: (?P[0-9a-f]+) end: (?P[0-9a-f]+) offset: (?P[0-9a-f]+)$') -STACK_BEGIN = '>>>stack>>>' -STACK_END = '<<[0-9a-f]+):\W+(?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+)(\W.*)?$') - -StackLine = namedtuple("StackLine", ["offset", "content"]) - - -class ExceptionDataParser(object): - def __init__(self): - self.exception = None - - self.epc1 = None - self.epc2 = None - self.epc3 = None - self.excvaddr = None - self.depc = None - - self.ctx = None - - self.sp = None - self.end = None - self.offset = None - - self.stack = [] - - def _parse_exception(self, line): - match = EXCEPTION_REGEX.match(line) - if match is not None: - self.exception = int(match.group('exc')) - return self._parse_counters - return self._parse_exception - - def _parse_counters(self, line): - match = COUNTER_REGEX.match(line) - if match is not None: - self.epc1 = match.group("epc1") - self.epc2 = match.group("epc2") - self.epc3 = match.group("epc3") - self.excvaddr = match.group("excvaddr") - self.depc = match.group("depc") - return self._parse_ctx - return self._parse_counters - - def _parse_ctx(self, line): - match = CTX_REGEX.match(line) - if match is not None: - self.ctx = match.group("ctx") - return self._parse_pointers - return self._parse_ctx - - def _parse_pointers(self, line): - match = POINTER_REGEX.match(line) - if match is not None: - self.sp = match.group("sp") - self.end = match.group("end") - self.offset = match.group("offset") - return self._parse_stack_begin - return self._parse_pointers - - def _parse_stack_begin(self, line): - if line == STACK_BEGIN: - return self._parse_stack_line - return self._parse_stack_begin - - def _parse_stack_line(self, line): - if line != STACK_END: - match = STACK_REGEX.match(line) - if match is not None: - self.stack.append(StackLine(offset=match.group("off"), - content=(match.group("c1"), match.group("c2"), match.group("c3"), - match.group("c4")))) - return self._parse_stack_line - return None - - def parse_file(self, file, stack_only=False): - func = self._parse_exception - if stack_only: - func = self._parse_stack_begin - - for line in file: - func = func(line.strip()) - if func is None: - break - - if func is not None: - print("ERROR: Parser not complete!") - sys.exit(1) - - -class AddressResolver(object): - def __init__(self, tool_path, elf_path): - self._tool = tool_path - self._elf = elf_path - self._address_map = {} - - def _lookup(self, addresses): - cmd = [self._tool, "-aipfC", "-e", self._elf] + [addr for addr in addresses if addr is not None] - - if sys.version_info[0] < 3: - output = subprocess.check_output(cmd) - else: - output = subprocess.check_output(cmd, encoding="utf-8") - - line_regex = re.compile("^(?P[0-9a-fx]+): (?P.+)$") - - last = None - for line in output.splitlines(): - line = line.strip() - match = line_regex.match(line) - - if match is None: - if last is not None and line.startswith('(inlined by)'): - line = line [12:].strip() - self._address_map[last] += ("\n \-> inlined by: " + line) - continue - - if match.group("result") == '?? ??:0': - continue - - self._address_map[match.group("addr")] = match.group("result") - last = match.group("addr") - - def fill(self, parser): - addresses = [parser.epc1, parser.epc2, parser.epc3, parser.excvaddr, parser.sp, parser.end, parser.offset] - for line in parser.stack: - addresses.extend(line.content) - - self._lookup(addresses) - - def _sanitize_addr(self, addr): - if addr.startswith("0x"): - addr = addr[2:] - - fill = "0" * (8 - len(addr)) - return "0x" + fill + addr - - def resolve_addr(self, addr): - out = self._sanitize_addr(addr) - - if out in self._address_map: - out += ": " + self._address_map[out] - - return out - - def resolve_stack_addr(self, addr, full=True): - addr = self._sanitize_addr(addr) - if addr in self._address_map: - return addr + ": " + self._address_map[addr] - - if full: - return "[DATA (0x" + addr + ")]" - - return None - - -def print_addr(name, value, resolver): - print("{}:{} {}".format(name, " " * (8 - len(name)), resolver.resolve_addr(value))) - - -def print_stack_full(lines, resolver): - print("stack:") - for line in lines: - print(line.offset + ":") - for content in line.content: - print(" " + resolver.resolve_stack_addr(content)) - - -def print_stack(lines, resolver): - print("stack:") - for line in lines: - for content in line.content: - out = resolver.resolve_stack_addr(content, full=False) - if out is None: - continue - print(out) - - -def print_result(parser, resolver, full=True, stack_only=False): - if not stack_only: - print('Exception: {} ({})'.format(parser.exception, EXCEPTIONS[parser.exception])) - - print("") - print_addr("epc1", parser.epc1, resolver) - print_addr("epc2", parser.epc2, resolver) - print_addr("epc3", parser.epc3, resolver) - print_addr("excvaddr", parser.excvaddr, resolver) - print_addr("depc", parser.depc, resolver) - - print("") - print("ctx: " + parser.ctx) - - print("") - print_addr("sp", parser.sp, resolver) - print_addr("end", parser.end, resolver) - print_addr("offset", parser.offset, resolver) - - print("") - if full: - print_stack_full(parser.stack, resolver) - else: - print_stack(parser.stack, resolver) - - -def parse_args(): - parser = argparse.ArgumentParser(description="decode ESP Stacktraces.") - - parser.add_argument("-p", "--platform", help="The platform to decode from", choices=PLATFORMS.keys(), - default="ESP8266") - parser.add_argument("-t", "--tool", help="Path to the xtensa toolchain", - default="~/.platformio/packages/toolchain-xtensa/") - parser.add_argument("-e", "--elf", help="path to elf file", required=True) - parser.add_argument("-f", "--full", help="Print full stack dump", action="store_true") - parser.add_argument("-s", "--stack_only", help="Decode only a stractrace", action="store_true") - parser.add_argument("file", help="The file to read the exception data from ('-' for STDIN)", default="-") - - return parser.parse_args() - - -if __name__ == "__main__": - args = parse_args() - - if args.file == "-": - file = sys.stdin - else: - if not os.path.exists(args.file): - print("ERROR: file " + args.file + " not found") - sys.exit(1) - file = open(args.file, "r") - - addr2line = os.path.join(os.path.abspath(os.path.expanduser(args.tool)), - "bin/xtensa-" + PLATFORMS[args.platform] + "-elf-addr2line.exe") - if not os.path.exists(addr2line): - print("ERROR: addr2line not found (" + addr2line + ")") - - elf_file = os.path.abspath(os.path.expanduser(args.elf)) - if not os.path.exists(elf_file): - print("ERROR: elf file not found (" + elf_file + ")") - - parser = ExceptionDataParser() - resolver = AddressResolver(addr2line, elf_file) - - parser.parse_file(file, args.stack_only) - resolver.fill(parser) - - print_result(parser, resolver, args.full, args.stack_only) diff --git a/scripts/decoder_linux.py b/scripts/decoder_linux.py deleted file mode 100755 index 710d4b640..000000000 --- a/scripts/decoder_linux.py +++ /dev/null @@ -1,307 +0,0 @@ -#!/usr/bin/env python3 - -"""ESP Exception Decoder - -github: https://github.com/janLo/EspArduinoExceptionDecoder -license: GPL v3 -author: Jan Losinski -""" - -import argparse -import re -import subprocess -from collections import namedtuple - -import sys - -import os - -EXCEPTIONS = [ - "Illegal instruction", - "SYSCALL instruction", - "InstructionFetchError: Processor internal physical address or data error during instruction fetch", - "LoadStoreError: Processor internal physical address or data error during load or store", - "Level1Interrupt: Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register", - "Alloca: MOVSP instruction, if caller's registers are not in the register file", - "IntegerDivideByZero: QUOS, QUOU, REMS, or REMU divisor operand is zero", - "reserved", - "Privileged: Attempt to execute a privileged operation when CRING ? 0", - "LoadStoreAlignmentCause: Load or store to an unaligned address", - "reserved", - "reserved", - "InstrPIFDataError: PIF data error during instruction fetch", - "LoadStorePIFDataError: Synchronous PIF data error during LoadStore access", - "InstrPIFAddrError: PIF address error during instruction fetch", - "LoadStorePIFAddrError: Synchronous PIF address error during LoadStore access", - "InstTLBMiss: Error during Instruction TLB refill", - "InstTLBMultiHit: Multiple instruction TLB entries matched", - "InstFetchPrivilege: An instruction fetch referenced a virtual address at a ring level less than CRING", - "reserved", - "InstFetchProhibited: An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch", - "reserved", - "reserved", - "reserved", - "LoadStoreTLBMiss: Error during TLB refill for a load or store", - "LoadStoreTLBMultiHit: Multiple TLB entries matched for a load or store", - "LoadStorePrivilege: A load or store referenced a virtual address at a ring level less than CRING", - "reserved", - "LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads", - "StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores" -] - -PLATFORMS = { - "ESP8266": "lx106", - "ESP32": "esp32" -} - -EXCEPTION_REGEX = re.compile("^Exception \\((?P[0-9]*)\\):$") -COUNTER_REGEX = re.compile('^epc1=(?P0x[0-9a-f]+) epc2=(?P0x[0-9a-f]+) epc3=(?P0x[0-9a-f]+) ' - 'excvaddr=(?P0x[0-9a-f]+) depc=(?P0x[0-9a-f]+)$') -CTX_REGEX = re.compile("^ctx: (?P.+)$") -POINTER_REGEX = re.compile('^sp: (?P[0-9a-f]+) end: (?P[0-9a-f]+) offset: (?P[0-9a-f]+)$') -STACK_BEGIN = '>>>stack>>>' -STACK_END = '<<[0-9a-f]+):\W+(?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+)(\W.*)?$') - -StackLine = namedtuple("StackLine", ["offset", "content"]) - - -class ExceptionDataParser(object): - def __init__(self): - self.exception = None - - self.epc1 = None - self.epc2 = None - self.epc3 = None - self.excvaddr = None - self.depc = None - - self.ctx = None - - self.sp = None - self.end = None - self.offset = None - - self.stack = [] - - def _parse_exception(self, line): - match = EXCEPTION_REGEX.match(line) - if match is not None: - self.exception = int(match.group('exc')) - return self._parse_counters - return self._parse_exception - - def _parse_counters(self, line): - match = COUNTER_REGEX.match(line) - if match is not None: - self.epc1 = match.group("epc1") - self.epc2 = match.group("epc2") - self.epc3 = match.group("epc3") - self.excvaddr = match.group("excvaddr") - self.depc = match.group("depc") - return self._parse_ctx - return self._parse_counters - - def _parse_ctx(self, line): - match = CTX_REGEX.match(line) - if match is not None: - self.ctx = match.group("ctx") - return self._parse_pointers - return self._parse_ctx - - def _parse_pointers(self, line): - match = POINTER_REGEX.match(line) - if match is not None: - self.sp = match.group("sp") - self.end = match.group("end") - self.offset = match.group("offset") - return self._parse_stack_begin - return self._parse_pointers - - def _parse_stack_begin(self, line): - if line == STACK_BEGIN: - return self._parse_stack_line - return self._parse_stack_begin - - def _parse_stack_line(self, line): - if line != STACK_END: - match = STACK_REGEX.match(line) - if match is not None: - self.stack.append(StackLine(offset=match.group("off"), - content=(match.group("c1"), match.group("c2"), match.group("c3"), - match.group("c4")))) - return self._parse_stack_line - return None - - def parse_file(self, file, stack_only=False): - func = self._parse_exception - if stack_only: - func = self._parse_stack_begin - - for line in file: - func = func(line.strip()) - if func is None: - break - - if func is not None: - print("ERROR: Parser not complete!") - sys.exit(1) - - -class AddressResolver(object): - def __init__(self, tool_path, elf_path): - self._tool = tool_path - self._elf = elf_path - self._address_map = {} - - def _lookup(self, addresses): - cmd = [self._tool, "-aipfC", "-e", self._elf] + [addr for addr in addresses if addr is not None] - - if sys.version_info[0] < 3: - output = subprocess.check_output(cmd) - else: - output = subprocess.check_output(cmd, encoding="utf-8") - - line_regex = re.compile("^(?P[0-9a-fx]+): (?P.+)$") - - last = None - for line in output.splitlines(): - line = line.strip() - match = line_regex.match(line) - - if match is None: - if last is not None and line.startswith('(inlined by)'): - line = line [12:].strip() - self._address_map[last] += ("\n \-> inlined by: " + line) - continue - - if match.group("result") == '?? ??:0': - continue - - self._address_map[match.group("addr")] = match.group("result") - last = match.group("addr") - - def fill(self, parser): - addresses = [parser.epc1, parser.epc2, parser.epc3, parser.excvaddr, parser.sp, parser.end, parser.offset] - for line in parser.stack: - addresses.extend(line.content) - - self._lookup(addresses) - - def _sanitize_addr(self, addr): - if addr.startswith("0x"): - addr = addr[2:] - - fill = "0" * (8 - len(addr)) - return "0x" + fill + addr - - def resolve_addr(self, addr): - out = self._sanitize_addr(addr) - - if out in self._address_map: - out += ": " + self._address_map[out] - - return out - - def resolve_stack_addr(self, addr, full=True): - addr = self._sanitize_addr(addr) - if addr in self._address_map: - return addr + ": " + self._address_map[addr] - - if full: - return "[DATA (0x" + addr + ")]" - - return None - - -def print_addr(name, value, resolver): - print("{}:{} {}".format(name, " " * (8 - len(name)), resolver.resolve_addr(value))) - - -def print_stack_full(lines, resolver): - print("stack:") - for line in lines: - print(line.offset + ":") - for content in line.content: - print(" " + resolver.resolve_stack_addr(content)) - - -def print_stack(lines, resolver): - print("stack:") - for line in lines: - for content in line.content: - out = resolver.resolve_stack_addr(content, full=False) - if out is None: - continue - print(out) - - -def print_result(parser, resolver, full=True, stack_only=False): - if not stack_only: - print('Exception: {} ({})'.format(parser.exception, EXCEPTIONS[parser.exception])) - - print("") - print_addr("epc1", parser.epc1, resolver) - print_addr("epc2", parser.epc2, resolver) - print_addr("epc3", parser.epc3, resolver) - print_addr("excvaddr", parser.excvaddr, resolver) - print_addr("depc", parser.depc, resolver) - - print("") - print("ctx: " + parser.ctx) - - print("") - print_addr("sp", parser.sp, resolver) - print_addr("end", parser.end, resolver) - print_addr("offset", parser.offset, resolver) - - print("") - if full: - print_stack_full(parser.stack, resolver) - else: - print_stack(parser.stack, resolver) - - -def parse_args(): - parser = argparse.ArgumentParser(description="decode ESP Stacktraces.") - - parser.add_argument("-p", "--platform", help="The platform to decode from", choices=PLATFORMS.keys(), - default="ESP8266") - parser.add_argument("-t", "--tool", help="Path to the xtensa toolchain", - default="~/.platformio/packages/toolchain-xtensa/") - parser.add_argument("-e", "--elf", help="path to elf file", required=True) - parser.add_argument("-f", "--full", help="Print full stack dump", action="store_true") - parser.add_argument("-s", "--stack_only", help="Decode only a stractrace", action="store_true") - parser.add_argument("file", help="The file to read the exception data from ('-' for STDIN)", default="-") - - return parser.parse_args() - - -if __name__ == "__main__": - args = parse_args() - - if args.file == "-": - file = sys.stdin - else: - if not os.path.exists(args.file): - print("ERROR: file " + args.file + " not found") - sys.exit(1) - file = open(args.file, "r") - - addr2line = os.path.join(os.path.abspath(os.path.expanduser(args.tool)), - "bin/xtensa-" + PLATFORMS[args.platform] + "-elf-addr2line") - if not os.path.exists(addr2line): - print("ERROR: addr2line not found (" + addr2line + ")") - - elf_file = os.path.abspath(os.path.expanduser(args.elf)) - if not os.path.exists(elf_file): - print("ERROR: elf file not found (" + elf_file + ")") - - parser = ExceptionDataParser() - resolver = AddressResolver(addr2line, elf_file) - - parser.parse_file(file, args.stack_only) - resolver.fill(parser) - - print_result(parser, resolver, args.full, args.stack_only) diff --git a/scripts/memanalyzer.py b/scripts/memanalyzer.py deleted file mode 100755 index 160c4c9bb..000000000 --- a/scripts/memanalyzer.py +++ /dev/null @@ -1,383 +0,0 @@ -#!/usr/bin/env python3 -# pylint: disable=C0301,C0114,C0116,W0511 -# coding=utf-8 -# ------------------------------------------------------------------------------- -# based on ESPurna module memory analyser by xose.perez@gmail.com -# -# Rewritten for python-3 and changed to use "size" instead of "objdump" -# Based on https://github.com/esp8266/Arduino/pull/6525 -# by Maxim Prokhorov -# -# Based on: -# https://github.com/letscontrolit/ESPEasy/blob/mega/memanalyzer.py -# by psy0rz -# https://raw.githubusercontent.com/SmingHub/Sming/develop/tools/memanalyzer.py -# by Slavey Karadzhov -# https://github.com/Sermus/ESP8266_memory_analyzer -# by Andrey Filimonov -# -# ------------------------------------------------------------------------------- -# -# When using Windows with non-default installation at the C:\.platformio, -# you would need to specify toolchain path manually. For example: -# -# $ py -3 scripts\memanalyzer.py --toolchain-prefix C:\.platformio\packages\toolchain-xtensa\bin\xtensa-lx106-elf- -# -# You could also change the path to platformio binary in a similar fashion: -# $ py -3 scripts\memanalyzer.py --platformio-prefix C:\Users\Max\platformio-penv\Scripts\ -# -# ------------------------------------------------------------------------------- - -import argparse -import os -import re -import subprocess -import sys -from collections import OrderedDict -from subprocess import getstatusoutput - -__version__ = (0, 3) - -# ------------------------------------------------------------------------------- - -TOTAL_IRAM = 32786 -TOTAL_DRAM = 81920 - -DEFAULT_ENV = "esp12e" -TOOLCHAIN_PREFIX = "~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-" -PLATFORMIO_PREFIX = "" -SECTIONS = OrderedDict( - [ - (".data", "Initialized Data (RAM)"), - (".rodata", "ReadOnly Data (RAM)"), - (".bss", "Uninitialized Data (RAM)"), - (".text", "Cached Code (IRAM)"), - (".irom0.text", "Uncached Code (SPI)"), - ] -) -DESCRIPTION = "Memory Analyzer v{}".format( - ".".join(str(x) for x in __version__) -) - - -# ------------------------------------------------------------------------------- - - -def size_binary_path(prefix): - return "{}size".format(os.path.expanduser(prefix)) - - -def file_size(file): - try: - return os.stat(file).st_size - except OSError: - return 0 - - -def analyse_memory(size, elf_file): - proc = subprocess.Popen( - [size, "-A", elf_file], stdout=subprocess.PIPE, universal_newlines=True - ) - lines = proc.stdout.readlines() - - values = {} - - for line in lines: - words = line.split() - for name in SECTIONS.keys(): - if line.startswith(name): - value = values.setdefault(name, 0) - value += int(words[1]) - values[name] = value - break - - return values - - -def run(prefix, env, modules, debug): - flags = " ".join("-D{}_SUPPORT={:d}".format(k, v) for k, v in modules.items()) - - os_env = os.environ.copy() - os_env["PLATFORMIO_SRC_BUILD_FLAGS"] = flags - os_env["PLATFORMIO_BUILD_CACHE_DIR"] = "test/pio_cache" - - if debug: - print("Selected flags: {}".format(flags)) - - command = [os.path.join(prefix, "platformio"), "run"] - if not debug: - command.append("--silent") - command.extend(["--environment", env]) - - output = None if debug else subprocess.DEVNULL - - - try: - subprocess.check_call( - command, shell=False, env=os_env, stdout=output, stderr=output - ) - except subprocess.CalledProcessError: - print(" - Command failed: {}".format(command)) - print(" - Selected flags: {}".format(flags)) - sys.exit(1) - - -def get_available_modules(): - modules = [] - for line in open("lib/framework/services.h"): - match = re.search(r"(\w*)_SUPPORT", line) - if match: - modules.append((match.group(1), 0)) - modules.sort(key=lambda item: item[0]) - - return OrderedDict(modules) - - -def parse_commandline_args(): - parser = argparse.ArgumentParser( - description=DESCRIPTION, formatter_class=argparse.ArgumentDefaultsHelpFormatter - ) - parser.add_argument( - "-e", "--environment", help="platformio environment to use", default=DEFAULT_ENV - ) - parser.add_argument( - "--toolchain-prefix", - help="where to find the xtensa toolchain binaries", - default=TOOLCHAIN_PREFIX, - ) - parser.add_argument( - "--platformio-prefix", - help="where to find the platformio executable", - default=PLATFORMIO_PREFIX, - ) - parser.add_argument( - "-c", - "--core", - help="use core as base configuration instead of default", - action="store_true", - default=False, - ) - parser.add_argument( - "-l", - "--list", - help="list available modules", - action="store_true", - default=False, - ) - parser.add_argument("-d", "--debug", action="store_true", default=False) - parser.add_argument( - "modules", nargs="*", help="Modules to test (use ALL to test them all)" - ) - - return parser.parse_args() - - -def size_binary_exists(args): - - status, _ = getstatusoutput(size_binary_path(args.toolchain_prefix)) - if status != 1: - print("size not found, please check that the --toolchain-prefix is correct") - sys.exit(1) - - -def get_modules(args): - - # Load list of all modules - available_modules = get_available_modules() - if args.list: - print("List of available modules:\n") - for module in available_modules: - print("* " + module) - print() - sys.exit(0) - - modules = [] - if args.modules: - if "ALL" in args.modules: - modules.extend(available_modules.keys()) - else: - modules.extend(args.modules) - modules.sort() - - # Check test modules exist - for module in modules: - if module not in available_modules: - print("Module {} not found".format(module)) - sys.exit(2) - - # Either use all of modules or specified subset - if args.core: - modules = available_modules - else: - modules = OrderedDict((x, 0) for x in modules) - - configuration = "CORE" if args.core else "DEFAULT" - - return configuration, modules - - -# ------------------------------------------------------------------------------- - - -class Analyser: - """Run platformio and print info about the resulting binary.""" - - OUTPUT_FORMAT = "{:<20}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}" - DELIMETERS = OUTPUT_FORMAT.format( - "-" * 20, "-" * 15, "-" * 15, "-" * 15, "-" * 15, "-" * 15, "-" * 15, "-" * 15 - ) - FIRMWARE_FORMAT = ".pio/build/{env}/firmware.{suffix}" - - class _Enable: - def __init__(self, analyser, module=None): - self.analyser = analyser - self.module = module - - def __enter__(self): - if not self.module: - for name in self.analyser.modules: - self.analyser.modules[name] = 1 - else: - self.analyser.modules[self.module] = 1 - return self.analyser - - def __exit__(self, *args, **kwargs): - if not self.module: - for name in self.analyser.modules: - self.analyser.modules[name] = 0 - else: - self.analyser.modules[self.module] = 0 - - analyser = None - module = None - - def __init__(self, args, modules): - self._debug = args.debug - self._platformio_prefix = args.platformio_prefix - self._toolchain_prefix = args.toolchain_prefix - self._environment = args.environment - self.modules = modules - self.baseline = None - - def enable(self, module=None): - return self._Enable(self, module) - - def print(self, *args): - print(self.OUTPUT_FORMAT.format(*args)) - - def print_delimiters(self): - print(self.DELIMETERS) - - def begin(self, name): - self.print( - "Module", - "Cache IRAM", - "Init RAM", - "R.O. RAM", - "Uninit RAM", - "Available RAM", - "Flash ROM", - "Binary size", - ) - self.print( - "", - ".text + .text1", - ".data", - ".rodata", - ".bss", - "heap + stack", - ".irom0.text", - "", - ) - self.print_delimiters() - self.baseline = self.run() - self.print_values(name, self.baseline) - - def print_values(self, header, values): - self.print( - header, - values[".text"], - values[".data"], - values[".rodata"], - values[".bss"], - values["free"], - values[".irom0.text"], - values["size"], - ) - - def print_compare(self, header, values): - self.print( - header, - values[".text"] - self.baseline[".text"], - values[".data"] - self.baseline[".data"], - values[".rodata"] - self.baseline[".rodata"], - values[".bss"] - self.baseline[".bss"], - values["free"] - self.baseline["free"], - values[".irom0.text"] - self.baseline[".irom0.text"], - values["size"] - self.baseline["size"], - ) - - def run(self): - run(self._platformio_prefix, self._environment, self.modules, self._debug) - - elf_path = self.FIRMWARE_FORMAT.format(env=self._environment, suffix="elf") - bin_path = self.FIRMWARE_FORMAT.format(env=self._environment, suffix="bin") - - values = analyse_memory( - size_binary_path(self._toolchain_prefix), elf_path - ) - - free = 80 * 1024 - values[".data"] - values[".rodata"] - values[".bss"] - free = free + (16 - free % 16) - values["free"] = free - - values["size"] = file_size(bin_path) - - return values - - -def main(args): - - # Check xtensa-lx106-elf-size is in the path - size_binary_exists(args) - - # Which modules to test? - configuration, modules = get_modules(args) - - # print_values init message - print('Selected environment "{}"'.format(args.environment), end="") - if modules: - print(" with modules: {}".format(" ".join(modules.keys()))) - else: - print() - - print() - print("Analyzing {} configuration".format(configuration)) - print() - - # Build the core without any modules to get base memory usage - analyser = Analyser(args, modules) - analyser.begin(configuration) - - # Test each module separately - results = {} - for module in analyser.modules: - with analyser.enable(module): - results[module] = analyser.run() - analyser.print_compare(module, results[module]) - - # Test all modules - if analyser.modules: - - with analyser.enable(): - total = analyser.run() - - analyser.print_delimiters() - if len(analyser.modules) > 1: - analyser.print_compare("ALL MODULES", total) - - analyser.print_values("TOTAL", total) - - -if __name__ == "__main__": - main(parse_commandline_args()) diff --git a/src/version.h b/src/version.h index 96602d1d1..4616c4e4d 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "2.1.1b0" +#define EMSESP_APP_VERSION "2.1.1b1"