Skip to content

Commit 4b9c87a

Browse files
authored
Merge branch 'fix_triton_extra_name_on_ascend_20260225' into ascend/support_bf16
Signed-off-by: ldwang <ftgreat@163.com>
2 parents 57bf47b + d89d74d commit 4b9c87a

12 files changed

Lines changed: 1224 additions & 38 deletions

File tree

benchmark/test_binary_pointwise_perf.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,97 @@ def test_general_binary_pointwise_perf(op_name, torch_op, dtypes):
9999
bench.run()
100100

101101

102+
class BinaryScalarPointwiseBenchmark(Benchmark):
103+
"""
104+
Benchmark class for binary pointwise operations with a scalar operand.
105+
"""
106+
107+
DEFAULT_METRICS = DEFAULT_METRICS[:] + ["tflops"]
108+
109+
def set_more_shapes(self):
110+
special_shapes_2d = [(1024, 2**i) for i in range(0, 20, 4)]
111+
shapes_3d = [(64, 64, 2**i) for i in range(0, 20, 4)]
112+
return special_shapes_2d + shapes_3d
113+
114+
def get_input_iter(self, cur_dtype) -> Generator:
115+
for shape in self.shapes:
116+
inp1 = generate_tensor_input(shape, cur_dtype, self.device)
117+
inp2 = generate_tensor_input(shape, cur_dtype, self.device)
118+
yield inp1, inp2
119+
120+
def get_tflops(self, op, *args, **kwargs):
121+
shape1 = list(args[0].shape)
122+
return torch.tensor(shape1).prod().item()
123+
124+
125+
@pytest.mark.parametrize(
126+
"op_name, torch_op, dtypes",
127+
[
128+
pytest.param(
129+
"ne_scalar",
130+
torch.ne,
131+
FLOAT_DTYPES,
132+
marks=pytest.mark.ne,
133+
),
134+
pytest.param(
135+
"lt_scalar",
136+
torch.lt,
137+
FLOAT_DTYPES,
138+
marks=pytest.mark.lt,
139+
),
140+
pytest.param(
141+
"ge_scalar",
142+
torch.ge,
143+
FLOAT_DTYPES,
144+
marks=pytest.mark.ge,
145+
),
146+
],
147+
)
148+
def test_binary_scalar_pointwise_perf(op_name, torch_op, dtypes):
149+
bench = BinaryScalarPointwiseBenchmark(
150+
op_name=op_name, torch_op=torch_op, dtypes=dtypes
151+
)
152+
bench.run()
153+
154+
155+
class BinaryTensorScalarBenchmark(Benchmark):
156+
"""
157+
Benchmark class for binary pointwise operations with tensor and scalar operands
158+
(e.g., pow_tensor_scalar).
159+
"""
160+
161+
DEFAULT_METRICS = DEFAULT_METRICS[:] + ["tflops"]
162+
163+
def __init__(self, *args, scalar=2.0, **kwargs):
164+
super().__init__(*args, **kwargs)
165+
self.scalar = scalar
166+
167+
def set_more_shapes(self):
168+
special_shapes_2d = [(1024, 2**i) for i in range(0, 20, 4)]
169+
shapes_3d = [(64, 64, 2**i) for i in range(0, 20, 4)]
170+
return special_shapes_2d + shapes_3d
171+
172+
def get_input_iter(self, cur_dtype) -> Generator:
173+
for shape in self.shapes:
174+
inp1 = generate_tensor_input(shape, cur_dtype, self.device)
175+
yield inp1, self.scalar
176+
177+
def get_tflops(self, op, *args, **kwargs):
178+
shape1 = list(args[0].shape)
179+
return torch.tensor(shape1).prod().item()
180+
181+
182+
@pytest.mark.pow
183+
def test_pow_tensor_scalar_perf():
184+
bench = BinaryTensorScalarBenchmark(
185+
op_name="pow_tensor_scalar",
186+
torch_op=torch.pow,
187+
dtypes=FLOAT_DTYPES,
188+
scalar=2.0,
189+
)
190+
bench.run()
191+
192+
102193
@pytest.mark.parametrize(
103194
"op_name, torch_op, dtypes",
104195
[

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from .add import add, add_
12
from .addmm import addmm
23
from .all import all, all_dim, all_dims
34
from .amax import amax
@@ -40,22 +41,27 @@
4041
from .full import full
4142
from .full_like import full_like
4243
from .gather import gather
44+
from .scatter_add_ import scatter_add_
4345
from .groupnorm import group_norm, group_norm_backward
4446
from .hstack import hstack
4547
from .index import index
4648
from .index_add import index_add
49+
from .index_put import index_put, index_put_
4750
from .index_select import index_select
4851
from .isin import isin
4952
from .linspace import linspace
5053
from .logical_and import logical_and, logical_and_
5154
from .log_softmax import log_softmax, log_softmax_backward
55+
from .lt import lt, lt_scalar
5256
from .masked_fill import masked_fill, masked_fill_
5357
from .masked_select import masked_select
5458
from .max import max, max_dim
5559
from .mean import mean, mean_dim
5660
from .min import min, min_dim
5761
from .mm import mm
5862
from .multinomial import multinomial
63+
from .ne import ne, ne_scalar
64+
from .nonzero import nonzero
5965
from .ones import ones
6066
from .ones_like import ones_like
6167
from .outer import outer
@@ -76,6 +82,7 @@
7682
from .softmax import softmax, softmax_backward
7783
from .sort import sort
7884
from .stack import stack
85+
from .topk import topk
7986
from .threshold import threshold, threshold_backward
8087
from .triu import triu
8188
from .unique import _unique2
@@ -88,6 +95,8 @@
8895
from .zeros_like import zeros_like
8996

9097
__all__ = [
98+
"add",
99+
"add_",
91100
"addmm",
92101
"all",
93102
"all_dim",
@@ -177,8 +186,16 @@
177186
"bitwise_or_tensor",
178187
"bitwise_or_tensor_",
179188
"multinomial",
189+
"lt",
190+
"lt_scalar",
191+
"ne",
192+
"ne_scalar",
193+
"nonzero",
180194
"index_add",
195+
"index_put",
196+
"index_put_",
181197
"_unique2",
198+
"topk",
182199
"upsample_nearest2d",
183200
"randperm",
184201
"true_divide",
@@ -192,4 +209,5 @@
192209
"div_mode_",
193210
"logical_and",
194211
"logical_and_",
212+
"scatter_add_",
195213
]
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import logging
2+
import math
3+
4+
import torch
5+
import triton
6+
import triton.language as tl
7+
8+
from flag_gems.runtime import torch_device_fn
9+
from flag_gems.utils import pointwise_dynamic
10+
11+
logger = logging.getLogger(f'flag_gems.runtime._ascend.ops.{__name__.split(".")[-1]}')
12+
13+
CORE_NUM = 40
14+
15+
try:
16+
import torch_npu # noqa: F401
17+
import triton.runtime.driver as driver
18+
19+
device = torch.npu.current_device()
20+
props = driver.active.utils.get_device_properties(device)
21+
CORE_NUM = props["num_vectorcore"]
22+
except Exception:
23+
CORE_NUM = 40
24+
25+
26+
@triton.jit
27+
def add_kernel(
28+
x_ptr,
29+
y_ptr,
30+
out_ptr,
31+
alpha,
32+
data_len,
33+
BLOCK_SIZE: tl.constexpr,
34+
TILE_SIZE: tl.constexpr,
35+
):
36+
pid = tl.program_id(0)
37+
iter_num = tl.cdiv(BLOCK_SIZE, TILE_SIZE)
38+
39+
for idx in tl.range(0, iter_num):
40+
offsets = pid * BLOCK_SIZE + idx * TILE_SIZE + tl.arange(0, TILE_SIZE)
41+
mask = offsets < data_len
42+
x = tl.load(x_ptr + offsets, mask=mask, care_padding=False)
43+
y = tl.load(y_ptr + offsets, mask=mask, care_padding=False)
44+
out = x + y * alpha
45+
tl.store(out_ptr + offsets, out, mask=mask)
46+
47+
48+
@pointwise_dynamic(
49+
is_tensor=[True, False, False], promotion_methods=[(0, 1, "DEFAULT")]
50+
)
51+
@triton.jit
52+
def add_func_tensor_scalar(x, y, alpha):
53+
return x + y * alpha
54+
55+
56+
@pointwise_dynamic(
57+
is_tensor=[False, True, False], promotion_methods=[(0, 1, "DEFAULT")]
58+
)
59+
@triton.jit
60+
def add_func_scalar_tensor(x, y, alpha):
61+
return x + y * alpha
62+
63+
64+
def _launch_add_kernel(x_flat, y_flat, out_flat, alpha, data_len, device):
65+
TILE_SIZE = 8192
66+
BLOCK_SIZE = math.ceil(data_len / CORE_NUM)
67+
BLOCK_SIZE = max(BLOCK_SIZE, TILE_SIZE)
68+
# Round up to multiple of TILE_SIZE for proper tiling
69+
BLOCK_SIZE = triton.cdiv(BLOCK_SIZE, TILE_SIZE) * TILE_SIZE
70+
grid = lambda meta: (triton.cdiv(data_len, meta["BLOCK_SIZE"]),)
71+
with torch_device_fn.device(device):
72+
add_kernel[grid](
73+
x_flat, y_flat, out_flat, float(alpha), data_len, BLOCK_SIZE, TILE_SIZE
74+
)
75+
76+
77+
def add(A, B, *, alpha=1):
78+
logger.debug("GEMS_ASCEND ADD")
79+
if isinstance(A, torch.Tensor) and isinstance(B, torch.Tensor):
80+
if B.device != A.device:
81+
B = B.to(A.device)
82+
result_type = torch.result_type(A, B)
83+
A_cont = A.contiguous()
84+
B_cont = B.contiguous()
85+
if A_cont.dtype != result_type:
86+
A_cont = A_cont.to(result_type)
87+
if B_cont.dtype != result_type:
88+
B_cont = B_cont.to(result_type)
89+
A_flat = A_cont.view(-1)
90+
B_flat = B_cont.view(-1)
91+
out = torch.empty_like(A_flat, dtype=result_type)
92+
data_len = A_flat.numel()
93+
_launch_add_kernel(A_flat, B_flat, out, alpha, data_len, A.device)
94+
return out.view(A.shape)
95+
elif isinstance(A, torch.Tensor):
96+
return add_func_tensor_scalar(A, B, alpha)
97+
elif isinstance(B, torch.Tensor):
98+
return add_func_scalar_tensor(A, B, alpha)
99+
else:
100+
return torch.tensor(A + B * alpha)
101+
102+
103+
def add_(A, B, *, alpha=1):
104+
logger.debug("GEMS_ASCEND ADD_")
105+
if isinstance(A, torch.Tensor) and isinstance(B, torch.Tensor):
106+
if B.device != A.device:
107+
B = B.to(A.device)
108+
A_flat = A.contiguous().view(-1)
109+
B_flat = B.contiguous().view(-1)
110+
data_len = A_flat.numel()
111+
_launch_add_kernel(A_flat, B_flat, A_flat, alpha, data_len, A.device)
112+
return A
113+
elif isinstance(A, torch.Tensor):
114+
return add_func_tensor_scalar(A, B, alpha, out0=A)
115+
else:
116+
raise ValueError("Unreachable.")

src/flag_gems/runtime/backend/_ascend/ops/cumsum.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ def cumsum_wrapper(inp, dim=1, dtype=None, out=None):
236236

237237

238238
def reduce_then_scan_row(x, out, M, N, compute_dtype):
239-
if N <= 16384: # persistent
239+
if N <= 8192: # persistent (capped to avoid UB overflow with int64 + multibuffer)
240240
TILE_SIZE = triton.next_power_of_2(N)
241241
reduce_then_scan_root_scan_kernel_row[(M, 1, 1)](
242242
x,
@@ -248,7 +248,12 @@ def reduce_then_scan_row(x, out, M, N, compute_dtype):
248248

249249
TILE_SIZE = min(4096, triton.next_power_of_2(N))
250250
num_tiles = triton.cdiv(N, TILE_SIZE)
251-
num_ctas = num_tiles
251+
# Cap num_ctas so ROOT_SCAN_TILE_SIZE fits in UB (max 4096 for int64 + multibuffer)
252+
MAX_ROOT_SCAN = 4096
253+
num_ctas = min(num_tiles, MAX_ROOT_SCAN)
254+
# Ensure total grid (M * num_ctas) doesn't exceed Ascend coreDim limit
255+
max_ctas_for_grid = max(1, GRID_Y_LIMIT // M)
256+
num_ctas = min(num_ctas, max_ctas_for_grid)
252257
ROOT_SCAN_TILE_SIZE = triton.next_power_of_2(num_ctas)
253258
tiles_per_cta = triton.cdiv(num_tiles, num_ctas)
254259
block_sums = torch.empty(

0 commit comments

Comments
 (0)