Skip to content

Commit c6da816

Browse files
authored
rever internal overlapping detection to 3-value classification: Yes, No and TooHard. TooHard is okay for torch to assume no internal overlapping. (#711)
1 parent 5bd03b9 commit c6da816

9 files changed

Lines changed: 78 additions & 67 deletions

File tree

src/flag_gems/ops/scatter.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77

88
from flag_gems.utils.code_cache import code_cache_dir
99
from flag_gems.utils.code_utils import IndentedBuffer, write_atomic
10-
from flag_gems.utils.shape_utils import has_internal_overlapping, restride_dim
10+
from flag_gems.utils.shape_utils import (
11+
MemOverlap,
12+
has_internal_overlapping,
13+
restride_dim,
14+
)
1115

1216
logger = logging.getLogger(__name__)
1317

@@ -332,7 +336,7 @@ def scatter(inp, dim, index, src, reduce=None):
332336
torch.bfloat16,
333337
), "Unsupported operation: reduce scatter bfloat tensors."
334338

335-
if has_internal_overlapping(out):
339+
if has_internal_overlapping(out) == MemOverlap.Yes:
336340
out = out.contiguous()
337341

338342
src_strided = src.as_strided(index.shape, src.stride())
@@ -367,8 +371,8 @@ def scatter_(inp, dim, index, src, reduce=None):
367371
torch.bfloat16,
368372
), "Unsupported operation: reduce scatter bfloat tensors."
369373

370-
assert not has_internal_overlapping(
371-
out
374+
assert (
375+
has_internal_overlapping(out) != MemOverlap.Yes
372376
), "Unsupported operation: trying to inplace write to an internally overlapping tensor."
373377

374378
src_restrided = src.as_strided(index.shape, src.stride())

src/flag_gems/ops/select_scatter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import torch
44

55
from ..ops.copy import copy
6-
from ..utils.shape_utils import has_internal_overlapping
6+
from ..utils.shape_utils import MemOverlap, has_internal_overlapping
77

88
logger = logging.getLogger(__name__)
99

@@ -21,7 +21,7 @@ def select_scatter(inp, src, dim, index):
2121
list(src.shape) == valid_shape
2222
), "Expected src to have a size equal to the slice of self"
2323

24-
if has_internal_overlapping(inp):
24+
if has_internal_overlapping(inp) == MemOverlap.Yes:
2525
out = torch.empty(inp.size(), dtype=inp.dtype, device=inp.device)
2626
else:
2727
out = torch.empty_strided(

src/flag_gems/ops/slice_scatter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import triton
55

66
from ..ops.copy import copy
7-
from ..utils.shape_utils import has_internal_overlapping
7+
from ..utils.shape_utils import MemOverlap, has_internal_overlapping
88

99
logger = logging.getLogger(__name__)
1010

@@ -27,7 +27,7 @@ def slice_scatter(inp, src, dim=0, start=None, end=None, step=1):
2727
list(src.shape) == valid_shape
2828
), "Expected src to have a size equal to the slice of self"
2929

30-
if has_internal_overlapping(inp):
30+
if has_internal_overlapping(inp) == MemOverlap.Yes:
3131
out = torch.empty(inp.size(), dtype=inp.dtype, device=inp.device)
3232
else:
3333
out = torch.empty_strided(

src/flag_gems/runtime/backend/_kunlunxin/ops/scatter.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77

88
from flag_gems.utils.code_cache import code_cache_dir
99
from flag_gems.utils.code_utils import IndentedBuffer
10-
from flag_gems.utils.shape_utils import has_internal_overlapping, restride_dim
10+
from flag_gems.utils.shape_utils import (
11+
MemOverlap,
12+
has_internal_overlapping,
13+
restride_dim,
14+
)
1115

1216
logger = logging.getLogger(__name__)
1317

@@ -327,7 +331,7 @@ def scatter(inp, dim, index, src, reduce=None):
327331
torch.bfloat16,
328332
), "Unsupported operation: reduce scatter bfloat tensors."
329333

330-
if has_internal_overlapping(out):
334+
if has_internal_overlapping(out) == MemOverlap.Yes:
331335
out = out.contiguous()
332336

333337
src_strided = src.as_strided(index.shape, src.stride())
@@ -362,8 +366,8 @@ def scatter_(inp, dim, index, src, reduce=None):
362366
torch.bfloat16,
363367
), "Unsupported operation: reduce scatter bfloat tensors."
364368

