Skip to content

Commit 656a55b

Browse files
committed
feat(v5-g05): sharding axis_assignments → extras.sharding_applied
Closes V5-G05 / cppmega-mlx-8be. UI ShardingTab selection was propagation-decorative for stage_train. v5 now reports extras.sharding_applied = {axis_assignments[], shard_dim, microbatch_size, compile_mode} so e2e can prove UI selection reaches train context. Actual distributed math is single-device for stage_train; real multi-device train deferred to v6. 1/1 e2e green; 52 stage_train pytest unchanged.
1 parent 111f3e4 commit 656a55b

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

cppmega_v4/runner/stages.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,10 +707,33 @@ def _count(tree: Any) -> int:
707707
fp8_active = False
708708
# Wire fp8_enabled from spec.sharding (payload pydantic model)
709709
ws_sharding = getattr(ctx.spec, "sharding", None)
710+
sharding_applied: dict[str, Any] | None = None
710711
if ws_sharding is not None:
711712
fp8_active = bool(getattr(ws_sharding, "fp8_enabled", False))
712713
if fp8_active:
713714
train_dtype = "fp8"
715+
# G05: surface axis_assignments so e2e can prove UI sharding
716+
# selection reaches stage_train (math is single-device for
717+
# stage_train; real distributed train is v6).
718+
axes = getattr(ws_sharding, "axis_assignments", None) or []
719+
if axes:
720+
shard_dim = 1
721+
axis_list = []
722+
for a in axes:
723+
deg = int(getattr(a, "degree", 1))
724+
shard_dim *= deg
725+
axis_list.append({
726+
"axis_name": str(getattr(a, "axis_name", "")),
727+
"kind": str(getattr(a, "kind", "")),
728+
"degree": deg,
729+
})
730+
sharding_applied = {
731+
"axis_assignments": axis_list,
732+
"shard_dim": shard_dim,
733+
"microbatch_size": max(1, batch // shard_dim),
734+
"compile_mode": str(getattr(
735+
ws_sharding, "compile_mode", "off")),
736+
}
714737

715738
# G06: memory peak instrumentation — bracket train loop with
716739
# reset_peak_memory + get_peak_memory; extras.memory_peak_bytes.
@@ -894,6 +917,7 @@ def _count(tree: Any) -> int:
894917
"graph_diff": graph_diff,
895918
"gradient_clip": clip_extras,
896919
"memory_peak_bytes": memory_peak_bytes,
920+
"sharding_applied": sharding_applied,
897921
"train_dtype": train_dtype,
898922
"master_dtype": master_dtype,
899923
"fp8_active": fp8_active,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// G05: sharding axis_assignments propagate to extras.sharding_applied.
2+
3+
import { test, expect } from "@playwright/test";
4+
import { gotoApp, selectPreset, closeModal } from "../fixtures";
5+
6+
test("G05: INITIAL_SPEC fsdp2 axis surfaces in extras.sharding_applied",
7+
async ({ page }) => {
8+
test.setTimeout(60_000);
9+
await gotoApp(page);
10+
await selectPreset(page, "llama3_8b");
11+
// Topology must match axis degree
12+
await page.getByTestId("topology-selector").selectOption("h100_8x");
13+
await page.waitForTimeout(500);
14+
await page.getByTestId("run-pipeline-toggle").click();
15+
await page.getByTestId("run-pipeline-train").click();
16+
const modal = page.getByTestId("run-result-modal");
17+
await modal.waitFor({ timeout: 60_000 });
18+
await page.getByTestId("run-result-expand-train").click();
19+
20+
const shardDim = parseInt(
21+
(await page.getByTestId(
22+
"run-result-extras-train-sharding_applied-shard_dim")
23+
.textContent()) ?? "0", 10);
24+
const compile = await page.getByTestId(
25+
"run-result-extras-train-sharding_applied-compile_mode")
26+
.textContent();
27+
// INITIAL_SPEC has fsdp2 degree=8
28+
expect(shardDim).toBe(8);
29+
expect(compile?.trim()).toMatch(/regional|off|whole_model/);
30+
await closeModal(page);
31+
});

0 commit comments

Comments
 (0)