forked from tile-ai/TileOPs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_elementwise_fp8.py
More file actions
245 lines (189 loc) · 8.83 KB
/
Copy pathtest_elementwise_fp8.py
File metadata and controls
245 lines (189 loc) · 8.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
"""Tests for fp8 dtype rejection in elementwise kernels.
After narrowing `_FLOAT_DTYPES` to drop fp8, the elementwise / rope / dropout
kernels no longer advertise fp8 in `SUPPORTED_DTYPES`. The tests here are
sentinel checks that float and bitwise kernels correctly reject fp8 inputs
at the kernel layer (exercising `SUPPORTED_DTYPES`, not `Op._validate_dtypes`).
"""
import pytest
import torch
_N = 1024 * 16
@pytest.mark.smoke
def test_float_unary_kernel_rejects_fp8():
"""ReluFwdKernel raises ValueError for fp8 (not in narrowed _FLOAT_DTYPES)."""
from tileops.kernels.elementwise import ReluFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
ReluFwdKernel(N_total=_N, dtype=torch.float8_e4m3fn)
@pytest.mark.smoke
def test_bitwise_kernel_rejects_fp8():
"""BitwiseNotFwdKernel raises ValueError for fp8 (not in _BITWISE_DTYPES)."""
from tileops.kernels.elementwise import BitwiseNotFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
BitwiseNotFwdKernel(N_total=_N, dtype=torch.float8_e4m3fn)
@pytest.mark.smoke
def test_binary_bitwise_kernel_rejects_fp8():
"""BitwiseAndFwdKernel raises ValueError for fp8 (not in _BITWISE_DTYPES)."""
from tileops.kernels.elementwise import BitwiseAndFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
BitwiseAndFwdKernel(
N_total=_N, dtype=torch.float8_e4m3fn,
coalesced_shape=(_N,), a_strides=(1,), b_strides=(1,),
a_numel=_N, b_numel=_N,
)
@pytest.mark.smoke
def test_binary_arith_kernel_rejects_fp8():
"""MulFwdKernel raises ValueError for fp8 (not in _BINARY_FULL_DTYPES).
Regression sentinel: prevents MulFwdKernel.SUPPORTED_DTYPES from drifting
back to a dtype set that admits fp8 (e.g. None or _FLOAT_DTYPES superset).
"""
from tileops.kernels.elementwise import MulFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
MulFwdKernel(
N_total=_N, dtype=torch.float8_e4m3fn,
coalesced_shape=(_N,), a_strides=(1,), b_strides=(1,),
a_numel=_N, b_numel=_N,
)
@pytest.mark.smoke
def test_no_concrete_kernel_inherits_none_supported_dtypes():
"""Every concrete ``Kernel`` subclass must declare SUPPORTED_DTYPES as a
non-empty tuple that excludes every fp8 dtype.
The ``None`` default lives on the elementwise template bases
(``UnaryKernel`` / ``BinaryKernel`` and their float / logical / predicate
siblings), not on the abstract ``Kernel`` root. Inheriting that default
silently hides the rejection contract; admitting an fp8 entry would let
fp8 reach codegen paths that PR-time guards no longer cover.
"""
import inspect
import tileops.kernels.elementwise as ew
fp8_dtypes = set(ew._FP8_DTYPES)
none_offenders = []
type_offenders = []
empty_offenders = []
fp8_offenders = []
# Audit every concrete kernel reachable from the elementwise module.
# Concrete kernels follow the ``<Op>FwdKernel`` / ``<Op>BwdKernel`` naming
# convention; abstract template bases (BinaryKernel, FloatUnaryKernel, etc.)
# do not. Filtering by suffix keeps this guard stable when new templates are
# introduced — no manual allowlist to maintain.
for cls_name, cls in inspect.getmembers(ew, inspect.isclass):
if not issubclass(cls, ew.Kernel):
continue
if not (cls_name.endswith("FwdKernel") or cls_name.endswith("BwdKernel")):
continue
supported = getattr(cls, "SUPPORTED_DTYPES", None)
if supported is None:
none_offenders.append(cls.__name__)
continue
if not isinstance(supported, tuple):
type_offenders.append((cls.__name__, type(supported).__name__))
continue
if len(supported) == 0:
empty_offenders.append(cls.__name__)
continue
leaked = [dt for dt in supported if dt in fp8_dtypes]
if leaked:
fp8_offenders.append((cls.__name__, leaked))
assert not none_offenders, (
f"Concrete kernels with SUPPORTED_DTYPES=None: {none_offenders}"
)
assert not type_offenders, (
f"Concrete kernels with non-tuple SUPPORTED_DTYPES: {type_offenders}"
)
assert not empty_offenders, (
f"Concrete kernels with empty SUPPORTED_DTYPES tuple: {empty_offenders}"
)
assert not fp8_offenders, (
f"Concrete kernels admitting fp8 in SUPPORTED_DTYPES: {fp8_offenders}"
)
def _binary_kwargs(dtype):
return dict(
N_total=_N, dtype=dtype,
coalesced_shape=(_N,), a_strides=(1,), b_strides=(1,),
a_numel=_N, b_numel=_N,
)
@pytest.mark.smoke
def test_comparison_family_kernel_rejects_fp8():
"""Comparison family (Eq/Lt/Ge representatives) rejects fp8 at the kernel layer."""
from tileops.kernels.elementwise import (
EqFwdKernel,
GeFwdKernel,
LtFwdKernel,
)
for cls in (EqFwdKernel, LtFwdKernel, GeFwdKernel):
with pytest.raises(ValueError, match="only supports dtypes"):
cls(**_binary_kwargs(torch.float8_e4m3fn))
@pytest.mark.smoke
def test_pow_kernel_rejects_fp8():
"""PowFwdKernel rejects fp8 (narrowed _FLOAT_DTYPES)."""
from tileops.kernels.elementwise import PowFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
PowFwdKernel(**_binary_kwargs(torch.float8_e4m3fn))
@pytest.mark.smoke
def test_division_family_kernel_rejects_fp8():
"""Division family (Div/FloorDivide/Remainder) rejects fp8 at the kernel layer."""
from tileops.kernels.elementwise import (
DivFwdKernel,
FloorDivideFwdKernel,
RemainderFwdKernel,
)
for cls in (DivFwdKernel, FloorDivideFwdKernel, RemainderFwdKernel):
with pytest.raises(ValueError, match="only supports dtypes"):
cls(**_binary_kwargs(torch.float8_e4m3fn))
@pytest.mark.smoke
def test_lerp_kernel_rejects_fp8():
"""LerpFwdKernel rejects fp8 (narrowed _FLOAT_DTYPES)."""
from tileops.kernels.elementwise import LerpFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
LerpFwdKernel(**_binary_kwargs(torch.float8_e4m3fn))
@pytest.mark.smoke
def test_maximum_minimum_family_kernel_rejects_fp8():
"""Maximum/Minimum family rejects fp8 at the kernel layer."""
from tileops.kernels.elementwise import MaximumFwdKernel, MinimumFwdKernel
for cls in (MaximumFwdKernel, MinimumFwdKernel):
with pytest.raises(ValueError, match="only supports dtypes"):
cls(**_binary_kwargs(torch.float8_e4m3fn))
@pytest.mark.smoke
def test_logical_binary_family_kernel_rejects_fp8():
"""LogicalAnd/LogicalOr family rejects fp8 at the kernel layer."""
from tileops.kernels.elementwise import LogicalAndFwdKernel, LogicalOrFwdKernel
for cls in (LogicalAndFwdKernel, LogicalOrFwdKernel):
with pytest.raises(ValueError, match="only supports dtypes"):
cls(**_binary_kwargs(torch.float8_e4m3fn))
@pytest.mark.smoke
def test_logical_unary_kernel_rejects_fp8():
"""LogicalNotFwdKernel (LogicalUnaryKernel base) rejects fp8."""
from tileops.kernels.elementwise import LogicalNotFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
LogicalNotFwdKernel(N_total=_N, dtype=torch.float8_e4m3fn)
@pytest.mark.smoke
def test_pow_kernel_rejects_bool_and_int():
"""PowFwdKernel (float-only family) rejects both bool and int inputs.
Companion sentinel to fp8 rejection: ``PowFwdKernel.SUPPORTED_DTYPES``
is ``_FLOAT_DTYPES``, so int and bool must also raise at the kernel layer.
"""
from tileops.kernels.elementwise import PowFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
PowFwdKernel(**_binary_kwargs(torch.bool))
with pytest.raises(ValueError, match="only supports dtypes"):
PowFwdKernel(**_binary_kwargs(torch.int32))
@pytest.mark.smoke
def test_lerp_kernel_rejects_int():
"""LerpFwdKernel (float-only family) rejects int32 inputs."""
from tileops.kernels.elementwise import LerpFwdKernel
with pytest.raises(ValueError, match="only supports dtypes"):
LerpFwdKernel(**_binary_kwargs(torch.int32))
@pytest.mark.smoke
def test_division_family_kernel_rejects_bool_and_int():
"""Division family (Div/FloorDivide/Remainder, float-only ``_FLOAT_DTYPES``)
rejects bool and int at the kernel layer."""
from tileops.kernels.elementwise import (
DivFwdKernel,
FloorDivideFwdKernel,
RemainderFwdKernel,
)
for cls in (DivFwdKernel, FloorDivideFwdKernel, RemainderFwdKernel):
with pytest.raises(ValueError, match="only supports dtypes"):
cls(**_binary_kwargs(torch.bool))
with pytest.raises(ValueError, match="only supports dtypes"):
cls(**_binary_kwargs(torch.int32))
if __name__ == "__main__":
pytest.main([__file__, "-vvs"])