Skip to content

Commit a8fbad5

Browse files
committed
Add heap analysis scripts based on GDB breakpoint logs.
1 parent ea1320b commit a8fbad5

5 files changed

Lines changed: 485 additions & 0 deletions

File tree

py/gc.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@
102102
#define GC_EXIT()
103103
#endif
104104

105+
#ifdef LOG_HEAP_ACTIVITY
106+
volatile uint32_t change_me;
107+
108+
void __attribute__ ((noinline)) gc_log_change(uint32_t start_block, uint32_t length) {
109+
change_me += start_block;
110+
change_me += length; // Break on this line.
111+
}
112+
#endif
113+
105114
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
106115
void gc_init(void *start, void *end) {
107116
// align end pointer on block boundary
@@ -278,6 +287,10 @@ STATIC void gc_sweep(void) {
278287
#endif
279288
free_tail = 1;
280289
DEBUG_printf("gc_sweep(%x)\n", PTR_FROM_BLOCK(block));
290+
291+
#ifdef LOG_HEAP_ACTIVITY
292+
gc_log_change(block, 0);
293+
#endif
281294
#if MICROPY_PY_GC_COLLECT_RETVAL
282295
MP_STATE_MEM(gc_collected)++;
283296
#endif
@@ -470,6 +483,10 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser) {
470483
MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB;
471484
}
472485

486+
#ifdef LOG_HEAP_ACTIVITY
487+
gc_log_change(start_block, end_block - start_block + 1);
488+
#endif
489+
473490
// mark first block as used head
474491
ATB_FREE_TO_HEAD(start_block);
475492

@@ -556,6 +573,9 @@ void gc_free(void *ptr) {
556573
}
557574

558575
// free head and all of its tail blocks
576+
#ifdef LOG_HEAP_ACTIVITY
577+
gc_log_change(block, 0);
578+
#endif
559579
do {
560580
ATB_ANY_TO_FREE(block);
561581
block += 1;
@@ -715,6 +735,10 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
715735
gc_dump_alloc_table();
716736
#endif
717737

738+
#ifdef LOG_HEAP_ACTIVITY
739+
gc_log_change(block, new_blocks);
740+
#endif
741+
718742
return ptr_in;
719743
}
720744

@@ -740,6 +764,10 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
740764
gc_dump_alloc_table();
741765
#endif
742766

767+
#ifdef LOG_HEAP_ACTIVITY
768+
gc_log_change(block, new_blocks);
769+
#endif
770+
743771
return ptr_in;
744772
}
745773

tools/gc_activity.html

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<style>
6+
7+
html, body, svg {
8+
margin: 0px;
9+
min-height: 100%;
10+
height: 100%;
11+
width: 100%;
12+
}
13+
14+
.chart rect {
15+
fill: steelblue;
16+
}
17+
18+
.axis text {
19+
font: 10px sans-serif;
20+
}
21+
22+
.axis path,
23+
.axis line {
24+
fill: none;
25+
stroke: #000;
26+
shape-rendering: crispEdges;
27+
}
28+
29+
div.tooltip {
30+
position: absolute;
31+
# text-align: center;
32+
# width: 60px;
33+
# height: 28px;
34+
padding: 2px;
35+
font: 12px sans-serif;
36+
background: lightsteelblue;
37+
border: 0px;
38+
}
39+
40+
</style>
41+
</head>
42+
<body>
43+
<svg class="chart"></svg>
44+
<script src="https://d3js.org/d3.v4.js"></script>
45+
<script>
46+
var barHeight = 2;
47+
48+
var chart = d3.select(".chart");
49+
50+
var margin = {top: 20, right: 30, bottom: 30, left: 40},
51+
width = chart.style("width").replace("px", "") - margin.left - margin.right,
52+
height = chart.style("height").replace("px", "") - margin.top - margin.bottom;
53+
54+
var x = d3.scaleLinear().range([0, width]);
55+
var y = d3.scaleLinear().range([0, height]);
56+
57+
var chart = chart.append("g")
58+
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
59+
60+
var xAxis = d3.axisBottom().scale(x);
61+
var yAxis = d3.axisLeft().scale(y);
62+
63+
var div = d3.select("body").append("div")
64+
.attr("class", "tooltip")
65+
.style("opacity", 0);
66+
67+
d3.json("/allocation_history.json", function(error, data) {
68+
console.log(data[0]);
69+
x.domain([0, d3.max(data, function(d) { return d.end_time; })]);
70+
y.domain([0, d3.max(data, function(d) { return d.start_block + d.size; })]);
71+
72+
chart.append("g")
73+
.attr("class", "x axis")
74+
.attr("transform", "translate(0," + height + ")")
75+
.call(xAxis);
76+
77+
chart.append("g")
78+
.attr("class", "y axis")
79+
.call(yAxis);
80+
81+
var bar = chart.selectAll("g")
82+
.data(data)
83+
.enter().append("g")
84+
.attr("transform", function(d, i) { return "translate(" + x(d.start_time) + "," + y(d.start_block) + ")"; });
85+
86+
bar.append("rect")
87+
.attr("width", function(d) { return x(d.end_time - d.start_time); })
88+
.attr("height", function(d) { return y(d.size) - 1; })
89+
.on("mouseover", function(d) {
90+
var trace = "";
91+
for (var i = 0, len = d.start_trace.length; i < len; i++) {
92+
var frame = d.start_trace[i];
93+
trace += frame[2] + " " + frame[1] + "<br/>";
94+
}
95+
trace += "<br/>End Trace:<br/>";
96+
for (var i = 0, len = d.end_trace.length; i < len; i++) {
97+
var frame = d.end_trace[i];
98+
trace += frame[2] + " " + frame[1] + "<br/>";
99+
}
100+
var side = "left";
101+
var other_side = "right";
102+
var pos_x = x(d.start_time) + margin.left;
103+
if (width - pos_x < 300) {
104+
side = "right";
105+
other_side = "left";
106+
pos_x = width - x(d.start_time) + margin.right;
107+
}
108+
var pos_y = (height - y(d.start_block) + margin.bottom)
109+
var edge = "bottom";
110+
var other_edge = "top";
111+
if ((height - pos_y) < 300) {
112+
edge = "top";
113+
other_edge = "bottom";
114+
pos_y = y(d.start_block) + margin.top + y(d.size);
115+
}
116+
div.style("opacity", 1)
117+
.html("Start block: " + d.start_block + " Size: " + d.size + " blocks<br/><br/>" + trace)
118+
.style(side, pos_x + "px")
119+
.style(other_side, null)
120+
.style(edge, pos_y + "px")
121+
.style(other_edge, null);
122+
});
123+
124+
// bar.append("text")
125+
// .attr("x", function(d) { return x(d.value) - 3; })
126+
// .attr("y", barHeight / 2)
127+
// .attr("dy", ".35em")
128+
// .text(function(d) { return d.value; });
129+
});
130+
131+
function type(d) {
132+
d.value = +d.value; // coerce to number
133+
return d;
134+
}
135+
</script>
136+
</body>
137+
</html>

0 commit comments

Comments
 (0)