Skip to content

Commit 3f86a23

Browse files
authored
Merge branch 'master' into fix/benchmark-bugs
Signed-off-by: HuangYiQun <63465798+huangyiqun@users.noreply.github.com>
2 parents 948d1a6 + c7b3399 commit 3f86a23

309 files changed

Lines changed: 24584 additions & 11914 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
# @global-owner1 and @global-owner2 will be requested for
44
# review when someone opens a pull request.
55

6-
/src/flag_gems/* @kiddyjinjin @0x45f @zhangpeiyang1 @huangyiqun
6+
/src/flag_gems/* @0x45f @huangyiqun @douxetpur @bin913 @w1120029931-bit
77
/src/flag_gems/runtime/backend/*
88

9-
/tests/* @kiddyjinjin @0x45f @zhangpeiyang1 @huangyiqun
10-
/modules_tests/* @kiddyjinjin @0x45f @zhangpeiyang1 @huangyiqun
11-
/benchmark/* @kiddyjinjin @0x45f @zhangpeiyang1 @huangyiqun
9+
/tests/* @0x45f @huangyiqun @douxetpur @bin913 @w1120029931-bit
10+
/modules_tests/* @0x45f @huangyiqun @douxetpur @bin913 @w1120029931-bit
11+
/benchmark/* @0x45f @huangyiqun @douxetpur @bin913 @w1120029931-bit
1212

1313

14-
/lib/* @kiddyjinjin @0x45f @zhangpeiyang1 @huangyiqun
15-
/ctests/* @kiddyjinjin @0x45f @zhangpeiyang1 @huangyiqun
16-
/include/* @kiddyjinjin @0x45f @zhangpeiyang1 @huangyiqun
14+
/lib/* @0x45f @huangyiqun @douxetpur @bin913 @w1120029931-bit
15+
/ctests/* @0x45f @huangyiqun @douxetpur @bin913 @w1120029931-bit
16+
/include/* @0x45f @huangyiqun @douxetpur @bin913 @w1120029931-bit

benchmark/conftest.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,19 @@ def pytest_addoption(parser):
137137
help="Specify the shape file name for benchmarks. If not specified, a default shape list will be used.",
138138
)
139139

140-
parser.addoption(
141-
"--record",
142-
action="store",
143-
default="none",
144-
required=False,
145-
choices=["none", "log"],
146-
help="Benchmark info recorded in log files or not",
147-
)
140+
try:
141+
parser.addoption(
142+
"--record",
143+
action="store",
144+
default="none",
145+
required=False,
146+
choices=["none", "log"],
147+
help="Benchmark info recorded in log files or not",
148+
)
149+
except ValueError:
150+
# Mixed test+benchmark pytest runs may already register --record in
151+
# tests/conftest.py. Reuse the existing option in that case.
152+
pass
148153

149154
parser.addoption(
150155
"--parallel",
@@ -158,11 +163,16 @@ def pytest_addoption(parser):
158163
),
159164
)
160165

161-
parser.addoption(
162-
"--collect-marks",
163-
action="store_true",
164-
help="Collect the tests with marker information without executing them",
165-
)
166+
try:
167+
parser.addoption(
168+
"--collect-marks",
169+
action="store_true",
170+
help="Collect the tests with marker information without executing them",
171+
)
172+
except ValueError:
173+
# Mixed test+benchmark pytest runs may already register this option in
174+
# tests/conftest.py. Reuse the existing option in that case.
175+
pass
166176

167177

168178
def pytest_configure(config):

benchmark/core_shapes.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ log10_out:
6363
- [1024, 65536]
6464
shape_desc: "(B), M, N"
6565

66+
gcd:
67+
shapes:
68+
- [65536]
69+
- [1024, 1024]
70+
- [256, 4096]
71+
- [64, 256, 256]
72+
shape_desc: "(B), M, N"
73+
6674
softmax_backward:
6775
shapes:
6876
- [1048576] # 1024 * 1024
@@ -111,6 +119,19 @@ MvAndOuterBenchmark:
111119
- [8192, 8192]
112120
- [10240, 10240] #from perf
113121

122+
mm_self_transpose:
123+
shapes:
124+
- [257, 96]
125+
- [384, 384]
126+
- [1536, 320]
127+
- [3072, 768]
128+
- [1024, 1024]
129+
- [4096, 1024]
130+
- [5333, 71]
131+
- [8192, 2048]
132+
- [10240, 4096]
133+
shape_desc: "M, K"
134+
114135
# NORM shapes can be either 3D or 4D:
115136
# - 3D shapes are represented as [batch_size, channels, hidden_size]
116137
# - 4D shapes are represented as [batch_size, channels, height, width]

benchmark/test_attention_perf.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,76 @@ def set_more_shapes(self):
2424
return None
2525

2626

27+
#
28+
# sparse_attention shape layout:
29+
# (batch, seq_len, kv_len, topk, heads, dim)
30+
#
31+
SPARSE_ATTENTION_SHAPES = [
32+
(16, 1, 136, 136, 8, 512),
33+
(16, 1, 392, 385, 8, 512),
34+
(16, 1, 392, 386, 8, 512),
35+
(16, 1, 392, 387, 8, 512),
36+
(32, 1, 392, 388, 8, 512),
37+
(32, 1, 392, 389, 8, 512),
38+
(32, 1, 392, 390, 8, 512),
39+
(32, 1, 392, 391, 8, 512),
40+
(64, 1, 136, 136, 8, 512),
41+
(64, 1, 392, 385, 8, 512),
42+
(64, 1, 392, 388, 8, 512),
43+
(64, 1, 392, 389, 8, 512),
44+
]
45+
46+
47+
def torch_sparse_attention(q, kv, attn_sink, topk_idxs, softmax_scale):
48+
batch, seq_len, heads, dim = q.shape
49+
topk = topk_idxs.shape[-1]
50+
51+
kv_expanded = kv[:, None, :, :].expand(batch, seq_len, -1, dim)
52+
idx_expanded = topk_idxs[:, :, :, None].expand(batch, seq_len, topk, dim).long()
53+
gathered_kv = torch.gather(kv_expanded, 2, idx_expanded)
54+
55+
scores = (
56+
torch.einsum("bmhd,bmtd->bmht", q.float(), gathered_kv.float()) * softmax_scale
57+
)
58+
sink = attn_sink[None, None, :, None].expand(batch, seq_len, heads, 1)
59+
attn = torch.softmax(torch.cat([scores, sink], dim=-1), dim=-1)
60+
61+
out = torch.einsum("bmht,bmtd->bmhd", attn[:, :, :, :-1], gathered_kv.float())
62+
return out.to(q.dtype)
63+
64+
65+
class SparseAttentionBenchmark(Benchmark):
66+
def set_shapes(self, shape_file_path=None):
67+
self.shapes = SPARSE_ATTENTION_SHAPES[:]
68+
self.shape_desc = "B, M, KV_LEN, TOPK, H, D"
69+
70+
def set_more_shapes(self):
71+
return None
72+
73+
def get_input_iter(self, cur_dtype):
74+
for seed, (batch, seq_len, kv_len, topk, heads, dim) in enumerate(self.shapes):
75+
torch.manual_seed(2026 + seed)
76+
q = torch.randn(
77+
(batch, seq_len, heads, dim),
78+
dtype=cur_dtype,
79+
device=self.device,
80+
)
81+
kv = torch.randn(
82+
(batch, kv_len, dim),
83+
dtype=cur_dtype,
84+
device=self.device,
85+
)
86+
attn_sink = torch.zeros((heads,), dtype=torch.float32, device=self.device)
87+
topk_idxs = torch.randint(
88+
0,
89+
kv_len,
90+
(batch, seq_len, topk),
91+
dtype=torch.int32,
92+
device=self.device,
93+
)
94+
yield q, kv, attn_sink, topk_idxs, 1.0 / math.sqrt(dim)
95+
96+
2797
def torch_flash_attention_forward(
2898
q, k, v, scale, is_causal, dropout_p=0.0, return_debug_mask=False, **extra_kwargs
2999
):
@@ -315,6 +385,18 @@ def sdpa_flash(
315385
del os.environ["TRITON_HIP_USE_NEW_STREAM_PIPELINE"]
316386

317387

388+
@pytest.mark.skipif(flag_gems.device == "cpu", reason="Unsupported in CPU mode")
389+
@pytest.mark.sparse_attention
390+
def test_perf_sparse_attention():
391+
bench = SparseAttentionBenchmark(
392+
op_name="sparse_attention",
393+
torch_op=torch_sparse_attention,
394+
dtypes=[torch.bfloat16],
395+
)
396+
bench.set_gems(flag_gems.sparse_attn_triton)
397+
bench.run()
398+
399+
318400
class FlashMLABenchmark(GenericBenchmark):
319401
"""
320402
benchmark for flash_mla

benchmark/test_binary_pointwise_perf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def get_tflops(self, op, *args, **kwargs):
7575
("bitwise_and", torch.bitwise_and, INT_DTYPES + BOOL_DTYPES),
7676
("bitwise_or", torch.bitwise_or, INT_DTYPES + BOOL_DTYPES),
7777
("div", torch.div, FLOAT_DTYPES + COMPLEX_DTYPES),
78+
("gcd", torch.gcd, INT_DTYPES),
7879
("dunder_or", lambda a, b: a | b, INT_DTYPES + BOOL_DTYPES),
7980
("eq", torch.eq, FLOAT_DTYPES),
8081
("equal", torch.equal, FLOAT_DTYPES),

benchmark/test_blas_perf.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,21 @@ def get_tflops(self, op, *args, **kwargs):
135135
return total_flops
136136

137137

138+
class MmSelfTransposeBenchmark(GenericBenchmark2DOnly):
139+
"""
140+
Benchmark for the mm(a, a.t()) fast path.
141+
"""
142+
143+
DEFAULT_METRICS = DEFAULT_METRICS[:] + ["tflops"]
144+
145+
def set_more_shapes(self):
146+
return None
147+
148+
def get_tflops(self, op, *args, **kwargs):
149+
m, k = args[0].shape
150+
return 2 * m * m * k
151+
152+
138153
def addmm_input_fn(b, m, n, k, cur_dtype, device, b_column_major):
139154
inp1 = torch.randn([m, k], dtype=cur_dtype, device=device)
140155
bias = torch.randn([m, n], dtype=cur_dtype, device=device)
@@ -184,6 +199,16 @@ def mm_input_fn(b, m, n, k, cur_dtype, device, b_column_major):
184199
yield inp1, inp2
185200

186201

202+
def torch_mm_self_transpose(inp):
203+
return torch.mm(inp, inp.t())
204+
205+
206+
def mm_self_transpose_input_fn(shape, cur_dtype, device):
207+
m, k = shape
208+
inp = torch.randn([k, m], dtype=cur_dtype, device=device).t()
209+
yield inp,
210+
211+
187212
def group_mm_input_fn(groups, N, K, cur_dtype, device):
188213
assert cur_dtype == torch.bfloat16
189214
import random
@@ -439,6 +464,17 @@ def test_mv_and_outer_benchmark(op_name, torch_op, input_fn):
439464
bench.run()
440465

441466

467+
@pytest.mark.mm
468+
def test_mm_self_transpose_benchmark():
469+
bench = MmSelfTransposeBenchmark(
470+
input_fn=mm_self_transpose_input_fn,
471+
op_name="mm_self_transpose",
472+
torch_op=torch_mm_self_transpose,
473+
dtypes=FLOAT_DTYPES,
474+
)
475+
bench.run()
476+
477+
442478
class AddmvBenchmark(GenericBenchmark2DOnly):
443479
"""
444480
Benchmark for addmv

0 commit comments

Comments
 (0)