365-
assert not has_internal_overlapping(
366-
out
369+
assert (
370+
has_internal_overlapping(out) != MemOverlap.Yes
367371
), "Unsupported operation: trying to inplace write to an internally overlapping tensor."
368372

369373
src_restrided = src.as_strided(index.shape, src.stride())

src/flag_gems/runtime/backend/_kunlunxin/ops/select_scatter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import torch
44

5-
from flag_gems.utils.shape_utils import has_internal_overlapping
5+
from flag_gems.utils.shape_utils import MemOverlap, has_internal_overlapping
66

77
from ..ops.copy import copy
88

@@ -22,7 +22,7 @@ def select_scatter(inp, src, dim, index):
2222
list(src.shape) == valid_shape
2323
), "Expected src to have a size equal to the slice of self"
2424

25-
if has_internal_overlapping(inp):
25+
if has_internal_overlapping(inp) == MemOverlap.Yes:
2626
out = torch.empty(inp.size(), dtype=inp.dtype, device=inp.device)
2727
else:
2828
out = torch.empty_strided(

src/flag_gems/runtime/backend/_kunlunxin/ops/slice_scatter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import triton
55
from _kunlunxin.ops.copy import copy_slice
66

7-
from flag_gems.utils.shape_utils import has_internal_overlapping
7+
from flag_gems.utils.shape_utils import MemOverlap, has_internal_overlapping
88

99
logger = logging.getLogger(__name__)
1010

@@ -27,7 +27,7 @@ def slice_scatter(inp, src, dim=0, start=None, end=None, step=1):
2727
list(src.shape) == valid_shape
2828
), "Expected src to have a size equal to the slice of self"
2929

