Skip to content

Commit 3463554

Browse files
committed
feat: implement edge reconnection, unified handle management, and persistent routing layout flow
1 parent 9b7cadb commit 3463554

23 files changed

Lines changed: 1258 additions & 367 deletions

cppmega_mlx/runtime/path_c_physical_abi.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -463,8 +463,18 @@ def validate_physical_abi_runtime_bindings(
463463
mapping: Mapping[str, Any],
464464
bank_shapes: Mapping[str, Any],
465465
buffers: Mapping[str, Any] | None,
466+
*,
467+
allow_superset: bool = False,
466468
) -> dict[str, Any]:
467-
"""Validate caller-supplied physical bank buffers without allocating."""
469+
"""Validate caller-supplied physical bank buffers without allocating.
470+
471+
``allow_superset`` (opt-in; default exact-equality) accepts a caller/model-owned
472+
bank whose flat element count is >= the required extent and whose dtype matches.
473+
This is for bindings against a single schedule-template region when the model owns
474+
banks sized from the MERGED launcher+generated-stage ABI (a strict superset of any
475+
one region's need); the kernel-arg builder slices a contiguous prefix view to the
476+
exact per-region shape at call time. All other callers keep strict equality.
477+
"""
468478

469479
bridge_plan = plan_physical_abi_runtime_bridge(mapping, bank_shapes)
470480
required_banks = list(bridge_plan["required_bank_buffers"])
@@ -498,10 +508,19 @@ def validate_physical_abi_runtime_bindings(
498508
expected_shape = tuple(int(dim) for dim in tuple(bank_shapes[bank]))
499509
actual_shape = _shape_of(provided[bank])
500510
if actual_shape != expected_shape:
501-
shape_mismatches.append(bank)
502-
errors.append(
503-
f"{bank}: shape {actual_shape} does not match expected {expected_shape}"
511+
expected_numel = int(prod(expected_shape)) if expected_shape else 1
512+
actual_numel = (
513+
int(prod(actual_shape)) if actual_shape else 0
504514
)
515+
if allow_superset and actual_shape is not None and actual_numel >= expected_numel:
516+
# Larger-but-sufficient caller-owned bank (merged-ABI superset); the
517+
# kernel-arg builder slices a contiguous prefix view to the exact shape.
518+
pass
519+
else:
520+
shape_mismatches.append(bank)
521+
errors.append(
522+
f"{bank}: shape {actual_shape} does not match expected {expected_shape}"
523+
)
505524
expected_dtype = bank_dtypes.get(bank)
506525
actual_dtype = _dtype_of(provided[bank])
507526
if actual_dtype != expected_dtype:

cppmega_mlx/training/compiled.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ class PathCFusedTrainBlockCallableArtifact:
130130

131131
hidden_packing_performed = False
132132
no_hidden_allocation_policy = True
133+
# A base (non-staged) artifact wraps ONE compiled TileLang/Metal kernel that
134+
# lowers the whole forward and the full recurrent backward internally and only
135+
# gates on ``path_c_run_backward``; it is dispatched grid-chunked (launched once
136+
# per forward / backward). Multi-kernel stage artifacts override this to True.
137+
generated_stage_artifact = False
133138

134139
def __init__(
135140
self,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import time
2+
from playwright.sync_api import sync_playwright
3+
URL="http://127.0.0.1:8765"; PRESET="deepseek_v4_flash"
4+
with sync_playwright() as p:
5+
b=p.firefox.launch(headless=True); pg=b.new_page(viewport={"width":2200,"height":1300})
6+
pg.goto(URL,wait_until="networkidle"); time.sleep(2)
7+
sels=pg.locator("select")
8+
for i in range(sels.count()):
9+
if any(PRESET in o for o in sels.nth(i).locator("option").all_inner_texts()):
10+
sels.nth(i).select_option(label=PRESET); break
11+
time.sleep(1.5)
12+
g=pg.get_by_role("button",name="Generate Architecture")
13+
if g.count()>0: g.first.click()
14+
pg.wait_for_selector(".react-flow__node",timeout=15000); time.sleep(3)
15+
pg.locator(".react-flow__controls-fitview").first.click(); time.sleep(1)
16+
before = pg.locator('.react-flow__edge').count()
17+
# Select first edge, grab one of its updater anchors, drag onto its target node top handle.
18+
edge = pg.locator('.react-flow__edge').first
19+
box = edge.bounding_box()
20+
pg.mouse.click(box['x']+box['width']/2, box['y']+box['height']/2); time.sleep(0.4)
21+
anchors = pg.locator('.react-flow__edgeupdater')
22+
n = anchors.count()
23+
moved = False
24+
if n >= 1:
25+
a = anchors.first.bounding_box()
26+
# drag the anchor a bit (just to exercise the reconnect drag path); drop near a node center
27+
node = pg.locator('.react-flow__node').nth(1).bounding_box()
28+
pg.mouse.move(a['x']+a['width']/2, a['y']+a['height']/2)
29+
pg.mouse.down()
30+
pg.mouse.move(node['x']+node['width']/2, node['y']+5, steps=15) # near top edge of a node
31+
pg.mouse.up(); time.sleep(0.6)
32+
moved = True
33+
after = pg.locator('.react-flow__edge').count()
34+
print(f"edges before={before} after={after} anchors={n} dragPerformed={moved}")
35+
print("RESULT edges_survived_drag:", after >= before-1)
36+
pg.screenshot(path="/tmp/route_geo_folded.png")
37+
b.close()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import time
2+
from playwright.sync_api import sync_playwright
3+
URL="http://127.0.0.1:8765"; PRESET="deepseek_v4_flash"
4+
with sync_playwright() as p:
5+
b=p.firefox.launch(headless=True); pg=b.new_page(viewport={"width":2200,"height":1300})
6+
pg.goto(URL,wait_until="networkidle"); time.sleep(2)
7+
sels=pg.locator("select")
8+
for i in range(sels.count()):
9+
if any(PRESET in o for o in sels.nth(i).locator("option").all_inner_texts()):
10+
sels.nth(i).select_option(label=PRESET); break
11+
time.sleep(1.5)
12+
g=pg.get_by_role("button",name="Generate Architecture")
13+
if g.count()>0: g.first.click()
14+
pg.wait_for_selector(".react-flow__node",timeout=15000); time.sleep(3)
15+
pg.locator(".react-flow__controls-fitview").first.click(); time.sleep(1)
16+
zin=pg.locator(".react-flow__controls-zoomin").first
17+
zin.click();time.sleep(0.3);zin.click();time.sleep(0.6)
18+
pg.screenshot(path="/tmp/route_folded_tb.png")
19+
print("saved")
20+
b.close()

outputs/webwright_canvas/probe_folded_v2.py

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import time, sys
2+
from playwright.sync_api import sync_playwright
3+
URL="http://127.0.0.1:8765"
4+
PRESETS = ["gemma4","llama3_8b","deepseek_v3","gpt_oss_20b","minimax_m2"]
5+
VIOLATION_JS = open("probe_routing.py").read().split('VIOLATION_JS = r"""')[1].split('"""')[0]
6+
def measure(pg):
7+
return pg.evaluate("()=>{"+VIOLATION_JS.split("() => {",1)[1])
8+
with sync_playwright() as p:
9+
b=p.firefox.launch(headless=True); pg=b.new_page(viewport={"width":2400,"height":1400})
10+
grand=0
11+
for preset in PRESETS:
12+
for scen in ["folded","unpackall"]:
13+
pg.goto(URL,wait_until="networkidle"); time.sleep(1.5)
14+
sels=pg.locator("select"); ok=False
15+
for i in range(sels.count()):
16+
if any(preset==o.strip() for o in sels.nth(i).locator("option").all_inner_texts()):
17+
sels.nth(i).select_option(label=preset); ok=True; break
18+
if not ok: print(f" {preset}: NOT FOUND"); continue
19+
time.sleep(1.2)
20+
g=pg.get_by_role("button",name="Generate Architecture")
21+
if g.count()>0: g.first.click()
22+
try: pg.wait_for_selector(".react-flow__node",timeout=15000)
23+
except: print(f" {preset}/{scen}: no nodes"); continue
24+
time.sleep(1.5)
25+
if scen=="unpackall":
26+
ub=pg.locator('[data-testid^="unpack-btn-"]')
27+
if ub.count()>0:
28+
ub.first.click(); time.sleep(0.4)
29+
ua=pg.locator('[data-testid^="confirm-unpack-all-"]')
30+
if ua.count()>0: ua.first.click(); time.sleep(2.2)
31+
pg.get_by_role("button",name="Auto Align Graph").first.click(); time.sleep(4)
32+
m=measure(pg)
33+
grand+=len(m['violations'])
34+
print(f" {preset:16s}/{scen:9s}: edges={m['edges']:3d} nodes={m['nodes']:3d} OVER-BOXES={len(m['violations'])}")
35+
for v in m['violations'][:4]: print(f" ! {v}")
36+
print(f"\nGRAND TOTAL edges-over-boxes = {grand}")
37+
b.close()

outputs/webwright_canvas/probe_partial2.py

Lines changed: 0 additions & 63 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import time
2+
from playwright.sync_api import sync_playwright
3+
URL="http://127.0.0.1:8765"; PRESET="deepseek_v4_flash"
4+
with sync_playwright() as p:
5+
b=p.firefox.launch(headless=True); pg=b.new_page(viewport={"width":2200,"height":1300})
6+
pg.goto(URL,wait_until="networkidle"); time.sleep(2)
7+
sels=pg.locator("select")
8+
for i in range(sels.count()):
9+
if any(PRESET in o for o in sels.nth(i).locator("option").all_inner_texts()):
10+
sels.nth(i).select_option(label=PRESET); break
11+
time.sleep(1.5)
12+
g=pg.get_by_role("button",name="Generate Architecture")
13+
if g.count()>0: g.first.click()
14+
pg.wait_for_selector(".react-flow__node",timeout=15000); time.sleep(3)
15+
pg.locator(".react-flow__controls-fitview").first.click(); time.sleep(1)
16+
# Count edges + check reconnect anchors exist (react-flow__edgeupdater) when hovering an edge.
17+
info = pg.evaluate(r"""
18+
() => {
19+
const edges = document.querySelectorAll('.react-flow__edge').length;
20+
// selecting an edge should render edgeupdater anchors; check the DOM supports them
21+
const hasUpdaterClass = !!document.querySelector('.react-flow__edge');
22+
return { edges };
23+
}
24+
""")
25+
print("edges:", info['edges'])
26+
# Click an edge to select it, then check for edgeupdater anchors
27+
edge = pg.locator('.react-flow__edge').first
28+
box = edge.bounding_box()
29+
if box:
30+
pg.mouse.click(box['x']+box['width']/2, box['y']+box['height']/2)
31+
time.sleep(0.5)
32+
anchors = pg.locator('.react-flow__edgeupdater').count()
33+
print("edgeupdater anchors after selecting an edge:", anchors)
34+
# Programmatic reconnect test: pick the De-Tokenizer incoming edge, drag its
35+
# target anchor to a different handle. Simpler: verify the anchors are draggable
36+
# by checking they exist (>0 means reconnection UI is active).
37+
print("RECONNECT-UI-ACTIVE:", anchors > 0)
38+
b.close()

0 commit comments

Comments
 (0)