Browse Source

Scripts: memanalyzer can use size instead of objdump (#2021)

* utils: use size instead of objdump, include .text1 in .text calculation

* cleanup class attrs, import
master
Max Prokhorov 5 years ago
committed by GitHub
parent
commit
5ac420dfcd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 64 additions and 95 deletions
  1. +64
    -95
      code/scripts/memanalyzer.py

+ 64
- 95
code/scripts/memanalyzer.py View File

@ -5,8 +5,9 @@
# ESPurna module memory analyser # ESPurna module memory analyser
# xose.perez@gmail.com # xose.perez@gmail.com
# #
# Rewritten for python-3 by Maxim Prokhorov
# prokhorov.max@outlook.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: # Based on:
# https://github.com/letscontrolit/ESPEasy/blob/mega/memanalyzer.py # https://github.com/letscontrolit/ESPEasy/blob/mega/memanalyzer.py
@ -28,8 +29,6 @@
# #
# ------------------------------------------------------------------------------- # -------------------------------------------------------------------------------
from __future__ import print_function
import argparse import argparse
import os import os
import re import re
@ -38,7 +37,7 @@ import sys
from collections import OrderedDict from collections import OrderedDict
from subprocess import getstatusoutput from subprocess import getstatusoutput
__version__ = (0, 2)
__version__ = (0, 3)
# ------------------------------------------------------------------------------- # -------------------------------------------------------------------------------
@ -46,14 +45,15 @@ TOTAL_IRAM = 32786
TOTAL_DRAM = 81920 TOTAL_DRAM = 81920
DEFAULT_ENV = "nodemcu-lolin" DEFAULT_ENV = "nodemcu-lolin"
OBJDUMP_PREFIX = "~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-"
TOOLCHAIN_PREFIX = "~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-"
PLATFORMIO_PREFIX = ""
SECTIONS = OrderedDict( SECTIONS = OrderedDict(
[ [
("data", "Initialized Data (RAM)"),
("rodata", "ReadOnly Data (RAM)"),
("bss", "Uninitialized Data (RAM)"),
("text", "Cached Code (IRAM)"),
("irom0_text", "Uncached Code (SPI)"),
(".data", "Initialized Data (RAM)"),
(".rodata", "ReadOnly Data (RAM)"),
(".bss", "Uninitialized Data (RAM)"),
(".text", "Cached Code (IRAM)"),
(".irom0.text", "Uncached Code (SPI)"),
] ]
) )
DESCRIPTION = "ESPurna Memory Analyzer v{}".format( DESCRIPTION = "ESPurna Memory Analyzer v{}".format(
@ -64,8 +64,8 @@ DESCRIPTION = "ESPurna Memory Analyzer v{}".format(
# ------------------------------------------------------------------------------- # -------------------------------------------------------------------------------
def objdump_path(prefix):
return "{}objdump".format(os.path.expanduser(prefix))
def size_binary_path(prefix):
return "{}size".format(os.path.expanduser(prefix))
def file_size(file): def file_size(file):
@ -75,48 +75,24 @@ def file_size(file):
return 0 return 0
def analyse_memory(elf_file, objdump):
def analyse_memory(size, elf_file):
proc = subprocess.Popen( proc = subprocess.Popen(
[objdump, "-t", elf_file], stdout=subprocess.PIPE, universal_newlines=True
[size, "-A", elf_file], stdout=subprocess.PIPE, universal_newlines=True
) )
lines = proc.stdout.readlines() lines = proc.stdout.readlines()
# print("{0: >10}|{1: >30}|{2: >12}|{3: >12}|{4: >8}".format("Section", "Description", "Start (hex)", "End (hex)", "Used space"));
# print("------------------------------------------------------------------------------");
ret = {}
for (id_, _) in list(SECTIONS.items()):
section_start_token = " _{}_start".format(id_)
section_end_token = " _{}_end".format(id_)
section_start = -1
section_end = -1
for line in lines:
line = line.strip()
if section_start_token in line:
data = line.split(" ")
section_start = int(data[0], 16)
if section_end_token in line:
data = line.split(" ")
section_end = int(data[0], 16)
if section_start != -1 and section_end != -1:
break
section_length = section_end - section_start
# if i < 3:
# usedRAM += section_length
# if i == 3:
# usedIRAM = TOTAL_IRAM - section_length;
values = {}
ret[id_] = section_length
# print("{0: >10}|{1: >30}|{2:12X}|{3:12X}|{4:8}".format(id_, descr, section_start, section_end, section_length))
# i += 1
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
# print("Total Used RAM : {:d}".format(usedRAM))
# print("Free RAM : {:d}".format(TOTAL_DRAM - usedRAM))
# print("Free IRam : {:d}".format(usedIRAM))
return ret
return values
def run(prefix, env, modules, debug): def run(prefix, env, modules, debug):
@ -165,12 +141,12 @@ def parse_commandline_args():
parser.add_argument( parser.add_argument(
"--toolchain-prefix", "--toolchain-prefix",
help="where to find the xtensa toolchain binaries", help="where to find the xtensa toolchain binaries",
default=OBJDUMP_PREFIX,
default=TOOLCHAIN_PREFIX,
) )
parser.add_argument( parser.add_argument(
"--platformio-prefix", "--platformio-prefix",
help="where to find the platformio executable", help="where to find the platformio executable",
default="",
default=PLATFORMIO_PREFIX,
) )
parser.add_argument( parser.add_argument(
"-c", "-c",
@ -194,11 +170,11 @@ def parse_commandline_args():
return parser.parse_args() return parser.parse_args()
def objdump_check(args):
def size_binary_exists(args):
status, _ = getstatusoutput(objdump_path(args.toolchain_prefix))
if status not in (2, 512):
print("objdump not found, please check that the --toolchain-prefix is correct")
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) sys.exit(1)
@ -245,8 +221,10 @@ class Analyser:
"""Run platformio and print info about the resulting binary.""" """Run platformio and print info about the resulting binary."""
OUTPUT_FORMAT = "{:<20}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}" OUTPUT_FORMAT = "{:<20}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}|{:<15}"
ELF_FORMAT = ".pio/build/{env}/firmware.elf"
BIN_FORMAT = ".pio/build/{env}/firmware.bin"
DELIMETERS = OUTPUT_FORMAT.format(
"-" * 20, "-" * 15, "-" * 15, "-" * 15, "-" * 15, "-" * 15, "-" * 15, "-" * 15
)
FIRMWARE_FORMAT = ".pio/build/{env}/firmware.{suffix}"
class _Enable: class _Enable:
def __init__(self, analyser, module=None): def __init__(self, analyser, module=None):
@ -276,8 +254,6 @@ class Analyser:
self._platformio_prefix = args.platformio_prefix self._platformio_prefix = args.platformio_prefix
self._toolchain_prefix = args.toolchain_prefix self._toolchain_prefix = args.toolchain_prefix
self._environment = args.environment self._environment = args.environment
self._elf_path = self.ELF_FORMAT.format(env=args.environment)
self._bin_path = self.BIN_FORMAT.format(env=args.environment)
self.modules = modules self.modules = modules
self.baseline = None self.baseline = None
@ -288,16 +264,7 @@ class Analyser:
print(self.OUTPUT_FORMAT.format(*args)) print(self.OUTPUT_FORMAT.format(*args))
def print_delimiters(self): def print_delimiters(self):
self.print(
"-" * 20,
"-" * 15,
"-" * 15,
"-" * 15,
"-" * 15,
"-" * 15,
"-" * 15,
"-" * 15,
)
print(self.DELIMETERS)
def begin(self, name): def begin(self, name):
self.print( self.print(
@ -311,7 +278,14 @@ class Analyser:
"Binary size", "Binary size",
) )
self.print( self.print(
"", ".text", ".data", ".rodata", ".bss", "heap + stack", ".irom0.text", ""
"",
".text + .text1",
".data",
".rodata",
".bss",
"heap + stack",
".irom0.text",
"",
) )
self.print_delimiters() self.print_delimiters()
self.baseline = self.run() self.baseline = self.run()
@ -320,12 +294,12 @@ class Analyser:
def print_values(self, header, values): def print_values(self, header, values):
self.print( self.print(
header, header,
values["text"],
values["data"],
values["rodata"],
values["bss"],
values[".text"],
values[".data"],
values[".rodata"],
values[".bss"],
values["free"], values["free"],
values["irom0_text"],
values[".irom0.text"],
values["size"], values["size"],
) )
@ -334,43 +308,38 @@ class Analyser:
def print_compare(self, header, values): def print_compare(self, header, values):
self.print( self.print(
header, header,
values["text"] - self.baseline["text"],
values["data"] - self.baseline["data"],
values["rodata"] - self.baseline["rodata"],
values["bss"] - self.baseline["bss"],
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["free"] - self.baseline["free"],
values["irom0_text"] - self.baseline["irom0_text"],
values[".irom0.text"] - self.baseline[".irom0.text"],
values["size"] - self.baseline["size"], values["size"] - self.baseline["size"],
) )
def run(self): def run(self):
run(self._platformio_prefix, self._environment, self.modules, self._debug) run(self._platformio_prefix, self._environment, self.modules, self._debug)
values = analyse_memory(self._elf_path, objdump_path(self._toolchain_prefix))
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 = 80 * 1024 - values[".data"] - values[".rodata"] - values[".bss"]
free = free + (16 - free % 16) free = free + (16 - free % 16)
values["free"] = free values["free"] = free
values["size"] = file_size(self._bin_path)
values["size"] = file_size(bin_path)
return values return values
_debug = False
_platformio_prefix = None
_toolchain_prefix = None
_environment = None
_bin_path = None
_elf_path = None
modules = None
baseline = None
def main(args): def main(args):
# Check xtensa-lx106-elf-objdump is in the path
objdump_check(args)
# Check xtensa-lx106-elf-size is in the path
size_binary_exists(args)
# Which modules to test? # Which modules to test?
configuration, modules = get_modules(args) configuration, modules = get_modules(args)


Loading…
Cancel
Save