Skip to content

Commit e4bcf77

Browse files
committed
feat: add gradient buffer tracking for entry RMSNorm layers in path-c fusion runtime
1 parent cbc15a0 commit e4bcf77

10 files changed

Lines changed: 1187 additions & 24715 deletions

.services.pid

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
backend=30112
2-
frontend=30113
1+
backend=41057
2+
frontend=41058

backend.log

Lines changed: 903 additions & 24093 deletions
Large diffs are not rendered by default.

cppmega_mlx/nn/_tilelang/_engine_dispatch.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,9 @@ def _gemm_softmax_factory(*, M: int, N: int, K: int,
451451
f"{exc.__class__.__name__}: {exc}") from exc
452452

453453
@T.prim_func
454-
def gemm_softmax(Q: T.Buffer((M, K), in_dtype),
455-
K_buf: T.Buffer((N, K), in_dtype),
456-
Out: T.Buffer((M, N), out_dtype)):
454+
def gemm_softmax(Q: T.Tensor((M, K), in_dtype),
455+
K_buf: T.Tensor((N, K), in_dtype),
456+
Out: T.Tensor((M, N), out_dtype)):
457457
# Fused: Out = softmax(Q @ K^T) along axis=-1.
458458
with T.Kernel(M) as i:
459459
row = T.alloc_fragment((N,), "float32")

cppmega_mlx/runtime/path_c_fusion_launcher.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ def __init__(self, compiled: Any) -> None:
263263
self._kernel = compiled.compiled.artifact
264264
self._prim_func = self._kernel.prim_func
265265
self.manifest = load_path_c_abi_manifest(self._prim_func)
266+
self._result_param_indices = tuple(
267+
int(idx)
268+
for idx in self._prim_func.attrs.get("tilelang_out_idx", ())
269+
)
266270

267271
# --- inspection ------------------------------------------------------
268272

@@ -420,8 +424,42 @@ def __call__(
420424
f"not present in banks, dtype scratch, or top-level scratch"
421425
)
422426

423-
# Launch.
424-
self._kernel(*positional)
427+
# Launch. Descriptor schedules mark every ABI parameter as a native
428+
# owner-output/inout buffer; keep the returned aliases in the manifest
429+
# maps so extraction reads the MLX graph value produced by TileLang.
430+
returned = self._kernel(*positional)
431+
if returned is not None:
432+
returned_outputs = (
433+
[returned]
434+
if isinstance(returned, mx.array)
435+
else list(returned)
436+
)
437+
if returned_outputs:
438+
result_indices = self._result_param_indices
439+
if len(returned_outputs) != len(result_indices):
440+
raise ValueError(
441+
"Path C TileLang kernel returned "
442+
f"{len(returned_outputs)} owner outputs for "
443+
f"{len(result_indices)} result ABI parameters"
444+
)
445+
for param_index, value in zip(
446+
result_indices,
447+
returned_outputs,
448+
strict=True,
449+
):
450+
param_name = manifest.param_order[param_index]
451+
logical_name = (
452+
param_name[: -len("_handle")]
453+
if param_name.endswith("_handle")
454+
else param_name
455+
)
456+
if logical_name in banks:
457+
banks[logical_name] = value
458+
elif logical_name in scratch_buffers:
459+
scratch_buffers[logical_name] = value
460+
elif logical_name in top_level_buffers:
461+
top_level_buffers[logical_name] = value
462+
positional[param_index] = value
425463
# Force the lazy MLX graph to materialise so subsequent reads see the writes.
426464
mx.eval(*positional)
427465

cppmega_mlx/runtime/path_c_fusion_schedules.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,15 @@ def build_path_c_descriptor_prim_func(
12751275
"tilelang_pass_configs",
12761276
compile_pass_configs,
12771277
)
1278+
owner_output_param_indices = tuple(range(len(physical_abi_plan.param_lines)))
1279+
if owner_output_param_indices:
1280+
prim_func = prim_func.with_attr(
1281+
"tilelang_out_idx",
1282+
list(owner_output_param_indices),
1283+
).with_attr(
1284+
"tilelang_metal_zero_init_output_positions",
1285+
[],
1286+
)
12781287
prim_func._cppmega_path_c_schedule_generator = PATH_C_DESCRIPTOR_SCHEDULE_GENERATOR
12791288
prim_func._cppmega_path_c_brick_ops = tuple(
12801289
descriptor.op_name for descriptor in descriptors
@@ -1546,7 +1555,7 @@ def _descriptor_prim_func_source(
15461555
param_lines = list(physical_abi_plan.param_lines)
15471556
if not param_lines:
15481557
param_lines = [
1549-
f"{indent}_dummy: T.Buffer(({buffer_extent},), \"float32\"),"
1558+
f"{indent}_dummy: T.Tensor(({buffer_extent},), \"float32\"),"
15501559
]
15511560
access_by_buffer = {
15521561
buffer_name: _internal_buffer_ref(
@@ -2745,7 +2754,7 @@ def _spill_large_shared_scratch_to_abi(
27452754
raise ValueError("descriptor source did not contain a function signature close")
27462755
param_indent = " " * 4
27472756
spill_param_lines = [
2748-
f'{param_indent}{info["param_name"]}: T.Buffer({_shape_literal(info["shape"])}, '
2757+
f'{param_indent}{info["param_name"]}: T.Tensor({_shape_literal(info["shape"])}, '
27492758
f'"{info["dtype"]}"),'
27502759
for name, info in spilled.items()
27512760
]
@@ -2866,7 +2875,7 @@ def _physical_abi_plan(
28662875
}
28672876
param_lines = tuple(
28682877
f"{indent}{_physical_abi_bank_name(dtype)}: "
2869-
f"T.Buffer({_shape_literal(physical_shapes[_physical_abi_bank_name(dtype)])}, "
2878+
f"T.Tensor({_shape_literal(physical_shapes[_physical_abi_bank_name(dtype)])}, "
28702879
f"\"{dtype}\"),"
28712880
for dtype in bank_order
28722881
)
@@ -2920,7 +2929,7 @@ def _direct_physical_abi_plan(
29202929
for buffer_name in external_buffers
29212930
}
29222931
param_lines = tuple(
2923-
f"{indent}{name}: T.Buffer({_shape_literal(direct_shape_by_buffer[name])}, "
2932+
f"{indent}{name}: T.Tensor({_shape_literal(direct_shape_by_buffer[name])}, "
29242933
f"\"{dtype_by_buffer[name]}\"),"
29252934
for name in external_buffers
29262935
)

0 commit comments

Comments
 (0)