diff options
Diffstat (limited to 'circuitpython/tools/gc_activity.py')
-rw-r--r-- | circuitpython/tools/gc_activity.py | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/circuitpython/tools/gc_activity.py b/circuitpython/tools/gc_activity.py new file mode 100644 index 0000000..6a1772f --- /dev/null +++ b/circuitpython/tools/gc_activity.py @@ -0,0 +1,118 @@ +# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) +# +# SPDX-License-Identifier: MIT + +import sys +import json + +# Map start block to current allocation info. +current_heap = {} +allocation_history = [] +root = {} + + +def change_root(trace, size): + level = root + for frame in reversed(trace): + file_location = frame[1] + if file_location not in level: + level[file_location] = { + "blocks": 0, + "file": file_location, + "function": frame[2], + "subcalls": {}, + } + level[file_location]["blocks"] += size + level = level[file_location]["subcalls"] + + +total_actions = 0 +with open(sys.argv[1], "r") as f: + for line in f: + if not line.strip(): + break + for line in f: + action = None + if line.startswith("Breakpoint 2"): + break + next(f) # throw away breakpoint code line + next(f) # first frame + block = 0 + size = 0 + trace = [] + for line in f: + # print(line.strip()) + if line[0] == "#": + frame = line.strip().split() + if frame[1].startswith("0x"): + trace.append((frame[1], frame[-1], frame[3])) + else: + trace.append(("0x0", frame[-1], frame[1])) + elif line[0] == "$": + block = int(line.strip().split()[-1][2:], 16) + size = int(next(f).strip().split()[-1][2:], 16) + if not line.strip(): + break + + action = "unknown" + if block not in current_heap: + current_heap[block] = { + "start_block": block, + "size": size, + "start_trace": trace, + "start_time": total_actions, + } + action = "alloc" + change_root(trace, size) + else: + alloc = current_heap[block] + alloc["end_trace"] = trace + alloc["end_time"] = total_actions + change_root(alloc["start_trace"], -1 * alloc["size"]) + if size > 0: + action = "realloc" + current_heap[block] = { + "start_block": block, + "size": size, + "start_trace": trace, + "start_time": total_actions, + } + change_root(trace, size) + else: + action = "free" + if trace[0][2] == "gc_sweep": + action = "sweep" + del current_heap[block] + alloc["end_cause"] = action + allocation_history.append(alloc) + print(total_actions, action, block, size) + total_actions += 1 + +print() + +for alloc in current_heap.values(): + alloc["end_trace"] = "" + alloc["end_time"] = total_actions + allocation_history.append(alloc) + + +def print_frame(frame, indent=0): + for key in sorted(frame): + if ( + not frame[key]["blocks"] + or key.startswith("../py/malloc.c") + or key.startswith("../py/gc.c") + ): + continue + print(" " * (indent - 1), key, frame[key]["function"], frame[key]["blocks"], "blocks") + print_frame(frame[key]["subcalls"], indent + 2) + + +print_frame(root) +total_blocks = 0 +for key in sorted(root): + total_blocks += root[key]["blocks"] +print(total_blocks, "total blocks") + +with open("allocation_history.json", "w") as f: + json.dump(allocation_history, f) |