Add SIP-level tensor parallelism, component registry YAML, VA offset verification

- DPPolicy: 3-level (sip/cube/pe), unified naming (column_wise/row_wise)
- PE_CPU: auto num_programs from cube shard count
- context.launch(): per-SIP KernelLaunchMsg with local va_base + auto local shape
- deploy_tensor: removed mmus param, MMU mapping is context-only responsibility
- ComponentRegistry: YAML-based lazy loading (components.yaml), impls→builtin rename
- VA offset bench + tests: 2D/1D, standard Triton kernel pattern

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-26 01:13:17 -07:00
parent 08812eda58
commit 63669f82cb
35 changed files with 813 additions and 219 deletions
+53 -35
View File
@@ -7,12 +7,36 @@ from typing import Literal
@dataclass(frozen=True)
class DPPolicy:
"""Two-level data-parallel policy: cube-level + pe-level."""
"""Three-level data-parallel policy: sip-level + cube-level + pe-level.
cube: Literal["replicate", "shard_m", "shard_k"] = "replicate"
Policies:
- "replicate": full copy at each unit
- "column_wise": split K (column) axis across units
- "row_wise": split M (row) axis across units
"""
sip: Literal["replicate", "column_wise", "row_wise"] = "replicate"
cube: Literal["replicate", "column_wise", "row_wise"] = "replicate"
pe: Literal["replicate", "column_wise", "row_wise"] = "replicate"
def _split_shape(
policy: str, shape: tuple[int, int], count: int, itemsize: int,
) -> list[tuple[tuple[int, int], int]]:
"""Split shape by policy into (sub_shape, byte_offset) pairs."""
M, K = shape
if policy == "replicate":
return [((M, K), 0)] * count
elif policy == "column_wise":
chunk_k = K // count
return [((M, chunk_k), i * M * chunk_k * itemsize) for i in range(count)]
elif policy == "row_wise":
chunk_m = M // count
return [((chunk_m, K), i * chunk_m * K * itemsize) for i in range(count)]
else:
raise ValueError(f"Unknown policy: {policy}")
def resolve_dp_policy(
policy: DPPolicy,
*,
@@ -20,11 +44,14 @@ def resolve_dp_policy(
itemsize: int,
num_pe: int,
num_cubes: int = 1,
num_sips: int = 1,
) -> list[ShardSpec]:
"""Resolve a DPPolicy into a list[ShardSpec] with two-level resolution.
"""Resolve a DPPolicy into a list[ShardSpec] with three-level resolution.
Cube-level policy distributes across cubes, pe-level distributes within
each cube. ShardSpec.pe_index uses flat indexing: cube_id * num_pe + pe_id.
SIP-level → cube-level → pe-level.
num_cubes is cubes per SIP (not total).
ShardSpec.pe_index uses flat indexing:
sip_id * num_cubes * num_pe + cube_id * num_pe + pe_id
"""
_PE_RESOLVERS = {
"replicate": replicate,
@@ -35,40 +62,31 @@ def resolve_dp_policy(
if resolver is None:
raise ValueError(f"Unknown pe-level policy: {policy.pe}")
if num_cubes <= 1:
return resolver(shape=shape, itemsize=itemsize, num_pe=num_pe)
# Two-level resolution: cube-level → pe-level
M, K = shape
cubes_per_sip = num_cubes
all_shards: list[ShardSpec] = []
for cube_id in range(num_cubes):
# Determine per-cube shape based on cube-level policy
if policy.cube == "replicate":
cube_shape = (M, K)
cube_offset = 0
elif policy.cube == "shard_m":
chunk_m = M // num_cubes
cube_shape = (chunk_m, K)
cube_offset = cube_id * chunk_m * K * itemsize
elif policy.cube == "shard_k":
chunk_k = K // num_cubes
cube_shape = (M, chunk_k)
cube_offset = cube_id * M * chunk_k * itemsize
else:
raise ValueError(f"Unknown cube-level policy: {policy.cube}")
# Level 1: SIP
sip_splits = _split_shape(policy.sip, shape, num_sips, itemsize)
# Resolve pe-level within this cube's shape
pe_shards = resolver(shape=cube_shape, itemsize=itemsize, num_pe=num_pe)
for sip_id, (sip_shape, sip_offset) in enumerate(sip_splits):
# Level 2: Cube within SIP
cube_splits = _split_shape(policy.cube, sip_shape, cubes_per_sip, itemsize)
# Remap pe_index to flat index and adjust offset
for ps in pe_shards:
flat_idx = cube_id * num_pe + ps.pe_index
all_shards.append(ShardSpec(
pe_index=flat_idx,
offset_bytes=cube_offset + ps.offset_bytes,
nbytes=ps.nbytes,
))
for cube_id, (cube_shape, cube_offset) in enumerate(cube_splits):
# Level 3: PE within cube
pe_shards = resolver(shape=cube_shape, itemsize=itemsize, num_pe=num_pe)
for ps in pe_shards:
flat_idx = (
sip_id * cubes_per_sip * num_pe
+ cube_id * num_pe
+ ps.pe_index
)
all_shards.append(ShardSpec(
pe_index=flat_idx,
offset_bytes=sip_offset + cube_offset + ps.offset_bytes,
nbytes=ps.nbytes,
))
return all_shards