Skip to content

Commit fd0ccdd

Browse files
committed
Add WASD/arrow key navigation and fix unused variable
Perfetto-style keyboard controls: A/D or left/right to pan, W/S or up/down to zoom in/out. Also removes unused active_by_addr variable flagged by ruff.
1 parent 4c843f4 commit fd0ccdd

2 files changed

Lines changed: 70 additions & 16 deletions

File tree

transformer_nuggets/utils/benchmark.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ def save_memory_snapshot(file_path: Path | str, viz: str = "torch"):
265265
html = torch.cuda._memory_viz.trace_plot(s) # type: ignore
266266
case "d3":
267267
from transformer_nuggets.utils.memory_viz import generate_memory_html
268+
268269
html = generate_memory_html(s)
269270
case _:
270271
raise ValueError(f"Unknown viz backend: {viz!r}, expected 'torch' or 'd3'")
@@ -334,6 +335,7 @@ def oom_observer(device, alloc, device_alloc, device_free):
334335
html = torch.cuda._memory_viz.trace_plot(snapshot) # type: ignore
335336
case "d3":
336337
from transformer_nuggets.utils.memory_viz import generate_memory_html
338+
337339
html = generate_memory_html(snapshot)
338340
case _:
339341
html = torch.cuda._memory_viz.trace_plot(snapshot) # type: ignore

transformer_nuggets/utils/memory_viz.py

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ def _extract_frames(frames: list[dict]) -> list[str]:
77
fn = f.get("filename", "")
88
name = f.get("name", "")
99
line = f.get("line", 0)
10-
if not name or name in ("torch::unwind::unwind()", "torch::CapturedTraceback::gather(bool, bool, bool)"):
10+
if not name or name in (
11+
"torch::unwind::unwind()",
12+
"torch::CapturedTraceback::gather(bool, bool, bool)",
13+
):
1114
continue
1215
if fn and fn != "??" and fn != "":
1316
result.append(f"{fn}:{line} {name}")
@@ -48,7 +51,6 @@ def get_stack_idx(frames: list[dict]) -> int:
4851
reserved = 0
4952
hwm = 0
5053
timeline: list[dict] = []
51-
active_by_addr: dict[int, dict] = {}
5254
last_time = 0
5355

5456
current_stack: list[int] = []
@@ -70,12 +72,14 @@ def get_stack_idx(frames: list[dict]) -> int:
7072
allocated += size
7173
offset = allocated - size
7274
alloc_id = len(alloc_polys)
73-
alloc_polys.append({
74-
"si": si,
75-
"s": size,
76-
"ts": [timestep],
77-
"offsets": [offset],
78-
})
75+
alloc_polys.append(
76+
{
77+
"si": si,
78+
"s": size,
79+
"ts": [timestep],
80+
"offsets": [offset],
81+
}
82+
)
7983
current_stack.append(alloc_id)
8084
alloc_id_by_addr[addr] = alloc_id
8185
timestep += 1
@@ -110,10 +114,17 @@ def get_stack_idx(frames: list[dict]) -> int:
110114
pass
111115

112116
hwm = max(hwm, allocated)
113-
timeline.append({
114-
"t": time_us, "a": allocated, "r": reserved,
115-
"h": hwm, "act": action, "s": size, "si": si,
116-
})
117+
timeline.append(
118+
{
119+
"t": time_us,
120+
"a": allocated,
121+
"r": reserved,
122+
"h": hwm,
123+
"act": action,
124+
"s": size,
125+
"si": si,
126+
}
127+
)
117128

118129
for alloc_id in current_stack:
119130
poly = alloc_polys[alloc_id]
@@ -149,8 +160,7 @@ def generate_memory_html(
149160
}
150161

151162
return (
152-
_MEMORY_VIZ_TEMPLATE
153-
.replace("__TITLE__", title)
163+
_MEMORY_VIZ_TEMPLATE.replace("__TITLE__", title)
154164
.replace("__TIMELINE__", json.dumps(timeline))
155165
.replace("__ALLOCS__", json.dumps(alloc_polys))
156166
.replace("__STACKS__", json.dumps(stacks))
@@ -566,18 +576,60 @@ def generate_memory_html(
566576
.extent([[0, 0], [width, height]])
567577
.on('zoom', (event) => updateChart(event.transform));
568578
569-
chartArea.append('rect')
579+
const zoomRect = chartArea.append('rect')
570580
.attr('width', width).attr('height', height)
571581
.attr('fill', 'none').attr('pointer-events', 'all')
572582
.call(zoom);
573583
574584
// Raise polys above the zoom rect
575585
polysG.raise();
576586
587+
// WASD / arrow key navigation (Perfetto-style)
588+
const PAN_STEP = 0.15;
589+
const ZOOM_STEP = 1.3;
590+
591+
document.addEventListener('keydown', function(event) {
592+
if (event.target.tagName === 'INPUT') return;
593+
const k = event.key.toLowerCase();
594+
let t = currentTransform;
595+
596+
switch (k) {
597+
case 'a':
598+
case 'arrowleft':
599+
t = t.translate(width * PAN_STEP, 0);
600+
break;
601+
case 'd':
602+
case 'arrowright':
603+
t = t.translate(-width * PAN_STEP, 0);
604+
break;
605+
case 'w':
606+
case 'arrowup':
607+
t = d3.zoomIdentity
608+
.translate(width / 2, 0)
609+
.scale(t.k * ZOOM_STEP)
610+
.translate(-width / 2, 0)
611+
.translate(t.x / (t.k * ZOOM_STEP), 0);
612+
break;
613+
case 's':
614+
case 'arrowdown':
615+
t = d3.zoomIdentity
616+
.translate(width / 2, 0)
617+
.scale(t.k / ZOOM_STEP)
618+
.translate(-width / 2, 0)
619+
.translate(t.x / (t.k / ZOOM_STEP), 0);
620+
break;
621+
default:
622+
return;
623+
}
624+
625+
event.preventDefault();
626+
zoomRect.call(zoom.transform, t);
627+
});
628+
577629
document.getElementById('hwm-toggle').onchange = function() {
578630
hwmG.style('display', this.checked ? null : 'none');
579631
};
580632
</script>
581633
</body>
582634
</html>
583-
""";
635+
"""

0 commit comments

Comments
 (0)