Skip to content

Commit 80c7d57

Browse files
committed
refactor: update Path-C training to use single-kernel fused launcher artifacts and add corresponding tests.
1 parent 93277d1 commit 80c7d57

38 files changed

Lines changed: 1945 additions & 75 deletions

cppmega_mlx/runtime/path_c_fusion_schedules.py

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
DESCRIPTOR_PORTABLE_KERNEL_BUFFER_LIMIT = 31
125125
DESCRIPTOR_SHARED_SCRATCH_SPILL_THRESHOLD_BYTES = 1024
126126
DESCRIPTOR_SHARED_SCRATCH_BUDGET_BYTES = 12 * 1024
127-
MAMBA3_BWD_REPLAY_CHECKPOINT_INTERVAL = 64
127+
MAMBA3_BWD_REPLAY_CHECKPOINT_INTERVAL = 8
128128
M2RNN_BWD_REPLAY_CHECKPOINT_INTERVAL = 1
129129
_DESCRIPTOR_ROOT_READS_MARKER = "cppmega_path_c_root_reads"
130130
_DESCRIPTOR_ROOT_WRITES_MARKER = "cppmega_path_c_root_writes"
@@ -430,6 +430,7 @@ class PathCDescriptorScheduleStageGroup:
430430
active_node_names: tuple[str, ...]
431431
stage_suffix: str
432432
row_dispatch_mode: str
433+
rows_per_kernel_launch: int
433434
reason: str
434435

435436

@@ -488,6 +489,13 @@ def _path_c_descriptor_stage_node_op_name(node: Any) -> str:
488489
return str(getattr(node, "op_name", ""))
489490

490491

