mbed memory usage
Page last updated
23 Jan 2010, by
Igor Skochinsky.
6
replies
Inspired by this thread.
Since mbed's startup code is quite standard, it's possible to parse it with a little work. I made a Python script which looks for the scatter region table and calculates some values from it.
# script to print memory usage stats for binaries produced by mbed online compiler
# Version 1.0, 2010-01-23
# Author: Igor Skochinsky
import sys, struct
RAM_START = 0x10000000
RAM_SIZE = 0x00008000 # 32K
FLASH_SIZE = 0x00080000 # 512K
# read a 4-byte dword (little-endian) from file
def getDword(f, off):
f.seek(off)
data = f.read(4)
if len(data) != 4:
print "Trying to read ouside the file!"
return 0
return struct.unpack("<I", data)[0]
class RegionEntry:
def __init__(self, f, off):
f.seek(off)
data = f.read(4*4)
if len(data) != 4*4:
print "Trying to read ouside the file!"
return
values = struct.unpack("<IIII", data)
self.source = values[0]
self.dest = values[1]
self.size = values[2]
self.func = values[3]
def show_stats(f):
sp = getDword(f, 0)
if sp != RAM_START + RAM_SIZE:
print "Warning: stack pointer (%08X) is different from expected value (%08X)" % (sp, RAM_START + RAM_SIZE)
entry = getDword(f, 4)
print "Entry point address: %08X" % entry
if entry & 1 != 1:
print "Doesn't look like a Cortex-M3 binary"
return
entry &= ~1
f.seek(entry)
startup = f.read(8)
# ldr r0, =HWInit
# blx r0
# ldr r0, =__main
# bx r0
if startup != "\x06\x48\x80\x47\x06\x48\x00\x47":
print "Wrong startup code, probably not an mbed 1768 binary"
return
__main = getDword(f, entry + 0x20) & ~1
f.seek(__main)
if f.read(4) != "\x00\xF0\x02\xF8":
print "Wrong startup code, probably not an mbed 1768 binary"
return
#fetch scatter region table pointers
tblptrs = __main+0x34
tblstart = getDword(f, tblptrs) + tblptrs
tblend = getDword(f, tblptrs+4) + tblptrs
tblsize = tblend - tblstart
tblentries = tblsize / 16
if tblsize % 16 != 0 or tblentries == 0 or tblentries > 2:
print "Wrong size of scatter region table (%d entries)" % tblentries
return
entry1 = RegionEntry(f, tblstart)
# first entry sets up RW data
# so its src address will be code + RO data size
code_rodata = entry1.source
# size will be the size of RW data
rwdata = entry1.size
if tblentries == 2:
# second entry sets up ZI data
# its "source" will be the total flash size, but we'll just use the file size
entry2 = RegionEntry(f, tblstart+16)
zidata = entry2.size
else:
# no ZI data
zidata = 0
usedram = rwdata + zidata
f.seek(0, 2)
usedflash = f.tell()
print "Code + RO data = %-7d (0x%05x)" % (code_rodata, code_rodata)
print "RW data = %-7d (0x%05x)" % (rwdata, rwdata)
print "ZI data = %-7d (0x%05x)" % (zidata, zidata)
print "Used flash = %-7d (0x%05x)" % (usedflash, usedflash)
print "Free flash = %-7d (0x%05x)" % (FLASH_SIZE - usedflash, FLASH_SIZE - usedflash)
print "Used RAM = %-7d (0x%05x)" % (usedram, usedram)
print "Free RAM = %-7d (0x%05x)" % (RAM_SIZE - usedram, RAM_SIZE - usedram)
print "mbed 1768 binary stats script 1.0"
if len(sys.argv) >= 2:
inf = open(sys.argv[1],"rb")
show_stats(inf)
else:
print "Usage: binstats.py file.bin"
Save it as binstats.py and pass the binary filename as the parameter. If you need to install it, get Python 2.x, not 3.x.
Please note that the reported sizes are before any C/C++ startup code is executed, so any RAM used by CRT (e.g. malloc structures) or global objects is not included. Also, the stack occupies the top of the RAM and overwriting it is not a good idea.
Example stats for some programs:
FFT.bin:
Entry point address: 00000215
Code + RO data = 43568 (0x0aa30)
RW data = 240 (0x000f0)
ZI data = 380 (0x0017c)
Used flash = 43808 (0x0ab20)
Free flash = 480480 (0x754e0)
Used RAM = 620 (0x0026c)
Free RAM = 32148 (0x07d94)
DOGLCDDemo.bin:
Entry point address: 00000255
Code + RO data = 36128 (0x08d20)
RW data = 2528 (0x009e0)
ZI data = 1720 (0x006b8)
Used flash = 36616 (0x08f08)
Free flash = 487672 (0x770f8)
Used RAM = 4248 (0x01098)
Free RAM = 28520 (0x06f68)
Hi Igor
I compiled the EthernetTester from this notebook and ran the script with the following outcome:
mbed 1768 binary stats script 1.0
Entry point address: 00000261
Wrong size of scatter region table (3 entries)
Is this due to two libraries being linked (mbed and lwip)?
Thanks
Daniel
Hi Igor,
I ran the script on a program with three libraries (FATFileSystem, mbed and lwip) and got exactly the same result as Daniel.
Paul
For what it's worth, I had the same issue with the script mentioned above, and dug into it because I wanted to know whether I had a RAM usage problem or not, and just how much I really had left if there wasn't really a problem.
As mentioned in other places, the MBED compiler report of RAM usage is not correct if the AHB SRAM memory banks are used, which apparently the EthernetInterface does. The LCP1768 has two 16K AHB SRAM banks in addition to the 32K bank in the CPU. So while MBED docs show the 1768 has only 32K of RAM, the spec sheets say it has 64K.
When the AHB SRAM banks are used, there are extra table entries in the bin file, which is why the above script bombed out when used on a program that uses EthernetInterface.
I modified the script to report usage by RAM block (CPU, AHB0, and AHB1), and the modified code is pasted below. Example results with this modified script appear as follows:
mbed 1768 binary stats script 2.0
Entry point address: 000002C5
Region 1: source=0x000129C8, dest=0x100000C8, size= 720, func= 256
Region 2: source=0x00012A08, dest=0x2007C000, size= 16384, func= 256
Region 3: source=0x00012A8C, dest=0x20080000, size= 11220, func= 256
Region 4: source=0x00012A08, dest=0x10000398, size= 10348, func= 316
Used flash = 76520 (0x12ae8)
Free flash = 447768 (0x6d518)
CPU RAM Used = 11068 (0x02b3c)
CPU Free RAM = 21700 (0x054c4)
AHB0 RAM Used = 16384 (0x04000)
AHB0 Free RAM = 0 (0x00000)
AHB1 RAM Used = 11220 (0x02bd4)
AHB1 Free RAM = 5164 (0x0142c)
The modified script follows:
# script to print memory usage stats for binaries produced by mbed online compiler
# Version 1.0, 2013-07-26 Author: Igor Skochinsky
# Version 2.0, 2013-07-26 Modifications by John VanLaanen
# Based on an the oroginal script by Igor Skochinsky copied from: http://mbed.org/users/igorsk/notebook/mbed-memory-usage/
import sys, struct
# Memory map for the LCP1768
RAM_START = 0x10000000
RAM_SIZE = 0x00008000 # 32K
RAM_END = RAM_START + RAM_SIZE - 1
AHB0_START = 0x2007c000
AHB0_SIZE = 0x4000 # 16K
AHB0_END = AHB0_START + AHB0_SIZE - 1
AHB1_START = 0x20080000
AHB1_SIZE = 0x4000 # 16K
AHB1_END = AHB1_START + AHB1_SIZE - 1
FLASH_SIZE = 0x00080000 # 512K
# read a 4-byte dword (little-endian) from file
def getDword(f, off):
f.seek(off)
data = f.read(4)
if len(data) != 4:
print "Trying to read ouside the file!"
return 0
return struct.unpack("= RAM_START) and (entryn.dest <= RAM_END):
ram_used += entryn.size
elif (entryn.dest >= AHB0_START) and (entryn.dest <= AHB0_END):
ahb0_used += entryn.size
elif (entryn.dest >= AHB1_START) and (entryn.dest <= AHB1_END):
ahb1_used += entryn.size
else:
print("Region %d in an unknown memory location" % ii)
print('Region %d: source=0x%08X, dest=0x%08X, size=%8d, func=%4d' % \
(ii+1, entryn.source, entryn.dest, entryn.size, entryn.func) )
f.seek(0, 2)
usedflash = f.tell()
print("\n")
print "Used flash = %-7d (0x%05x)" % (usedflash, usedflash)
print "Free flash = %-7d (0x%05x)\n" % (FLASH_SIZE - usedflash, FLASH_SIZE - usedflash)
print "CPU RAM Used = %-7d (0x%05x)" % (ram_used, ram_used)
print "CPU Free RAM = %-7d (0x%05x)\n" % (RAM_SIZE - ram_used, RAM_SIZE - ram_used)
print "AHB0 RAM Used = %-7d (0x%05x)" % (ahb0_used, ahb0_used)
print "AHB0 Free RAM = %-7d (0x%05x)\n" % (AHB0_SIZE - ahb0_used, AHB0_SIZE - ahb0_used)
print "AHB1 RAM Used = %-7d (0x%05x)" % (ahb1_used, ahb1_used)
print "AHB1 Free RAM = %-7d (0x%05x)" % (AHB1_SIZE - ahb1_used, AHB1_SIZE - ahb1_used)
print "mbed 1768 binary stats script 2.0\n"
if len(sys.argv) >= 2:
inf = open(sys.argv[1],"rb")
show_stats(inf)
else:
print "Usage: MBED_binstats.py file.bin"
Something happened with the previous post and the script got corrupted. I tried it again and the same thing happened. If anyone wants the modified script, please contact me at johnvanlaanen@gmail.com
Something happened with the previous post and the script got corrupted. I tried it again and the same thing happened. If anyone wants the modified script, please contact me at johnvanlaanen@gmail.com
Could you share it on pastebin or any similar service available, just paste the link here, that would be much better than privately shared through an email.
Regards,
0xc0170
#
11 Jan 2016 . Edited: 11 Jan 2016
John VanLaanen sent me his script which I have modified to work with Python 3.
{{{
<>
# script to print memory usage stats for binaries produced by mbed online compiler
# Version 1.0, 2013-07-26 Author: Igor Skochinsky
# Version 2.0, 2013-07-26 Modifications by John VanLaanen
# Version 2.1, 2016-01-11 Modifications by David Pairman
# Based on an the oroginal script by Igor Skochinsky copied from: http://mbed.org/users/igorsk/notebook/mbed-memory-usage/
import sys, struct
# Memory map for the LCP1768
RAM_START = 0x10000000
RAM_SIZE = 0x00008000 # 32K
RAM_END = RAM_START + RAM_SIZE - 1
AHB0_START = 0x2007c000
AHB0_SIZE = 0x4000 # 16K
AHB0_END = AHB0_START + AHB0_SIZE - 1
AHB1_START = 0x20080000
AHB1_SIZE = 0x4000 # 16K
AHB1_END = AHB1_START + AHB1_SIZE - 1
FLASH_SIZE = 0x00080000 # 512K
# read a 4-byte dword (little-endian) from file
def getDword(f, off):
f.seek(off)
data = f.read(4)
if len(data) != 4:
print("Trying to read ouside the file!")
return 0
return struct.unpack("= RAM_START) and (entryn.dest <= RAM_END):
ram_used += entryn.size
elif (entryn.dest >= AHB0_START) and (entryn.dest <= AHB0_END):
ahb0_used += entryn.size
elif (entryn.dest >= AHB1_START) and (entryn.dest <= AHB1_END):
ahb1_used += entryn.size
else:
print("Region %d in an unknown memory location" % ii)
print('Region %d: source=0x%08X, dest=0x%08X, size=%8d, func=%4d' % \
(ii+1, entryn.source, entryn.dest, entryn.size, entryn.func) )
f.seek(0, 2)
usedflash = f.tell()
print("\n")
print("Used flash = %-7d (0x%05x)" % (usedflash, usedflash))
print("Free flash = %-7d (0x%05x)\n" % (FLASH_SIZE - usedflash, FLASH_SIZE - usedflash))
print("CPU RAM Used = %-7d (0x%05x)" % (ram_used, ram_used))
print("CPU Free RAM = %-7d (0x%05x)\n" % (RAM_SIZE - ram_used, RAM_SIZE - ram_used))
print("AHB0 RAM Used = %-7d (0x%05x)" % (ahb0_used, ahb0_used))
print("AHB0 Free RAM = %-7d (0x%05x)\n" % (AHB0_SIZE - ahb0_used, AHB0_SIZE - ahb0_used))
print("AHB1 RAM Used = %-7d (0x%05x)" % (ahb1_used, ahb1_used))
print("AHB1 Free RAM = %-7d (0x%05x)" % (AHB1_SIZE - ahb1_used, AHB1_SIZE - ahb1_used))
print("mbed 1768 binary stats script 2.0\n")
if len(sys.argv) >= 2:
inf = open(sys.argv[1],"rb")
show_stats(inf)
else:
print("Usage: MBED_binstats.py file.bin")
<
>
}}}
\\linebreak
My apologies - I can't seem to get the "code" markup working as per [[https://developer.mbed.org/cookbook/Wiki-Syntax]]!!
You need to log in to post a comment
Hi Igor
I compiled the EthernetTester from this notebook and ran the script with the following outcome:
mbed 1768 binary stats script 1.0
Entry point address: 00000261
Wrong size of scatter region table (3 entries)
Is this due to two libraries being linked (mbed and lwip)?
Thanks
Daniel