mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
removed old scripts, so mem optimizations
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
- optimized MQTT for HA to reduce mem fragmentation issues
|
||||
|
||||
### Removed
|
||||
|
||||
- old scripts
|
||||
|
||||
|
||||
@@ -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
|
||||
# <<<stack<<<
|
||||
|
||||
call(['python', 'scripts/decoder.py ', '-s', '-e', os.getcwd()+"/.pio/build/esp12e/firmware.elf", 'scripts/stackdmp.txt'])
|
||||
|
||||
# example for linux:
|
||||
# % cd EMS-ESP
|
||||
# % python scripts/decoder_linux.py -s -e .pio/build/esp12e/firmware.elf scripts/stackdmp.txt
|
||||
|
||||
# python decoder_linux.py -s -e ../.pio/build/esp8266-debug/firmware.elf stackdmp.txt
|
||||
169
scripts/build.sh
169
scripts/build.sh
@@ -1,169 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
### Functions
|
||||
|
||||
is_git() {
|
||||
command -v git >/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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<exc>[0-9]*)\\):$")
|
||||
COUNTER_REGEX = re.compile('^epc1=(?P<epc1>0x[0-9a-f]+) epc2=(?P<epc2>0x[0-9a-f]+) epc3=(?P<epc3>0x[0-9a-f]+) '
|
||||
'excvaddr=(?P<excvaddr>0x[0-9a-f]+) depc=(?P<depc>0x[0-9a-f]+)$')
|
||||
CTX_REGEX = re.compile("^ctx: (?P<ctx>.+)$")
|
||||
POINTER_REGEX = re.compile('^sp: (?P<sp>[0-9a-f]+) end: (?P<end>[0-9a-f]+) offset: (?P<offset>[0-9a-f]+)$')
|
||||
STACK_BEGIN = '>>>stack>>>'
|
||||
STACK_END = '<<<stack<<<'
|
||||
STACK_REGEX = re.compile(
|
||||
'^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[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<addr>[0-9a-fx]+): (?P<result>.+)$")
|
||||
|
||||
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)
|
||||
@@ -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<exc>[0-9]*)\\):$")
|
||||
COUNTER_REGEX = re.compile('^epc1=(?P<epc1>0x[0-9a-f]+) epc2=(?P<epc2>0x[0-9a-f]+) epc3=(?P<epc3>0x[0-9a-f]+) '
|
||||
'excvaddr=(?P<excvaddr>0x[0-9a-f]+) depc=(?P<depc>0x[0-9a-f]+)$')
|
||||
CTX_REGEX = re.compile("^ctx: (?P<ctx>.+)$")
|
||||
POINTER_REGEX = re.compile('^sp: (?P<sp>[0-9a-f]+) end: (?P<end>[0-9a-f]+) offset: (?P<offset>[0-9a-f]+)$')
|
||||
STACK_BEGIN = '>>>stack>>>'
|
||||
STACK_END = '<<<stack<<<'
|
||||
STACK_REGEX = re.compile(
|
||||
'^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[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<addr>[0-9a-fx]+): (?P<result>.+)$")
|
||||
|
||||
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)
|
||||
@@ -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 <prokhorov.max@outlook.com>
|
||||
#
|
||||
# Based on:
|
||||
# https://github.com/letscontrolit/ESPEasy/blob/mega/memanalyzer.py
|
||||
# by psy0rz <edwin@datux.nl>
|
||||
# https://raw.githubusercontent.com/SmingHub/Sming/develop/tools/memanalyzer.py
|
||||
# by Slavey Karadzhov <slav@attachix.com>
|
||||
# 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- <args>
|
||||
#
|
||||
# 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())
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "2.1.1b0"
|
||||
#define EMSESP_APP_VERSION "2.1.1b1"
|
||||
|
||||
Reference in New Issue
Block a user