mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-27 19:57:38 +00:00
227 lines
6.1 KiB
Python
Executable File
227 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
########################################################
|
|
#
|
|
# ESPEasy plugin memory analyser
|
|
# edwin@datux.nl
|
|
#
|
|
###
|
|
# Based on:
|
|
# https://raw.githubusercontent.com/SmingHub/Sming/develop/tools/memanalyzer.py
|
|
# Memory Analyzer
|
|
# Author: Slavey Karadzhov <slav@attachix.com>
|
|
# Based on https://github.com/Sermus/ESP8266_memory_analyzer
|
|
#
|
|
########################################################
|
|
from collections import OrderedDict
|
|
import os.path
|
|
import shlex
|
|
import subprocess
|
|
import sys
|
|
import glob
|
|
import os
|
|
|
|
TOTAL_IRAM = 32786;
|
|
TOTAL_DRAM = 81920;
|
|
|
|
sections = OrderedDict([
|
|
("data", "Initialized Data (RAM)"),
|
|
("rodata", "ReadOnly Data (RAM)"),
|
|
("bss", "Uninitialized Data (RAM)"),
|
|
("text", "Cached Code (IRAM)"),
|
|
("irom0_text", "Uncached Code (SPI)")
|
|
])
|
|
|
|
|
|
def abort(txt):
|
|
raise(Exception("error: "+txt))
|
|
|
|
def analyse_memory(elfFile):
|
|
command = "%s -t '%s' " % (objectDumpBin, elfFile)
|
|
response = subprocess.check_output(shlex.split(command))
|
|
if isinstance(response, bytes):
|
|
response = response.decode('utf-8')
|
|
lines = response.split('\n')
|
|
|
|
# print("{0: >10}|{1: >30}|{2: >12}|{3: >12}|{4: >8}".format("Section", "Description", "Start (hex)", "End (hex)", "Used space"));
|
|
# print("------------------------------------------------------------------------------");
|
|
ret={}
|
|
usedRAM = 0
|
|
usedIRAM = 0
|
|
|
|
i = 0
|
|
for (id, descr) in list(sections.items()):
|
|
sectionStartToken = " _%s_start" % id
|
|
sectionEndToken = " _%s_end" % id
|
|
sectionStart = -1
|
|
sectionEnd = -1
|
|
for line in lines:
|
|
if sectionStartToken in line:
|
|
data = line.split(' ')
|
|
sectionStart = int(data[0], 16)
|
|
|
|
if sectionEndToken in line:
|
|
data = line.split(' ')
|
|
sectionEnd = int(data[0], 16)
|
|
|
|
if sectionStart != -1 and sectionEnd != -1:
|
|
break
|
|
|
|
sectionLength = sectionEnd - sectionStart
|
|
# if i < 3:
|
|
# usedRAM += sectionLength
|
|
# if i == 3:
|
|
# usedIRAM = TOTAL_IRAM - sectionLength;
|
|
|
|
ret[id]=sectionLength
|
|
# print("{0: >10}|{1: >30}|{2:12X}|{3:12X}|{4:8}".format(id, descr, sectionStart, sectionEnd, sectionLength))
|
|
# i += 1
|
|
|
|
# print("Total Used RAM : %d" % usedRAM)
|
|
# print("Free RAM : %d" % (TOTAL_DRAM - usedRAM))
|
|
# print("Free IRam : %d" % usedIRAM)
|
|
return(ret)
|
|
|
|
# reenable all plugins and libs
|
|
def enable_all():
|
|
|
|
for plugin in glob.glob(".src/*"):
|
|
os.rename(plugin, "src/"+os.path.basename(plugin))
|
|
|
|
for lib in glob.glob(".lib/*"):
|
|
os.rename(lib, "lib/"+os.path.basename(lib))
|
|
|
|
def disable_plugin(plugin):
|
|
os.rename(plugin, ".src/"+os.path.basename(plugin))
|
|
|
|
def enable_plugin(plugin):
|
|
os.rename(".src/"+os.path.basename(plugin), plugin)
|
|
|
|
def disable_lib(lib):
|
|
os.rename(lib, ".lib/"+os.path.basename(lib))
|
|
|
|
def enable_lib(lib):
|
|
os.rename(".lib/"+os.path.basename(lib), lib)
|
|
|
|
|
|
try:
|
|
|
|
|
|
if not os.path.exists(".src"):
|
|
os.mkdir(".src")
|
|
|
|
if not os.path.exists(".lib"):
|
|
os.mkdir(".lib")
|
|
|
|
|
|
################### start
|
|
if len(sys.argv) < 1:
|
|
print("Usage: \n\t%s%s <path_to_objdump>" % sys.argv[0])
|
|
sys.exit(1)
|
|
|
|
objectDumpBin = sys.argv[1]
|
|
|
|
output_format="{:<30}|{:<11}|{:<11}|{:<11}|{:<11}|{:<11}"
|
|
print(output_format.format(
|
|
"plugin",
|
|
"cache IRAM",
|
|
"init RAM",
|
|
"r.o. RAM",
|
|
"uninit RAM",
|
|
"Flash ROM",
|
|
))
|
|
|
|
|
|
enable_all()
|
|
|
|
|
|
#get list of all plugins
|
|
plugins=glob.glob("src/_[CPN]*.ino")
|
|
plugins.sort()
|
|
|
|
#get list of all libs
|
|
libs=glob.glob("lib/*")
|
|
libs.remove("lib/pubsubclient")
|
|
libs.sort()
|
|
|
|
|
|
#### disable all plugins and to get base size
|
|
for plugin in plugins:
|
|
disable_plugin(plugin)
|
|
|
|
# for lib in libs:
|
|
# disable_lib(lib)
|
|
|
|
#build without plugins to get base memory usage
|
|
subprocess.check_call("platformio run --silent --environment dev_4096", shell=True)
|
|
#two times, sometimes it changes a few bytes somehow
|
|
subprocess.check_call("platformio run --silent --environment dev_4096", shell=True)
|
|
base=analyse_memory(".pioenvs/dev_4096/firmware.elf")
|
|
|
|
|
|
# note: unused libs never use any memory, so dont have to test this
|
|
# ##### test per lib
|
|
# results={}
|
|
# for lib in libs:
|
|
# enable_lib(lib)
|
|
# subprocess.check_call("platformio run --silent --environment dev_4096", shell=True)
|
|
# results[lib]=analyse_memory(".pioenvs/dev_4096/firmware.elf")
|
|
# disable_lib(lib)
|
|
#
|
|
# print(output_format.format(
|
|
# lib,
|
|
# results[lib]['text']-base['text'],
|
|
# results[lib]['data']-base['data'],
|
|
# results[lib]['rodata']-base['rodata'],
|
|
# results[lib]['bss']-base['bss'],
|
|
# results[lib]['irom0_text']-base['irom0_text'],
|
|
# ))
|
|
|
|
|
|
#which plugins to test?
|
|
if len(sys.argv)>2:
|
|
test_plugins=sys.argv[2:]
|
|
else:
|
|
test_plugins=plugins
|
|
test_plugins.sort()
|
|
|
|
|
|
|
|
##### test per plugin
|
|
results={}
|
|
for plugin in test_plugins:
|
|
enable_plugin(plugin)
|
|
subprocess.check_call("platformio run --silent --environment dev_4096", shell=True)
|
|
results[plugin]=analyse_memory(".pioenvs/dev_4096/firmware.elf")
|
|
disable_plugin(plugin)
|
|
|
|
print(output_format.format(
|
|
plugin,
|
|
results[plugin]['text']-base['text'],
|
|
results[plugin]['data']-base['data'],
|
|
results[plugin]['rodata']-base['rodata'],
|
|
results[plugin]['bss']-base['bss'],
|
|
results[plugin]['irom0_text']-base['irom0_text'],
|
|
))
|
|
|
|
|
|
|
|
##### test with all test_plugins at once
|
|
for plugin in test_plugins:
|
|
enable_plugin(plugin)
|
|
|
|
subprocess.check_call("platformio run --silent --environment dev_4096", shell=True)
|
|
total=analyse_memory(".pioenvs/dev_4096/firmware.elf")
|
|
|
|
print(output_format.format(
|
|
"ALL",
|
|
total['text']-base['text'],
|
|
total['data']-base['data'],
|
|
total['rodata']-base['rodata'],
|
|
total['bss']-base['bss'],
|
|
total['irom0_text']-base['irom0_text'],
|
|
))
|
|
except:
|
|
enable_all()
|
|
|
|
raise
|