492+
def _path_c_descriptor_stage_rows_per_kernel_launch_for_node(node: Any) -> int:
493+
op_name = _path_c_descriptor_stage_node_op_name(node)
494+
if op_name in {"attention_qkv_projection_bwd", "mamba3_mimo_bwd"}:
495+
return 1
496+
return DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH
497+
498+
491499
def _path_c_descriptor_stage_append(
492500
groups: list[PathCDescriptorScheduleStageGroup],
493501
*,
@@ -496,6 +504,7 @@ def _path_c_descriptor_stage_append(
496504
active_node_names: Sequence[str],
497505
reason: str,
498506
row_dispatch_mode: str = DESCRIPTOR_ROW_DISPATCH_LAUNCHER_CHUNKS,
507+
rows_per_kernel_launch: int = DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH,
499508
) -> None:
500509
names = tuple(str(name) for name in active_node_names if str(name))
501510
if not names:
@@ -510,6 +519,9 @@ def _path_c_descriptor_stage_append(
510519
active_node_names=names,
511520
stage_suffix=f"{prefix}{stage_index}",
512521
row_dispatch_mode=validated_mode,
522+
rows_per_kernel_launch=_validated_rows_per_kernel_launch(
523+
rows_per_kernel_launch
524+
),
513525
reason=reason,
514526
)
515527
)
@@ -592,6 +604,11 @@ def plan_path_c_descriptor_stage_groups(
592604
stage_index=backward_index,
593605
active_node_names=(name,),
594606
reason=f"descriptor_isolates_backward_{op_name}_fragment",
607+
rows_per_kernel_launch=(
608+
_path_c_descriptor_stage_rows_per_kernel_launch_for_node(
609+
node
610+
)
611+
),
595612
)
596613
backward_consumed.add(name)
597614
backward_index += 1
@@ -606,6 +623,9 @@ def plan_path_c_descriptor_stage_groups(
606623
stage_index=backward_index,
607624
active_node_names=(name,),
608625
reason="descriptor_keeps_backward_block_as_generated_stage",
626+
rows_per_kernel_launch=(
627+
_path_c_descriptor_stage_rows_per_kernel_launch_for_node(node)
628+
),
609629
)
610630
backward_consumed.add(name)
611631
backward_index += 1
@@ -666,6 +686,7 @@ def make_path_c_descriptor_stage_schedule_template(
666686
active_node_names: Sequence[str] | None = None,
667687
stage_suffix: str = "",
668688
row_dispatch_mode: str = DESCRIPTOR_ROW_DISPATCH_LAUNCHER_CHUNKS,
689+
rows_per_kernel_launch: int = DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH,
669690
) -> Callable[[Any], Any]:
670691
"""Build a generated stage template with the train-block ABI contract.
671692

@@ -697,6 +718,7 @@ def make_path_c_descriptor_stage_schedule_template(
697718
),
698719
max_rows_per_launch=schedule_target.max_rows_per_launch,
699720
row_dispatch_mode=row_dispatch_mode,
721+
rows_per_kernel_launch=rows_per_kernel_launch,
700722
execution_stage=execution_stage,
701723
active_node_names=active_node_names,
702724
),
@@ -728,6 +750,7 @@ def path_c_descriptor_stage_prim_funcs(
728750
active_node_names=group.active_node_names,
729751
stage_suffix=group.stage_suffix,
730752
row_dispatch_mode=group.row_dispatch_mode,
753+
rows_per_kernel_launch=group.rows_per_kernel_launch,
731754
)
732755
for group in stage_groups
733756
)
@@ -1317,6 +1340,7 @@ def make_path_c_descriptor_schedule_template(
13171340
train_step_output_abi: bool = False,
13181341
max_rows_per_launch: int | None = None,
13191342
row_dispatch_mode: str = DESCRIPTOR_DEFAULT_ROW_DISPATCH_MODE,
1343+
rows_per_kernel_launch: int = DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH,
13201344
execution_stage: str = DESCRIPTOR_EXECUTION_STAGE_ALL,
13211345
active_node_names: Sequence[str] | None = None,
13221346
) -> Callable[[Any], Any]:
@@ -1337,6 +1361,9 @@ def make_path_c_descriptor_schedule_template(
13371361
max_rows_per_launch
13381362
)
13391363
validated_row_dispatch_mode = _validated_row_dispatch_mode(row_dispatch_mode)
1364+
validated_rows_per_kernel_launch = _validated_rows_per_kernel_launch(
1365+
rows_per_kernel_launch
1366+
)
13401367
validated_execution_stage = _validated_execution_stage(execution_stage)
13411368
active_node_names_tuple = (
13421369
tuple(str(name) for name in active_node_names)
@@ -1357,6 +1384,7 @@ def descriptor_schedule_template(template_region: Any) -> Any:
13571384
train_step_output_abi=bool(train_step_output_abi),
13581385
max_rows_per_launch=validated_max_rows_per_launch,
13591386
row_dispatch_mode=validated_row_dispatch_mode,
1387+
rows_per_kernel_launch=validated_rows_per_kernel_launch,
13601388
execution_stage=validated_execution_stage,
13611389
active_node_names=active_node_names_tuple,
13621390
)
@@ -1383,6 +1411,9 @@ def descriptor_schedule_template(template_region: Any) -> Any:
13831411
descriptor_schedule_metadata._cppmega_path_c_row_dispatch_mode = (
13841412
validated_row_dispatch_mode
13851413
)
1414+
descriptor_schedule_metadata._cppmega_path_c_rows_per_kernel_launch = (
1415+
validated_rows_per_kernel_launch
1416+
)
13861417
descriptor_schedule_metadata._cppmega_path_c_execution_stage = (
13871418
validated_execution_stage
13881419
)
@@ -1461,6 +1492,7 @@ def build_path_c_descriptor_prim_func(
14611492
train_step_output_abi: bool = False,
14621493
max_rows_per_launch: int | None = None,
14631494
row_dispatch_mode: str = DESCRIPTOR_DEFAULT_ROW_DISPATCH_MODE,
1495+
rows_per_kernel_launch: int = DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH,
14641496
execution_stage: str = DESCRIPTOR_EXECUTION_STAGE_ALL,
14651497
active_node_names: Sequence[str] | None = None,
14661498
) -> Any:
@@ -1486,6 +1518,9 @@ def build_path_c_descriptor_prim_func(
14861518
max_rows_per_launch
14871519
)
14881520
validated_row_dispatch_mode = _validated_row_dispatch_mode(row_dispatch_mode)
1521+
validated_rows_per_kernel_launch = _validated_rows_per_kernel_launch(
1522+
rows_per_kernel_launch
1523+
)
14891524
validated_execution_stage = _validated_execution_stage(execution_stage)
14901525
active_node_name_set = (
14911526
frozenset(str(name) for name in active_node_names)
@@ -1508,10 +1543,10 @@ def build_path_c_descriptor_prim_func(
15081543
1,
15091544
(
15101545
int(validated_max_rows_per_launch)
1511-
+ DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH
1546+
+ validated_rows_per_kernel_launch
15121547
- 1
15131548
)
1514-
// DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH,
1549+
// validated_rows_per_kernel_launch,
15151550
)
15161551
if (
15171552
row_chunk_count is not None
@@ -1662,6 +1697,7 @@ def build_path_c_descriptor_prim_func(
16621697
loop_policy=validated_loop_policy,
16631698
max_rows_per_launch=validated_max_rows_per_launch,
16641699
row_dispatch_mode=validated_row_dispatch_mode,
1700+
rows_per_kernel_launch=validated_rows_per_kernel_launch,
16651701
execution_stage=validated_execution_stage,
16661702
active_node_names=active_node_name_set,
16671703
external_buffers=external_buffers_for_abi,
@@ -1780,7 +1816,7 @@ def build_path_c_descriptor_prim_func(
17801816
DESCRIPTOR_ROW_SUBCHUNK_INDEX_PARAM,
17811817
).with_attr(
17821818
"tl.fusion.rows_per_kernel_launch",
1783-
DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH,
1819+
validated_rows_per_kernel_launch,
17841820
).with_attr(
17851821
"tl.fusion.row_subchunk_count",
17861822
row_subchunk_count,
@@ -1834,6 +1870,9 @@ def build_path_c_descriptor_prim_func(
18341870
prim_func._cppmega_path_c_physical_abi_policy = validated_physical_abi_policy
18351871
prim_func._cppmega_path_c_max_rows_per_launch = validated_max_rows_per_launch
18361872
prim_func._cppmega_path_c_row_dispatch_mode = validated_row_dispatch_mode
1873+
prim_func._cppmega_path_c_rows_per_kernel_launch = (
1874+
validated_rows_per_kernel_launch
1875+
)
18371876
prim_func._cppmega_path_c_execution_stage = validated_execution_stage
18381877
prim_func._cppmega_path_c_active_node_names = tuple(
18391878
sorted(active_node_name_set or ())
@@ -2180,6 +2219,7 @@ def _descriptor_prim_func_source(
21802219
loop_policy: str,
21812220
max_rows_per_launch: int | None,
21822221
row_dispatch_mode: str,
2222+
rows_per_kernel_launch: int,
21832223
execution_stage: str,
21842224
active_node_names: frozenset[str] | None,
21852225
external_buffers: Sequence[str],
@@ -2360,6 +2400,7 @@ def _descriptor_prim_func_source(
23602400
),
23612401
max_rows_per_launch=max_rows_per_launch,
23622402
row_dispatch_mode=row_dispatch_mode,
2403+
rows_per_kernel_launch=rows_per_kernel_launch,
23632404
execution_stage=execution_stage,
23642405
active_node_names=active_node_names,
23652406
indent=indent,
@@ -4409,6 +4450,7 @@ def _append_row_phased_hidden_body(
44094450
train_step_loss_parameter_grad_buffers: Sequence[str],
44104451
max_rows_per_launch: int | None,
44114452
row_dispatch_mode: str,
4453+
rows_per_kernel_launch: int,
44124454
execution_stage: str,
44134455
active_node_names: frozenset[str] | None,
44144456
indent: str,
@@ -4450,8 +4492,8 @@ def _append_row_phased_hidden_body(
44504492
)
44514493
subchunk_count = max(
44524494
1,
4453-
(int(max_rows_per_launch) + DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH - 1)
4454-
// DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH,
4495+
(int(max_rows_per_launch) + int(rows_per_kernel_launch) - 1)
4496+
// int(rows_per_kernel_launch),
44554497
)
44564498
row_chunk_assumptions = (
44574499
f"{indent * 2}T.assume({row_chunk_expr} >= 0)",
@@ -4671,13 +4713,13 @@ def append_forward_phase(lines: Sequence[str]) -> None:
46714713
f"{indent * 2}subchunk_row_chunk_start = "
46724714
f"T.min(logical_row_chunk_start + "
46734715
f"{DESCRIPTOR_ROW_SUBCHUNK_INDEX_PARAM} * "
4674-
f"{DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH}, "
4716+
f"{rows_per_kernel_launch}, "
46754717
"logical_row_chunk_stop)"
46764718
)
46774719
body.append(
46784720
f"{indent * 2}subchunk_row_chunk_stop = "
46794721
f"T.min(subchunk_row_chunk_start + "
4680-
f"{DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH}, "
4722+
f"{rows_per_kernel_launch}, "
46814723
"logical_row_chunk_stop)"
46824724
)
46834725
body.append(f"{indent * 2}row_chunk_start = subchunk_row_chunk_start")
@@ -4729,13 +4771,13 @@ def append_forward_phase(lines: Sequence[str]) -> None:
47294771
f"{indent * 2}subchunk_row_chunk_start = "
47304772
f"T.min(logical_row_chunk_start + "
47314773
f"{DESCRIPTOR_ROW_SUBCHUNK_INDEX_PARAM} * "
4732-
f"{DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH}, "
4774+
f"{rows_per_kernel_launch}, "
47334775
"logical_row_chunk_stop)"
47344776
)
47354777
body.append(
47364778
f"{indent * 2}subchunk_row_chunk_stop = "
47374779
f"T.min(subchunk_row_chunk_start + "
4738-
f"{DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH}, "
4780+
f"{rows_per_kernel_launch}, "
47394781
"logical_row_chunk_stop)"
47404782
)
47414783
body.append(f"{indent * 2}row_chunk_start = subchunk_row_chunk_start")
@@ -4864,13 +4906,13 @@ def append_forward_phase(lines: Sequence[str]) -> None:
48644906
f"{indent * 2}subchunk_row_chunk_start = "
48654907
f"T.min(logical_row_chunk_start + "
48664908
f"{DESCRIPTOR_ROW_SUBCHUNK_INDEX_PARAM} * "
4867-
f"{DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH}, "
4909+
f"{rows_per_kernel_launch}, "
48684910
"logical_row_chunk_stop)"
48694911
)
48704912
body.append(
48714913
f"{indent * 2}subchunk_row_chunk_stop = "
48724914
f"T.min(subchunk_row_chunk_start + "
4873-
f"{DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH}, "
4915+
f"{rows_per_kernel_launch}, "
48744916
"logical_row_chunk_stop)"
48754917
)
48764918
body.append(f"{indent * 2}row_chunk_start = subchunk_row_chunk_start")
@@ -9087,7 +9129,11 @@ def _append_row_phased_m2rnn_bwd_body(
90879129
body.append(f"{indent * 3}{scalar0} = T.alloc_local((1,), \"float32\")")
90889130
body.append(f"{indent * 3}{scalar1} = T.alloc_local((1,), \"float32\")")
90899131
body.append(f"{indent * 3}{scalar2} = T.alloc_local((1,), \"float32\")")
9090-
first_row_condition = "path_c_first_row_launch != 0" if launcher_chunked_rows else "row == 0"
9132+
first_row_condition = (
9133+
"path_c_first_row_launch != 0 and row == row_chunk_start"
9134+
if launcher_chunked_rows
9135+
else "row == 0"
9136+
)
90919137
time_rev_range = "row, row + 1" if launcher_chunked_rows else f"0, {sequence_length}"
90929138
body.append(f"{indent * 3}if {first_row_condition}:")
90939139
body.append(f"{indent * 4}if lane == 0:")
@@ -10402,7 +10448,9 @@ def _mamba3_emit_recompute_row(
1040210448
):
1040310449
body.append(f"{indent * 3}{scalar} = T.alloc_local((1,), \"float32\")")
1040410450
first_row_condition = (
10405-
"path_c_first_row_launch != 0" if launcher_chunked_rows else "row == 0"
10451+
"path_c_first_row_launch != 0 and row == row_chunk_start"
10452+
if launcher_chunked_rows
10453+
else "row == 0"
1040610454
)
1040710455
time_rev_range = "row, row + 1" if launcher_chunked_rows else f"0, {sequence_length}"
1040810456
body.append(f"{indent * 3}if {first_row_condition}:")
@@ -11237,6 +11285,17 @@ def _validated_max_rows_per_launch(max_rows_per_launch: int | None) -> int | Non
1123711285
return rows
1123811286

1123911287

11288+
def _validated_rows_per_kernel_launch(rows_per_kernel_launch: int | None) -> int:
11289+
rows = (
11290+
DESCRIPTOR_ROWS_PER_KERNEL_LAUNCH
11291+
if rows_per_kernel_launch is None
11292+
else int(rows_per_kernel_launch)
11293+
)
11294+
if rows <= 0:
11295+
raise ValueError("rows_per_kernel_launch must be positive")
11296+
return rows
11297+
11298+
1124011299
def _validated_row_dispatch_mode(row_dispatch_mode: str) -> str:
1124111300
mode = str(row_dispatch_mode)
1124211301
if mode not in {

0 commit comments

Comments
 (0)