Skip to content

Commit cedf2f3

Browse files
committed
refactor: optimize thread indexing using metal intrinsics and simplify sigmoid activation implementation
1 parent 8106b17 commit cedf2f3

2 files changed

Lines changed: 16 additions & 32 deletions

File tree

cppmega_mlx/nn/_tilelang/mamba3_path_c.py

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -981,9 +981,8 @@ def snapshots(
981981
h0: T.Tensor((BATCH, HEADS, HEADDIM, STATE), h0_dtype),
982982
h_snap: T.Tensor((BATCH, BLOCKS + 1, HEADS, HEADDIM, STATE), "float32"),
983983
):
984-
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as bx:
985-
tid = T.get_thread_binding(0)
986-
global_lane = bx * THREADS + tid
984+
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as _bx:
985+
global_lane = T.call_intrin("int32", "tir.metal.thread_position_in_grid_x")
987986
h_state = T.alloc_local((STATE,), accum_dtype)
988987
if global_lane < LANES:
989988
p = global_lane % HEADDIM
@@ -1120,9 +1119,8 @@ def bwd_simd(
11201119
dD_batch: T.Tensor((BATCH, HEADS), dD_dtype),
11211120
dh0: T.Tensor((BATCH, HEADS, HEADDIM, STATE), dh0_dtype),
11221121
):
1123-
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as bx:
1124-
tid = T.get_thread_binding(0)
1125-
global_lane = bx * THREADS + tid
1122+
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as _bx:
1123+
global_lane = T.call_intrin("int32", "tir.metal.thread_position_in_grid_x")
11261124
h_state = T.alloc_local((STATE,), accum_dtype)
11271125
dh = T.alloc_local((STATE,), accum_dtype)
11281126
if global_lane < LANES:
@@ -1161,12 +1159,7 @@ def bwd_simd(
11611159
y_state += h_state[n] * T.cast(C[b, t, h, n], accum_dtype)
11621160
D_h = T.cast(D[h], accum_dtype)
11631161
y_skipped = y_state + D_h * x_val
1164-
sig_z = T.alloc_var(T.float32, init=0.0)
1165-
if z_val >= 0.0:
1166-
sig_z = 1.0 / (1.0 + T.exp(-z_val))
1167-
else:
1168-
sig_z = T.exp(z_val)
1169-
sig_z = sig_z / (1.0 + sig_z)
1162+
sig_z = 1.0 / (1.0 + T.exp(-z_val))
11701163
silu_z = z_val * sig_z
11711164
silu_dz = sig_z * (1.0 + z_val * (1.0 - sig_z))
11721165

@@ -1329,9 +1322,8 @@ def bwd_snap_simd(
13291322
dD_batch: T.Tensor((BATCH, HEADS), dD_dtype),
13301323
dh0: T.Tensor((BATCH, HEADS, HEADDIM, STATE), dh0_dtype),
13311324
):
1332-
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as bx:
1333-
tid = T.get_thread_binding(0)
1334-
global_lane = bx * THREADS + tid
1325+
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as _bx:
1326+
global_lane = T.call_intrin("int32", "tir.metal.thread_position_in_grid_x")
13351327
h_state = T.alloc_local((STATE,), accum_dtype)
13361328
dh = T.alloc_local((STATE,), accum_dtype)
13371329
if global_lane < LANES:
@@ -1368,12 +1360,7 @@ def bwd_snap_simd(
13681360
accum_dtype,
13691361
)
13701362
y_skipped = y_state + D_h * x_val
1371-
sig_z = T.alloc_var(T.float32, init=0.0)
1372-
if z_val >= 0.0:
1373-
sig_z = 1.0 / (1.0 + T.exp(-z_val))
1374-
else:
1375-
sig_z = T.exp(z_val)
1376-
sig_z = sig_z / (1.0 + sig_z)
1363+
sig_z = 1.0 / (1.0 + T.exp(-z_val))
13771364
silu_z = z_val * sig_z
13781365
silu_dz = sig_z * (1.0 + z_val * (1.0 - sig_z))
13791366

@@ -1515,9 +1502,8 @@ def bwd_partial(
15151502
dD_partial: T.Tensor((BATCH, HEADS, HEADDIM), dD_dtype),
15161503
dh0: T.Tensor((BATCH, HEADS, HEADDIM, STATE), dh0_dtype),
15171504
):
1518-
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as bx:
1519-
tid = T.get_thread_binding(0)
1520-
global_lane = bx * THREADS + tid
1505+
with T.Kernel(T.ceildiv(LANES, THREADS), threads=THREADS) as _bx:
1506+
global_lane = T.call_intrin("int32", "tir.metal.thread_position_in_grid_x")
15211507
h_state = T.alloc_local((STATE,), accum_dtype)
15221508
dh = T.alloc_local((STATE,), accum_dtype)
15231509
if global_lane < LANES:
@@ -1544,12 +1530,7 @@ def bwd_partial(
15441530
h_state[n] = h_snap[b, t + 1, h, p, n]
15451531
y_state += h_state[n] * T.cast(C[b, t, h, n], accum_dtype)
15461532
y_skipped = y_state + D_h * x_val
1547-
sig_z = T.alloc_var(T.float32, init=0.0)
1548-
if z_val >= 0.0:
1549-
sig_z = 1.0 / (1.0 + T.exp(-z_val))
1550-
else:
1551-
sig_z = T.exp(z_val)
1552-
sig_z = sig_z / (1.0 + sig_z)
1533+
sig_z = 1.0 / (1.0 + T.exp(-z_val))
15531534
silu_z = z_val * sig_z
15541535
silu_dz = sig_z * (1.0 + z_val * (1.0 - sig_z))
15551536

tests/test_tilelang_mamba3_path_c.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,13 +361,16 @@ def test_lowered_msl_reuses_hot_scalar_temporaries() -> None:
361361
assert re.search(r"z_val \* \([^;\n]+exp\(", fwd) is None
362362

363363
bwd = dump_lowered_bwd_msl(batch=1, seq=4, heads=1, headdim=2, state=4)
364+
assert "gridThreadIdx [[thread_position_in_grid]]" in bwd
365+
assert "blockIdx.x) * 256) + (((int)threadIdx.x)" not in bwd
364366
assert len(re.findall(r"float decay = exp\(", bwd)) == 1
365367
assert "h_snap" in bwd
366368
assert "1.000000e+00 / decay" not in bwd
367369
assert re.search(r"d_decay\[0\] \* exp\(", bwd) is None
368370
assert re.search(r"dh\[n_\d+\] = \(dh\[n_\d+\] \* exp\(", bwd) is None
369-
assert len(re.findall(r"sig_z = .*exp\(", bwd)) == 2
370-
assert "sig_z = exp(z_val)" in bwd
371+
assert "if (0.000000e+00f <= z_val)" not in bwd
372+
assert "sig_z = exp(z_val)" not in bwd
373+
assert "1.000000e+00f + exp(" in bwd
371374
assert re.search(r"dY \* \(z_val \* \([^;\n]+exp\(", bwd) is None
372375
assert "y_state = sig_z" not in bwd
373376
assert "dx_inp = sig_z" not in bwd

0 commit comments

Comments
 (0)