9e1242039b
End-to-end wires C=8 P=8 d_head=128 prefill with snake-ring inter-CUBE SFR, intra-CUBE PE-SP (all 64 ranks active), and the milestone bench panel. Decode kernel gains lrab-adapted center-root reduce for the 2×4 sub-mesh per ADR-0060 §4.2. Increment 1 — SFR multi-row snake src/kernbench/ccl/sfr_config.py: configure_sfr_intercube_ring gains submesh_shape / submesh_origin kwargs; installs a Hamiltonian snake ring through a rectangular sub-mesh (every hop is 1-hop physical neighbour). Backward-compat: 1D-row behaviour preserved when submesh_shape is None. tests/test_intercube_snake_ring.py (12 tests) Increment 2 — Decode lrab-adapted center-root reduce src/kernbench/benches/_gqa_attention_decode_long.py: new sub_w param (default 0 = existing 1D-chain). sub_w >= 2 selects the ADR-0060 §4.2 prescribed lrab-adapted Phase 1+2 reduce (bidirectional row + bidirectional col converge to the center cube), with log-sum-exp _merge_running replacing the plain + of lrab. tests/attention/test_gqa_decode_long_2d_reduce.py (4 tests) Increment 3 — Prefill kernel at C=8 (no production change) Verified by inspection that the existing prefill_long kernel + Increment 1's snake SFR already work at C=8 without any kernel edit. The kernel speaks logical W/E; the snake routes it. tests/attention/test_gqa_prefill_long_c8_snake.py (3 tests) Increment 4 — Intra-CUBE PE-SP in prefill (all 64 ranks) src/kernbench/benches/_gqa_attention_prefill_long.py: new P param (default 1 = existing PE-0-only). P > 1 splits T_q query-axis-wise across the P PEs of each CUBE; output rows are disjoint per PE so no intra-CUBE reduce is needed; each PE drives its own same-lane ring (P parallel rings). tests/attention/test_gqa_prefill_long_pe_sp.py (5 tests) Increment 5 — LLaMA-scale milestone bench panel src/kernbench/benches/milestone_gqa_headline.py: new panel single_kv_group_prefill_gqa_c8_p8 (C=8, P=8, T_q=S_kv=32K, d_head=128). _run_prefill_panel extended with P/T_q/d_head defaults; routes snake SFR when C > mesh_w. tests/attention/test_milestone_gqa_single_kv_group_prefill_panel.py (3 tests) Total: 4 production files modified, 5 new test files, 27 new tests. Followed the Phase 1/2 protocol per CLAUDE.md throughout. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
406 lines
14 KiB
Python
406 lines
14 KiB
Python
"""SFR configuration for the full IPCQ hardware wiring.
|
||
|
||
Installs PE_IPCQ neighbor tables modeling the physical hardware.
|
||
Wiring is independent of DPPolicy / kernel choice — the kernel decides
|
||
at runtime which links to use.
|
||
|
||
Direction label namespaces (disjoint):
|
||
|
||
- Intra-cube PE-to-PE: ``intra_N / intra_S / intra_E / intra_W``
|
||
Logical 2×4 PE grid within a cube (no wrap):
|
||
|
||
Row 0: pe0 pe1 pe2 pe3
|
||
Row 1: pe4 pe5 pe6 pe7
|
||
|
||
- Intercube same-lane: ``N / S / E / W``
|
||
``pe_i of cube_A ↔ pe_i of cube_B`` across the 4×4 cube mesh
|
||
(no wrap). Every PE i ∈ [0..7] wired independently.
|
||
|
||
- Inter-SIP same-(cube, pe): ``global_N / global_S / global_E / global_W``
|
||
``pe_i of cube_c on sip_A ↔ pe_i of cube_c on sip_B`` per
|
||
``topology.yaml → system.sips.topology``.
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import types
|
||
from typing import Any
|
||
|
||
from kernbench.ccl.install import install_ipcq
|
||
from kernbench.ccl.topologies import _BUILTIN as _TOPO_BUILTINS
|
||
|
||
|
||
# ── Intra-cube 2×4 PE grid ───────────────────────────────────────────
|
||
|
||
_PE_GRID_COLS = 4
|
||
_PE_GRID_ROWS = 2
|
||
_PES_PER_CUBE = _PE_GRID_COLS * _PE_GRID_ROWS # 8
|
||
|
||
|
||
def _intra_cube_neighbors(pe: int) -> dict[str, int]:
|
||
"""Logical 2×4 PE grid neighbors within a cube (no wrap).
|
||
|
||
Returns directions in the ``intra_*`` namespace.
|
||
"""
|
||
row, col = divmod(pe, _PE_GRID_COLS)
|
||
nbrs: dict[str, int] = {}
|
||
if col < _PE_GRID_COLS - 1:
|
||
nbrs["intra_E"] = row * _PE_GRID_COLS + (col + 1)
|
||
if col > 0:
|
||
nbrs["intra_W"] = row * _PE_GRID_COLS + (col - 1)
|
||
if row < _PE_GRID_ROWS - 1:
|
||
nbrs["intra_S"] = (row + 1) * _PE_GRID_COLS + col
|
||
if row > 0:
|
||
nbrs["intra_N"] = (row - 1) * _PE_GRID_COLS + col
|
||
return nbrs
|
||
|
||
|
||
# ── Public entry point ───────────────────────────────────────────────
|
||
|
||
|
||
def configure_sfr_intercube_multisip(
|
||
engine: Any,
|
||
spec: dict,
|
||
cfg: dict,
|
||
) -> dict[str, Any]:
|
||
"""Wire the full IPCQ hardware model.
|
||
|
||
Every PE on every cube on every SIP gets neighbor table entries for:
|
||
|
||
- intra-cube (2×4 grid) in the ``intra_*`` namespace
|
||
- intercube same-lane (4×4 cube mesh, no wrap) in ``N/S/E/W``
|
||
- inter-SIP same-(cube, pe) in ``global_*``
|
||
|
||
Args:
|
||
engine: GraphEngine with ``_components``.
|
||
spec: topology spec dict (from topology.yaml).
|
||
cfg: merged algorithm config (from ``resolve_algorithm_config``).
|
||
|
||
Returns:
|
||
The install plan dict from ``install_ipcq``.
|
||
"""
|
||
cm = spec["sip"]["cube_mesh"]
|
||
mesh_w = int(cm["w"])
|
||
mesh_h = int(cm["h"])
|
||
n_cubes = mesh_w * mesh_h
|
||
sips_cfg = spec.get("system", {}).get("sips", {})
|
||
n_sips = int(sips_cfg.get("count", 1))
|
||
sip_topology = str(sips_cfg.get("topology", "ring_1d"))
|
||
sip_w = sips_cfg.get("w")
|
||
sip_h = sips_cfg.get("h")
|
||
sip_w = int(sip_w) if sip_w is not None else None
|
||
sip_h = int(sip_h) if sip_h is not None else None
|
||
|
||
if sip_topology not in _TOPO_BUILTINS:
|
||
raise ValueError(
|
||
f"Unknown sip topology '{sip_topology}'. "
|
||
f"Available: {list(_TOPO_BUILTINS)}"
|
||
)
|
||
_sip_topo_fn_raw = _TOPO_BUILTINS[sip_topology]
|
||
|
||
def sip_topo_fn(rank: int, ws: int) -> dict:
|
||
if sip_w is not None and sip_h is not None:
|
||
try:
|
||
return _sip_topo_fn_raw(rank, ws, w=sip_w, h=sip_h)
|
||
except TypeError:
|
||
pass
|
||
return _sip_topo_fn_raw(rank, ws)
|
||
|
||
pes_per_cube = _PES_PER_CUBE
|
||
world_size = n_sips * n_cubes * pes_per_cube
|
||
pe_idx_to_pe: list[tuple[int, int, int]] = [
|
||
(sip, cube, pe)
|
||
for sip in range(n_sips)
|
||
for cube in range(n_cubes)
|
||
for pe in range(pes_per_cube)
|
||
]
|
||
|
||
def _pe_idx(sip: int, cube: int, pe: int) -> int:
|
||
return (sip * n_cubes + cube) * pes_per_cube + pe
|
||
|
||
def _neighbors(pe_idx: int, ws: int, _base: dict) -> dict[str, int]:
|
||
tmp = pe_idx
|
||
pe = tmp % pes_per_cube
|
||
tmp //= pes_per_cube
|
||
cube = tmp % n_cubes
|
||
sip = tmp // n_cubes
|
||
row = cube // mesh_w
|
||
col = cube % mesh_w
|
||
|
||
nbrs: dict[str, int] = {}
|
||
|
||
# ── Intra-cube (intra_N/S/E/W) ──
|
||
for d, peer_pe in _intra_cube_neighbors(pe).items():
|
||
nbrs[d] = _pe_idx(sip, cube, peer_pe)
|
||
|
||
# ── Intercube same-lane (N/S/E/W, 4×4 no wrap) ──
|
||
if col < mesh_w - 1:
|
||
nbrs["E"] = _pe_idx(sip, row * mesh_w + (col + 1), pe)
|
||
if col > 0:
|
||
nbrs["W"] = _pe_idx(sip, row * mesh_w + (col - 1), pe)
|
||
if row < mesh_h - 1:
|
||
nbrs["S"] = _pe_idx(sip, (row + 1) * mesh_w + col, pe)
|
||
if row > 0:
|
||
nbrs["N"] = _pe_idx(sip, (row - 1) * mesh_w + col, pe)
|
||
|
||
# ── Inter-SIP same-(cube, pe) (global_*) ──
|
||
if n_sips > 1:
|
||
sip_nbrs = sip_topo_fn(sip, n_sips)
|
||
for d, peer_sip in sip_nbrs.items():
|
||
nbrs[f"global_{d}"] = _pe_idx(peer_sip, cube, pe)
|
||
|
||
return nbrs
|
||
|
||
mock_module = types.SimpleNamespace(neighbors=_neighbors)
|
||
|
||
cfg_copy = dict(cfg)
|
||
cfg_copy["world_size"] = world_size
|
||
cfg_copy["topology"] = "none"
|
||
|
||
return install_ipcq(
|
||
engine, spec, cfg_copy,
|
||
algo_module=mock_module,
|
||
rank_to_pe=pe_idx_to_pe,
|
||
)
|
||
|
||
|
||
# ── Intra-cube PE ring (ADR-0058 Proposed) ─────────────────────────────
|
||
|
||
|
||
def configure_sfr_intracube_pe_ring(
|
||
engine: Any,
|
||
spec: dict,
|
||
cfg: dict,
|
||
) -> dict[str, Any]:
|
||
"""Install an 8-PE logical ring inside every cube on every SIP.
|
||
|
||
Per cube ``c`` on every SIP, every PE ``i`` ∈ [0, pes_per_cube) gets:
|
||
|
||
nbrs[i]["E"] = pe ((i + 1) % pes_per_cube) on the same cube and sip
|
||
nbrs[i]["W"] = pe ((i - 1) % pes_per_cube) on the same cube and sip
|
||
|
||
No intercube or inter-SIP edges are installed by this function — the
|
||
single_user_* attention panels (ADR-0057) operate inside one cube,
|
||
so cross-cube traffic is architecturally not part of their kernel.
|
||
|
||
The ``E``/``W`` direction namespace is shared with
|
||
``configure_sfr_intercube_multisip`` (which writes cube-mesh
|
||
same-lane edges to the same names). The two installs are
|
||
**mutually exclusive on the same engine** — the bench is responsible
|
||
for picking one per panel-run (ADR-0058 D2). v1 does not add a
|
||
runtime guard.
|
||
|
||
Args:
|
||
engine: GraphEngine with ``_components``.
|
||
spec: topology spec dict (from topology.yaml).
|
||
cfg: merged algorithm config (from ``resolve_algorithm_config``).
|
||
|
||
Returns:
|
||
The install plan dict from ``install_ipcq`` (same shape as
|
||
``configure_sfr_intercube_multisip``).
|
||
"""
|
||
cm = spec["sip"]["cube_mesh"]
|
||
n_cubes = int(cm["w"]) * int(cm["h"])
|
||
n_sips = int(spec.get("system", {}).get("sips", {}).get("count", 1))
|
||
pl = spec["cube"]["pe_layout"]
|
||
pes_per_cube = int(pl["pe_per_corner"]) * len(pl["corners"])
|
||
|
||
world_size = n_sips * n_cubes * pes_per_cube
|
||
pe_idx_to_pe: list[tuple[int, int, int]] = [
|
||
(sip, cube, pe)
|
||
for sip in range(n_sips)
|
||
for cube in range(n_cubes)
|
||
for pe in range(pes_per_cube)
|
||
]
|
||
|
||
def _pe_idx(sip: int, cube: int, pe: int) -> int:
|
||
return (sip * n_cubes + cube) * pes_per_cube + pe
|
||
|
||
def _neighbors(pe_idx: int, ws: int, _base: dict) -> dict[str, int]:
|
||
tmp = pe_idx
|
||
pe = tmp % pes_per_cube
|
||
tmp //= pes_per_cube
|
||
cube = tmp % n_cubes
|
||
sip = tmp // n_cubes
|
||
return {
|
||
"E": _pe_idx(sip, cube, (pe + 1) % pes_per_cube),
|
||
"W": _pe_idx(sip, cube, (pe - 1) % pes_per_cube),
|
||
}
|
||
|
||
mock_module = types.SimpleNamespace(neighbors=_neighbors)
|
||
|
||
cfg_copy = dict(cfg)
|
||
cfg_copy["world_size"] = world_size
|
||
cfg_copy["topology"] = "none"
|
||
|
||
return install_ipcq(
|
||
engine, spec, cfg_copy,
|
||
algo_module=mock_module,
|
||
rank_to_pe=pe_idx_to_pe,
|
||
)
|
||
|
||
|
||
# ── Inter-cube 1D ring (ADR-0060 §5.5 prefill Ring KV) ─────────────────
|
||
|
||
|
||
def configure_sfr_intercube_ring(
|
||
engine: Any,
|
||
spec: dict,
|
||
cfg: dict,
|
||
*,
|
||
ring_size: int | None = None,
|
||
submesh_shape: tuple[int, int] | None = None,
|
||
submesh_origin: tuple[int, int] = (0, 0),
|
||
) -> dict[str, Any]:
|
||
"""Install intra-cube PE grid + a CUBE-level ring with wrap.
|
||
|
||
Two ring layouts:
|
||
|
||
- **1D row** (default; ``submesh_shape=None``): cubes
|
||
``0..ring_size-1`` form a 1D ring with wrap. ``ring_size`` must
|
||
be ≤ ``mesh_w`` so every hop is a 1-hop CUBE NOC neighbour.
|
||
- **Snake/serpentine** (``submesh_shape=(rows, cols)``,
|
||
ADR-0060 §5.5 prefill Ring KV at C=G=8 on a 2×4 sub-mesh):
|
||
a boustrophedon Hamiltonian cycle through the ``rows × cols``
|
||
sub-mesh rooted at ``submesh_origin``. Every consecutive pair
|
||
on the snake (including the wrap) is a 1-hop CUBE NOC
|
||
neighbour, so the kernel sees a 1D logical E/W ring without
|
||
being aware of the underlying 2D layout.
|
||
|
||
Direction namespaces (disjoint, same as
|
||
``configure_sfr_intercube_multisip``):
|
||
|
||
- ``intra_N/S/E/W`` : 2×4 PE grid within each cube (no wrap)
|
||
- ``E/W`` : ring along the resolved path WITH WRAP
|
||
(symmetric to ``configure_sfr_intracube_pe_ring``
|
||
at PE level — wrap applied at CUBE level here)
|
||
- ``global_*`` : SIP topology (same as multisip)
|
||
|
||
N/S at CUBE level are intentionally NOT installed — use
|
||
``configure_sfr_intercube_multisip`` for the full 4×4 cube mesh.
|
||
|
||
Args:
|
||
ring_size: number of CUBEs in the ring. Defaults to the full
|
||
cube_mesh count for the 1D-row case, or ``rows*cols`` for
|
||
the snake case. If passed alongside ``submesh_shape``, must
|
||
equal ``rows*cols``.
|
||
submesh_shape: ``(rows, cols)`` of the snake sub-mesh. If
|
||
given, ring follows a boustrophedon path through that
|
||
rectangle. If ``None``, falls back to the 1D-row layout.
|
||
submesh_origin: ``(row, col)`` top-left of the sub-mesh inside
|
||
the cube mesh. Defaults to ``(0, 0)``.
|
||
"""
|
||
cm = spec["sip"]["cube_mesh"]
|
||
mesh_w = int(cm["w"])
|
||
mesh_h = int(cm["h"])
|
||
n_cubes = mesh_w * mesh_h
|
||
sips_cfg = spec.get("system", {}).get("sips", {})
|
||
n_sips = int(sips_cfg.get("count", 1))
|
||
sip_topology = str(sips_cfg.get("topology", "ring_1d"))
|
||
sip_w = sips_cfg.get("w")
|
||
sip_h = sips_cfg.get("h")
|
||
sip_w = int(sip_w) if sip_w is not None else None
|
||
sip_h = int(sip_h) if sip_h is not None else None
|
||
|
||
if submesh_shape is not None:
|
||
sub_h, sub_w = submesh_shape
|
||
origin_row, origin_col = submesh_origin
|
||
if (sub_h <= 0 or sub_w <= 0
|
||
or origin_row < 0 or origin_col < 0
|
||
or origin_row + sub_h > mesh_h
|
||
or origin_col + sub_w > mesh_w):
|
||
raise ValueError(
|
||
f"submesh_shape={submesh_shape} at origin={submesh_origin} "
|
||
f"does not fit cube_mesh ({mesh_h}x{mesh_w})"
|
||
)
|
||
expected_size = sub_h * sub_w
|
||
if ring_size is not None and ring_size != expected_size:
|
||
raise ValueError(
|
||
f"ring_size={ring_size} inconsistent with "
|
||
f"submesh_shape={submesh_shape} (expected {expected_size})"
|
||
)
|
||
ring_size = expected_size
|
||
# Boustrophedon: even rows L→R, odd rows R→L.
|
||
ring_path: list[int] = []
|
||
for r in range(sub_h):
|
||
cols = range(sub_w) if r % 2 == 0 else range(sub_w - 1, -1, -1)
|
||
for c in cols:
|
||
ring_path.append((origin_row + r) * mesh_w + (origin_col + c))
|
||
else:
|
||
if ring_size is None:
|
||
ring_size = n_cubes
|
||
if ring_size > mesh_w:
|
||
raise ValueError(
|
||
f"intercube_ring ring_size={ring_size} > mesh_w={mesh_w}; "
|
||
"multi-row rings cross non-neighbour boundaries"
|
||
)
|
||
ring_path = list(range(ring_size))
|
||
|
||
ring_pos: dict[int, int] = {c: i for i, c in enumerate(ring_path)}
|
||
ring_len = len(ring_path)
|
||
|
||
if sip_topology not in _TOPO_BUILTINS:
|
||
raise ValueError(
|
||
f"Unknown sip topology '{sip_topology}'. "
|
||
f"Available: {list(_TOPO_BUILTINS)}"
|
||
)
|
||
_sip_topo_fn_raw = _TOPO_BUILTINS[sip_topology]
|
||
|
||
def sip_topo_fn(rank: int, ws: int) -> dict:
|
||
if sip_w is not None and sip_h is not None:
|
||
try:
|
||
return _sip_topo_fn_raw(rank, ws, w=sip_w, h=sip_h)
|
||
except TypeError:
|
||
pass
|
||
return _sip_topo_fn_raw(rank, ws)
|
||
|
||
pes_per_cube = _PES_PER_CUBE
|
||
world_size = n_sips * n_cubes * pes_per_cube
|
||
pe_idx_to_pe: list[tuple[int, int, int]] = [
|
||
(sip, cube, pe)
|
||
for sip in range(n_sips)
|
||
for cube in range(n_cubes)
|
||
for pe in range(pes_per_cube)
|
||
]
|
||
|
||
def _pe_idx(sip: int, cube: int, pe: int) -> int:
|
||
return (sip * n_cubes + cube) * pes_per_cube + pe
|
||
|
||
def _neighbors(pe_idx: int, ws: int, _base: dict) -> dict[str, int]:
|
||
tmp = pe_idx
|
||
pe = tmp % pes_per_cube
|
||
tmp //= pes_per_cube
|
||
cube = tmp % n_cubes
|
||
sip = tmp // n_cubes
|
||
|
||
nbrs: dict[str, int] = {}
|
||
|
||
# ── Intra-cube (intra_N/S/E/W) ──
|
||
for d, peer_pe in _intra_cube_neighbors(pe).items():
|
||
nbrs[d] = _pe_idx(sip, cube, peer_pe)
|
||
|
||
# ── Cube ring (E/W along resolved ring_path, with wrap) ──
|
||
pos = ring_pos.get(cube)
|
||
if pos is not None:
|
||
nbrs["E"] = _pe_idx(sip, ring_path[(pos + 1) % ring_len], pe)
|
||
nbrs["W"] = _pe_idx(sip, ring_path[(pos - 1) % ring_len], pe)
|
||
|
||
# ── Inter-SIP same-(cube, pe) (global_*) ──
|
||
if n_sips > 1:
|
||
sip_nbrs = sip_topo_fn(sip, n_sips)
|
||
for d, peer_sip in sip_nbrs.items():
|
||
nbrs[f"global_{d}"] = _pe_idx(peer_sip, cube, pe)
|
||
|
||
return nbrs
|
||
|
||
mock_module = types.SimpleNamespace(neighbors=_neighbors)
|
||
|
||
cfg_copy = dict(cfg)
|
||
cfg_copy["world_size"] = world_size
|
||
cfg_copy["topology"] = "none"
|
||
|
||
return install_ipcq(
|
||
engine, spec, cfg_copy,
|
||
algo_module=mock_module,
|
||
rank_to_pe=pe_idx_to_pe,
|
||
)
|