30-
if has_internal_overlapping(inp):
30+
if has_internal_overlapping(inp) == MemOverlap.Yes:
3131
out = torch.empty(inp.size(), dtype=inp.dtype, device=inp.device)
3232
else:
3333
out = torch.empty_strided(

src/flag_gems/runtime/backend/_kunlunxin/utils/pointwise_dynamic.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from flag_gems.utils.code_cache import code_cache_dir
1111
from flag_gems.utils.code_utils import IndentedBuffer
1212
from flag_gems.utils.shape_utils import (
13+
MemOverlap,
1314
all_c_contiguous,
1415
all_the_same_shape,
1516
all_the_same_stride,
@@ -1215,15 +1216,13 @@ def prepare_args(self, *args, **kwargs):
12151216
if out_tensors:
12161217
for index, item in enumerate(out_tensors):
12171218
if list(item.shape) != list(task_shape):
1218-
raise ValueError(
1219+
raise RuntimeError(
12191220
f"out tensor at index {index} shape is invalid, should be {task_shape} but is {item.shape}!"
12201221
)
1221-
# output arguments must be dense and no overlapping for pointwise operation
1222-
if has_internal_overlapping(item) and any(
1223-
item is t for t in in_tensors
1224-
):
1225-
raise ValueError(
1226-
"Pointwise Input arguments must be dense and no overlapping."
1222+
# output arguments must not have internal overlapping for pointwise operation
1223+
if has_internal_overlapping(item) == MemOverlap.Yes:
1224+
raise RuntimeError(
1225+
"Pointwise Input arguments should not have internal overlapping."
12271226
)
12281227

12291228
ndim = len(task_shape)

src/flag_gems/utils/pointwise_dynamic.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from flag_gems.utils.code_cache import code_cache_dir
1010
from flag_gems.utils.code_utils import IndentedBuffer, write_atomic
1111
from flag_gems.utils.shape_utils import (
12+
MemOverlap,
1213
all_c_contiguous,
1314
all_the_same_shape,
1415
all_the_same_stride,
@@ -1169,15 +1170,13 @@ def prepare_args(self, *args, **kwargs):
11691170
if out_tensors:
11701171
for index, item in enumerate(out_tensors):
11711172
if list(item.shape) != list(task_shape):
1172-
raise ValueError(
1173+
raise RuntimeError(
11731174
f"out tensor at index {index} shape is invalid, should be {task_shape} but is {item.shape}!"
11741175
)
1175-
# output arguments must be dense and no overlapping for pointwise operation
1176-
if has_internal_overlapping(item) and any(
1177-
item is t for t in in_tensors
1178-
):
1179-
raise ValueError(
1180-
"Pointwise Input arguments must be dense and no overlapping."
1176+
# output arguments must not have internal overlapping for pointwise operation
1177+
if has_internal_overlapping(item) == MemOverlap.Yes:
1178+
raise RuntimeError(
1179+
"Pointwise Input arguments should not have internal overlapping."
11811180
)
11821181

11831182
ndim = len(task_shape)

src/flag_gems/utils/shape_utils.py

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import enum
12
import functools
23
import operator
34
from typing import Iterable, Sequence, Tuple
@@ -221,15 +222,21 @@ def can_use_int32_index(a):
221222
return True
222223

223224

225+
class MemOverlap(enum.Enum):
226+
No = 0
227+
Yes = 1
228+
TooHard = 2
229+
230+
224231
def has_internal_overlapping(x: torch.Tensor):
225232
if x.is_contiguous():
226-
return False
233+
return MemOverlap.No
227234
if torch.ops.aten.is_non_overlapping_and_dense(x):
228-
return False
235+
return MemOverlap.No
229236
for size, stride in zip(x.size(), x.stride()):
230237
if size > 1 and stride == 0:
231-
return True
232-
return True
238+
return MemOverlap.Yes
239+
return MemOverlap.TooHard
233240

234241

235242
def restride_dim(src, dim, shape, step=0, storage_offset=None):
@@ -277,6 +284,37 @@ def add_on_kernel(
277284
tl.store(add_on + offsets, res, mask=block_mask)
278285

279286

287+
def check_tensor_attributes(data_list, is_tensor_list):
288+
"""
289+
Checks if each element in data_list is a tensor and validates whether the corresponding
290+
boolean value in is_tensor_list is correct.
291+
Parameters:
292+
- data_list: A list containing tensor and non-tensor objects.
293+
- is_tensor_list: A list of boolean values indicating whether the corresponding element in data_list is a tensor.
294+
Returns:
295+
- True if all elements' types match their corresponding boolean values in is_tensor_list.
296+
- Raise Error otherwise, and prints the index and element that do not match.
297+
"""
298+
# Check if both lists have the same length
299+
if len(data_list) != len(is_tensor_list):
300+
raise ValueError(
301+
"Error: The lists of inputs and is_tensor must have the same length."
302+
)
303+
304+
for i, (data, is_tensor) in enumerate(zip(data_list, is_tensor_list)):
305+
actual_is_tensor = isinstance(data, torch.Tensor)
306+
307+
if actual_is_tensor != is_tensor:
308+
raise ValueError(
309+
f"Element at index {i} is incorrect. Expected {is_tensor}, but got {actual_is_tensor}."
310+
)
311+
312+
return True
313+
314+
315+
_initial_missing = object()
316+
317+
280318
def offset_calculator(inp, idx, strides, dim, isInp):
281319
"""
282320
Calculate the flat index(a.k.a offset) for a given ravel index in a multi-dimensional array.
@@ -341,39 +379,6 @@ def offset_calculator(inp, idx, strides, dim, isInp):
341379
return offsets if not isInp else (offsets - idx_dim)
342380

343381

344-
def check_tensor_attributes(data_list, is_tensor_list):
345-
"""
346-
Checks if each element in data_list is a tensor and validates whether the corresponding
347-
boolean value in is_tensor_list is correct.
348-
349-
Parameters:
350-
- data_list: A list containing tensor and non-tensor objects.
351-
- is_tensor_list: A list of boolean values indicating whether the corresponding element in data_list is a tensor.
352-
353-
Returns:
354-
- True if all elements' types match their corresponding boolean values in is_tensor_list.
355-
- Raise Error otherwise, and prints the index and element that do not match.
356-
"""
357-
# Check if both lists have the same length
358-
if len(data_list) != len(is_tensor_list):
359-
raise ValueError(
360-
"Error: The lists of inputs and is_tensor must have the same length."
361-
)
362-
363-
for i, (data, is_tensor) in enumerate(zip(data_list, is_tensor_list)):
364-
actual_is_tensor = isinstance(data, torch.Tensor)
365-
366-
if actual_is_tensor != is_tensor:
367-
raise ValueError(
368-
f"Element at index {i} is incorrect. Expected {is_tensor}, but got {actual_is_tensor}."
369-
)
370-
371-
return True
372-
373-
374-
_initial_missing = object()
375-
376-
377382
def offsetCalculator(inp, idx, strides, dim, isInp):
378383
ndim = inp.ndim
379384
shape = list(inp.shape)

0 commit comments

Comments
 (0)