Skip to content

Commit 5359bfc

Browse files
committed
Only take the fast path if the size of operands is relatively small
1 parent 132a9ca commit 5359bfc

File tree

2 files changed

+22
-31
lines changed

2 files changed

+22
-31
lines changed

src/blosc2/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ class Tuner(Enum):
138138
"""
139139
Maximum buffer size in bytes for a Blosc2 chunk."""
140140

141+
MAX_FAST_PATH_SIZE = 2**30
142+
"""
143+
Maximum size in bytes for a fast path evaluation.
144+
"""
145+
141146
MAX_OVERHEAD = MAX_OVERHEAD
142147
"""
143148
Maximum overhead during compression (in bytes). This is

src/blosc2/lazyexpr.py

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,43 +47,22 @@
4747

4848

4949
def compute_slice_shape(shape, slice_obj, dont_squeeze=False): # noqa: C901
50-
"""
51-
Compute the shape of an array after applying a slice.
52-
53-
Parameters
54-
----------
55-
shape : tuple
56-
The original shape of the array.
57-
slice_obj : int, slice, tuple of slices, or None
58-
The slice object to apply to the array.
59-
dont_squeeze : bool
60-
Integer indexing normall reduces dimensionality. Setting this
61-
to True, makes dimensionality untouched.
62-
63-
Returns
64-
-------
65-
slice_shape : tuple
66-
The shape of the resulting array after applying the slice.
67-
"""
6850
# Handle None or empty slice case
6951
if slice_obj is None or slice_obj == ():
7052
return shape
7153

7254
# Use ndindex to handle slice calculations
7355
try:
74-
# ndindex.ndindex converts slice_obj to a standardized form
75-
# and expand expands it to match the shape of the array
7656
idx = ndindex.ndindex(slice_obj).expand(shape)
77-
# Use ndindex's shape property which calculates the resulting shape
7857
return idx.shape
7958
except Exception:
80-
# Fall back to manual processing if ndindex fails
81-
# This could happen for complex cases that ndindex doesn't handle well
59+
# Fall back to manual processing
8260
if not isinstance(slice_obj, tuple):
8361
slice_obj = (slice_obj,)
8462

8563
result = []
8664
shape_idx = 0
65+
dims_reduced = 0
8766

8867
# Process slice components
8968
for i, s in enumerate(slice_obj):
@@ -103,21 +82,23 @@ def compute_slice_shape(shape, slice_obj, dont_squeeze=False): # noqa: C901
10382
result.append((stop - start - 1) // step + 1)
10483
else:
10584
result.append(0)
85+
shape_idx += 1
10686
elif isinstance(s, int) or np.isscalar(s):
10787
if dont_squeeze:
10888
result.append(1)
89+
shape_idx += 1
10990
else:
110-
# Integer indexing reduces dimensionality (normally)
91+
# Integer indexing reduces dimensionality
92+
dims_reduced += 1
93+
shape_idx += 1
11194
continue
11295
elif s is Ellipsis:
11396
# Fill in with remaining dimensions
114-
remaining_dims = len(shape) - (len(slice_obj) - 1)
97+
remaining_dims = len(shape) - (len(slice_obj) - 1 + dims_reduced)
11598
result.extend(shape[shape_idx : shape_idx + remaining_dims])
11699
shape_idx += remaining_dims
117100
continue
118101

119-
shape_idx += 1
120-
121102
# Add any remaining dimensions
122103
if shape_idx < len(shape):
123104
result.extend(shape[shape_idx:])
@@ -2050,11 +2031,16 @@ def chunked_eval( # noqa: C901
20502031
return reduce_slices(expression, operands, reduce_args=reduce_args, _slice=item, **kwargs)
20512032

20522033
if not is_full_slice(item) or (where is not None and len(where) < 2):
2053-
# The fast path is not possible when using partial slices or where returning
2054-
# a variable number of elements
2034+
# The fast path is possible under a few conditions
20552035
if getitem and (where is None or len(where) == 2) and not callable(expression):
2056-
# If we are using getitem, we can still use some optimizations
2057-
return slices_eval_getitem(expression, operands, _slice=item, **kwargs)
2036+
# Compute the size of operands for the fast path
2037+
shape = compute_broadcast_shape(operands.values())
2038+
shape_operands = compute_slice_shape(shape, item)
2039+
_dtype = kwargs.get("dtype", np.float64)
2040+
size_operands = math.prod(shape_operands) * len(operands) * _dtype.itemsize
2041+
# Only take the fast path if the size of operands is relatively small
2042+
if size_operands < blosc2.MAX_FAST_PATH_SIZE:
2043+
return slices_eval_getitem(expression, operands, _slice=item, **kwargs)
20582044
return slices_eval(expression, operands, getitem=getitem, _slice=item, **kwargs)
20592045

20602046
if fast_path:

0 commit comments

Comments
 (0)