commit 475777eaa2715294c014b2333b23b29e9c5083f3 from: Matthias L. Jugel via: GitHub date: Mon Feb 19 15:30:20 2018 UTC Create memtrace-calliope.py commit - 03569a2079440017ffe4956b5a569425f51dc8f1 commit + 475777eaa2715294c014b2333b23b29e9c5083f3 blob - /dev/null blob + 232f8f4134a6d2b32c404995632a116bd405e28c (mode 644) --- /dev/null +++ memtrace-calliope.py @@ -0,0 +1,101 @@ +""" +A simple mbed memtrace log extractor, calculating allocated memory. + +Author: Matthias L. Jugel (@thinkberg) + +Prerequisites: + pip install pygtail + +Usage: + python memtrace.py log-file mem-reset-keyword + + The script will tail the log file and reset the memory counter when + the mem-reset-keyword occurs. + + a) enable memory tracing in your embedded program (config.json): + ``` + { + "microbit-dal": { + "debug": 1, + "heap": { + "debug": 1 + } + } + } + ``` + + b) Log into a file: + `$ miniterm.py /dev/cu.usbmodem142111 9600 | tee memtrace.log` + + c) Analyze log file (tails the log file) + python -u bin/memtrace.py memtrace.log SHCSR + + If the analyzer behaves strangely, delete the "log-file.offset" file. +""" + +import re +import sys + +import time + +from pygtail import Pygtail + +mem = {} +allocated = 0 + +reset = None +if len(sys.argv) > 1: + reset = sys.argv[2] + print "RESETTING tracer on '%s'" % reset + +r_malloc = re.compile("^(microbit_)malloc:\\s+(NATIVE\\s+)?(ALLOCATED:)\\s+(\\d+)\\s+\\[(0x[0-9a-f]+)\\]") +r_free = re.compile("^(microbit_)free:\\s+(0x[0-9a-f]+)") + +partial = "" +while True: + for line in Pygtail(sys.argv[1]): + # we sometimes get incomplete lines, wait for a full line + if not (line[-1] == '\n' or line[-1] == '\r'): + partial = line + continue + else: + line = partial + line + partial = "" + + # strip newline and carriage return + line = line.rstrip('\n').rstrip('\r') + + # if we detect the reset keyword, rest the map and memory counter + if reset in line: + mem = {} + allocated = 0 + print "\n\n\033[91m>> RESET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m" + + # match malloc, realloc and free + m = r_malloc.search(line) + if m: + mem[m.group(5)] = int(m.group(4)) + allocated += int(m.group(4)) + print "\033[1m== (%03d) \033[34m%8d\033[0m [%8x] \033[31m+%-6d\033[0m (%s)" % \ + (len(mem), allocated, allocated, int(m.group(4)), + m.group(0).replace(m.group(1), "").replace(m.group(3), "")) + continue + + m = r_free.search(line) + if m: + # print "f", m.group(3) + freed = 0 + if mem.has_key(m.group(2)): + freed = mem[m.group(2)] + allocated -= freed + del mem[m.group(2)] + else: + print "\033[33m!! WARN: free(%s)\033[0m" % m.group(1) + print "\033[1m== (%03d) \033[34m%8d\033[0m [%8x] \033[92m-%-6d\033[0m (%s)" % \ + (len(mem), allocated, allocated, freed, m.group(0).replace(m.group(1), "")) + continue + + # print all other lines as is, so we can still use the log functionality + print line + sys.stdout.flush() + time.sleep(1)