Skip to content

Commit 3daaf6a

Browse files
authored
Metax c550 operator fixes (#5337)
1 parent b942ed1 commit 3daaf6a

15 files changed

Lines changed: 785 additions & 414 deletions

src/flag_gems/runtime/backend/_metax/heuristics_config_utils.py

Lines changed: 133 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,6 @@
1616
import triton
1717

1818

19-
def _metax_max_num_warps():
20-
"""Return the maximum number of warps safe on the current device.
21-
22-
MetaX C550 has warp_size=64 and max 512 threads per block, so
23-
max safe num_warps is 8 (64*8=512). For standard warp_size=32
24-
devices this returns 16, preserving existing behavior.
25-
"""
26-
props = torch.cuda.get_device_properties(torch.cuda.current_device())
27-
return 512 // props.warp_size
28-
29-
3019
def simple_elementwise_blocksize_heur(args):
3120
return 512
3221

@@ -39,6 +28,110 @@ def argmax_heur_block_n(args):
3928
return min(4096, triton.next_power_of_2(args["N"]))
4029

4130

31+
def argmax_heur_tile_k(args):
32+
MAX_TILE_K = 512
33+
NUM_SMS = torch.cuda.get_device_properties(
34+
torch.cuda.current_device()
35+
).multi_processor_count
36+
37+
K = args["K"]
38+
M = args["M"]
39+
40+
if K <= 128:
41+
return 1 << (K.bit_length() - 1) if K > 0 else 1
42+
43+
tile_k = 64
44+
upper_bound = min(K, MAX_TILE_K)
45+
46+
while tile_k <= upper_bound:
47+
num_blocks = M * triton.cdiv(K, tile_k)
48+
num_waves = num_blocks / NUM_SMS
49+
if num_waves > 1 and (tile_k * 2 <= upper_bound):
50+
tile_k *= 2
51+
else:
52+
break
53+
54+
return tile_k
55+
56+
57+
def argmax_heur_tile_n_non_inner(args):
58+
n = args["N"]
59+
tile_k = args["TILE_K"]
60+
61+
if n <= 128:
62+
return n
63+
64+
target_tile = min(8192, n)
65+
tile_n = triton.next_power_of_2(target_tile)
66+
tile_n = max(64, min(tile_n, 4096))
67+
68+
if tile_n * tile_k > 32768:
69+
tile_n = max(64, 32768 // tile_k)
70+
71+
return tile_n
72+
73+
74+
def argmax_heur_tile_n_inner(args):
75+
if args["N"] <= (32 * 1024):
76+
return triton.next_power_of_2(args["N"])
77+
else:
78+
return 4096
79+
80+
81+
def argmax_heur_one_tile_per_cta(args):
82+
return args["TILE_N"] >= args["N"]
83+
84+
85+
def argmax_heur_num_warps_non_inner(args):
86+
tile_n = args["TILE_N"]
87+
if tile_n <= 64:
88+
return 4
89+
else:
90+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
91+
92+
93+
def argmax_heur_num_warps_inner(args):
94+
tile_size = args["TILE_N"]
95+
if tile_size < 2048:
96+
return 4
97+
else:
98+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
99+
100+
101+
def mean_heur_tile_k(args):
102+
MAX_TILE_K = 512
103+
NUM_SMS = torch.cuda.get_device_properties(
104+
torch.cuda.current_device()
105+
).multi_processor_count
106+
tile_k = 1
107+
upper_bound = min(args["K"], MAX_TILE_K)
108+
while tile_k <= upper_bound:
109+
num_blocks = args["M"] * triton.cdiv(args["K"], tile_k)
110+
num_waves = num_blocks / NUM_SMS
111+
if (num_waves > 1) and (tile_k * 2 <= upper_bound):
112+
tile_k *= 2
113+
else:
114+
break
115+
return tile_k
116+
117+
118+
def mean_heur_tile_n_non_inner(args):
119+
tile_k = args.get("TILE_K", 1)
120+
n = args["N"]
121+
if n <= 128:
122+
return n
123+
target_tile = min(8192, n)
124+
tile_n = triton.next_power_of_2(target_tile)
125+
tile_n = max(64, min(tile_n, 4096))
126+
if tile_n * tile_k > 32768:
127+
tile_n = max(64, 32768 // tile_k)
128+
return tile_n
129+
130+
131+
def mean_heur_one_tile_per_cta(args):
132+
return args["TILE_N"] >= args["N"]
133+
134+
42135
def bmm_heur_divisible_m(args):
43136
return args["M"] % args["TILE_M"] == 0
44137

@@ -69,10 +162,8 @@ def dropout_heur_block(args):
69162
def dropout_heur_num_warps(args):
70163
if args["N"] <= 512:
71164
return 4
72-
elif args["N"] <= 1024:
73-
return 8
74165
else:
75-
return _metax_max_num_warps()
166+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
76167

77168

78169
def exponential_heur_block(args):
@@ -85,10 +176,8 @@ def exponential_heur_block(args):
85176
def exponential_heur_num_warps(args):
86177
if args["N"] <= 512:
87178
return 4
88-
elif args["N"] <= 1024:
89-
return 8
90179
else:
91-
return _metax_max_num_warps()
180+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
92181

93182

94183
def gather_heur_block_m(args):
@@ -149,10 +238,8 @@ def rand_heur_block(args):
149238
def rand_heur_num_warps(args):
150239
if args["N"] <= 512:
151240
return 4
152-
elif args["N"] <= 1024:
153-
return 8
154241
else:
155-
return _metax_max_num_warps()
242+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
156243

157244

158245
def randn_heur_block(args):
@@ -165,10 +252,8 @@ def randn_heur_block(args):
165252
def randn_heur_num_warps(args):
166253
if args["N"] <= 512:
167254
return 4
168-
elif args["N"] <= 1024:
169-
return 8
170255
else:
171-
return _metax_max_num_warps()
256+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
172257

173258

174259
def softmax_heur_tile_k(args):
@@ -201,14 +286,10 @@ def softmax_heur_num_warps_non_inner(args):
201286
tile_size = args["TILE_N"] * args["TILE_K"]
202287
if tile_size < 512:
203288
return 1
204-
elif tile_size < 256:
205-
return 2
206289
elif tile_size < 2048:
207290
return 4
208-
elif tile_size < 4096:
209-
return 8
210291
else:
211-
return _metax_max_num_warps()
292+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
212293

213294

214295
def softmax_heur_tile_n_inner(args):
@@ -222,10 +303,8 @@ def softmax_heur_num_warps_inner(args):
222303
tile_size = args["TILE_N"]
223304
if tile_size < 2048:
224305
return 4
225-
elif tile_size < 4096:
226-
return 8
227306
else:
228-
return _metax_max_num_warps()
307+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
229308

230309

231310
def softmax_heur_tile_n_bwd_non_inner(args):
@@ -246,10 +325,8 @@ def uniform_heur_block(args):
246325
def uniform_heur_num_warps(args):
247326
if args["N"] <= 512:
248327
return 4
249-
elif args["N"] <= 1024:
250-
return 8
251328
else:
252-
return _metax_max_num_warps()
329+
return 8 # MetaX C550: max 512 threads = 8 warps × 64
253330

254331

255332
def var_mean_heur_block_n(args):
@@ -269,14 +346,17 @@ def upsample_nearest2d_USE_INT32_IDX(args):
269346

270347

271348
def batch_norm_heur_block_m(args):
272-
return min(2048, triton.next_power_of_2(args["batch_dim"]))
349+
return min(512, triton.next_power_of_2(args["batch_dim"]))
273350

274351

275352
def batch_norm_heur_block_n(args):
276-
# A maximum of 16384 elements are loaded at once.
353+
# Cap total tile elements to 4096 to stay within MetaX C550 4KB/thread
354+
# private memory limit. The kernel holds 3 float32 accumulators (mean, var,
355+
# cnt) of shape (BLOCK_M, BLOCK_N) plus temporaries; 4096 elements keeps
356+
# register spill well under 4KB.
277357
BLOCK_M = batch_norm_heur_block_m(args)
278358
BLOCK_N = triton.next_power_of_2(args["spatial_dim"])
279-
return min(BLOCK_N, max(1, 2**14 // BLOCK_M))
359+
return min(BLOCK_N, max(1, 2**12 // BLOCK_M))
280360

281361

282362
def vdot_heur_block_size(args):
@@ -313,9 +393,16 @@ def zeros_heur_num_warps(args):
313393
"BLOCK_M": lambda args: 4,
314394
"BLOCK_N": lambda args: 1024,
315395
},
316-
"argmax": {
317-
"BLOCK_M": argmax_heur_block_m,
318-
"BLOCK_N": argmax_heur_block_n,
396+
"argmax_non_inner": {
397+
"TILE_K": argmax_heur_tile_k,
398+
"TILE_N": argmax_heur_tile_n_non_inner,
399+
"ONE_TILE_PER_CTA": argmax_heur_one_tile_per_cta,
400+
"num_warps": argmax_heur_num_warps_non_inner,
401+
},
402+
"argmax_inner": {
403+
"TILE_N": argmax_heur_tile_n_inner,
404+
"ONE_TILE_PER_CTA": argmax_heur_one_tile_per_cta,
405+
"num_warps": argmax_heur_num_warps_inner,
319406
},
320407
"argmin": {
321408
"BLOCK_M": argmin_heur_block_m,
@@ -375,6 +462,12 @@ def zeros_heur_num_warps(args):
375462
"ONE_TILE_PER_CTA": softmax_heur_one_tile_per_cta,
376463
"num_warps": softmax_heur_num_warps_inner,
377464
},
465+
"mean_non_inner": {
466+
"TILE_K": mean_heur_tile_k,
467+
"TILE_N": mean_heur_tile_n_non_inner,
468+
"ONE_TILE_PER_CTA": mean_heur_one_tile_per_cta,
469+
"num_warps": softmax_heur_num_warps_non_inner,
470+
},
378471
"softmax_backward_non_inner": {
379472
"TILE_N": softmax_heur_tile_n_bwd_non_inner,
380473
"ONE_TILE_PER_CTA": softmax_heur_one_tile_per_cta,

src/flag_gems/runtime/backend/_metax/ops/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from .addmm import addmm
44
from .amax import amax
55
from .arange import arange, arange_start
6-
from .batch_norm import batch_norm, batch_norm_backward
76
from .bmm import bmm
87
from .exponential_ import exponential_
98
from .full import full
@@ -18,6 +17,7 @@
1817
from .linalg_svdvals import linalg_svdvals
1918
from .log_sigmoid_forward import log_sigmoid_forward
2019
from .log_softmax import log_softmax, log_softmax_backward
20+
from .logical_or import logical_or, logical_or_
2121
from .masked_fill import masked_fill, masked_fill_
2222
from .matmul_bf16 import matmul_bf16
2323
from .matmul_int8 import matmul_int8
@@ -37,6 +37,7 @@
3737
special_shifted_chebyshev_polynomial_w,
3838
)
3939
from .tanh import tanh
40+
from .to_copy import to_copy
4041
from .unique import _unique2
4142
from .upsample_nearest2d import upsample_nearest2d
4243
from .zeros import zeros
@@ -50,8 +51,6 @@
5051
"amax",
5152
"arange",
5253
"arange_start",
53-
"batch_norm",
54-
"batch_norm_backward",
5554
"bmm",
5655
"exponential_",
5756
"full",
@@ -69,6 +68,8 @@
6968
"log_sigmoid_forward",
7069
"log_softmax",
7170
"log_softmax_backward",
71+
"logical_or",
72+
"logical_or_",
7273
"matmul_bf16",
7374
"matmul_int8",
7475
"masked_fill",
@@ -91,6 +92,7 @@
9192
"special_bessel_j0_out",
9293
"special_shifted_chebyshev_polynomial_w",
9394
"tanh",
95+
"to_copy",
9496
"upsample_nearest2d",
9597
"zeros",
9698
"zeros_like",

0 commit comments

Comments
 (0)