Skip to content

Commit a4d197a

Browse files
committed
Update gc tracking instructions and gdb commands.
1 parent 8364c60 commit a4d197a

File tree

3 files changed

+153
-5
lines changed

3 files changed

+153
-5
lines changed

tools/gc_activity.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ correct port. GDB is usually :3333 and JLink is :2331.
1313
Now, run gdb from your port directory:
1414

1515
```
16-
arm-none-eabi-gdb -x ../tools/output_gc_until_repl.txt build-metro_m0_express/firmware.elf
16+
arm-none-eabi-gdb -x ../../tools/output_gc_until_repl.txt build-metro_m0_express/firmware.elf
1717
```
1818

1919
This will take a little time while it breaks, backtraces and continues for every

tools/gc_activity_between_collects.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import sys
2+
import json
3+
4+
# Map start block to current allocation info.
5+
current_heap = {}
6+
allocation_history = []
7+
root = {}
8+
9+
def change_root(trace, size):
10+
level = root
11+
for frame in reversed(trace):
12+
file_location = frame[1]
13+
if file_location not in level:
14+
level[file_location] = {"blocks": 0,
15+
"file": file_location,
16+
"function": frame[2],
17+
"subcalls": {}}
18+
level[file_location]["blocks"] += size
19+
level = level[file_location]["subcalls"]
20+
21+
total_actions = 0
22+
non_single_block_streak = 0
23+
max_nsbs = 0
24+
last_action = None
25+
last_total_actions = 0
26+
count = 0
27+
actions = {}
28+
last_ticks_ms = 0
29+
ticks_ms = 0
30+
block_sizes = {}
31+
allocation_sources = {}
32+
with open(sys.argv[1], "r") as f:
33+
for line in f:
34+
if not line.strip():
35+
break
36+
for line in f:
37+
action = None
38+
if line.startswith("Breakpoint 2"):
39+
break
40+
next(f) # throw away breakpoint code line
41+
# print(next(f)) # first frame
42+
block = 0
43+
size = 0
44+
trace = []
45+
for line in f:
46+
# print(line.strip())
47+
if line[0] == "#":
48+
frame = line.strip().split()
49+
if frame[1].startswith("0x"):
50+
trace.append((frame[1], frame[-1], frame[3]))
51+
else:
52+
trace.append(("0x0", frame[-1], frame[1]))
53+
elif line[0] == "$":
54+
#print(line.strip().split()[-1])
55+
block = int(line.strip().split()[-1][2:], 16)
56+
next_line = next(f)
57+
size = int(next_line.strip().split()[-1][2:], 16)
58+
# next_line = next(f)
59+
# ticks_ms = int(next_line.strip().split()[-1][2:], 16)
60+
if not line.strip():
61+
break
62+
63+
action = "unknown"
64+
if block not in current_heap:
65+
current_heap[block] = {"start_block": block, "size": size, "start_trace": trace, "start_time": total_actions}
66+
action = "alloc"
67+
if size == 1:
68+
max_nsbs = max(max_nsbs, non_single_block_streak)
69+
non_single_block_streak = 0
70+
else:
71+
non_single_block_streak += 1
72+
#change_root(trace, size)
73+
if size not in block_sizes:
74+
block_sizes[size] = 0
75+
source = trace[-1][-1]
76+
if source not in allocation_sources:
77+
print(trace)
78+
allocation_sources[source] = 0
79+
allocation_sources[source] += 1
80+
block_sizes[size] += 1
81+
else:
82+
alloc = current_heap[block]
83+
alloc["end_trace"] = trace
84+
alloc["end_time"] = total_actions
85+
change_root(alloc["start_trace"], -1 * alloc["size"])
86+
if size > 0:
87+
action = "realloc"
88+
current_heap[block] = {"start_block": block, "size": size, "start_trace": trace, "start_time": total_actions}
89+
#change_root(trace, size)
90+
else:
91+
action = "free"
92+
if trace[0][2] == "gc_sweep":
93+
action = "sweep"
94+
non_single_block_streak = 0
95+
if (trace[3][2] == "py_gc_collect" or (trace[3][2] == "gc_deinit" and count > 1)) and last_action != "sweep":
96+
print(ticks_ms - last_ticks_ms, total_actions - last_total_actions, "gc.collect", max_nsbs)
97+
print(actions)
98+
print(block_sizes)
99+
print(allocation_sources)
100+
actions = {}
101+
block_sizes = {}
102+
allocation_sources = {}
103+
if count % 2 == 0:
104+
print()
105+
count += 1
106+
last_total_actions = total_actions
107+
last_ticks_ms = ticks_ms
108+
max_nsbs = 0
109+
del current_heap[block]
110+
alloc["end_cause"] = action
111+
allocation_history.append(alloc)
112+
if action not in actions:
113+
actions[action] = 0
114+
actions[action] += 1
115+
last_action = action
116+
#print(total_actions, non_single_block_streak, action, block, size)
117+
total_actions += 1
118+
print(actions)
119+
print(max_nsbs)
120+
print()
121+
122+
for alloc in current_heap.values():
123+
alloc["end_trace"] = ""
124+
alloc["end_time"] = total_actions
125+
allocation_history.append(alloc)
126+
127+
def print_frame(frame, indent=0):
128+
for key in sorted(frame):
129+
if not frame[key]["blocks"] or key.startswith("../py/malloc.c") or key.startswith("../py/gc.c"):
130+
continue
131+
print(" " * (indent - 1), key, frame[key]["function"], frame[key]["blocks"], "blocks")
132+
print_frame(frame[key]["subcalls"], indent + 2)
133+
134+
# print_frame(root)
135+
# total_blocks = 0
136+
# for key in sorted(root):
137+
# total_blocks += root[key]["blocks"]
138+
# print(total_blocks, "total blocks")
139+
140+
# with open("allocation_history.json", "w") as f:
141+
# json.dump(allocation_history, f)

tools/output_gc_until_repl.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,23 @@ set logging on
1010
set remote hardware-breakpoint-limit 4
1111

1212
# gc log
13-
break gc.c:103
13+
break gc.c:106
1414
commands
15-
backtrace
1615
p/x start_block
1716
p/x length
18-
append binary memory ram.bin &_srelocate &_estack
17+
p/x ticks_ms
18+
# backtrace output redirect is currently broken in gdb so we use up instead.
19+
# https://sourceware.org/bugzilla/show_bug.cgi?id=23439
20+
# backtrace
21+
up
22+
up
23+
up
24+
up
25+
# append binary memory ram.bin &_srelocate &_estack
1926
continue
2027
end
2128

22-
break main.c:179
29+
break main.c:251
2330

2431
continue
2532

0 commit comments

Comments
 (0)