Skip to content

Commit f07b60b

Browse files
committed
Better offset calculation for incomplete chunks at the end
1 parent f9c0324 commit f07b60b

2 files changed

Lines changed: 18 additions & 6 deletions

File tree

src/blosc2/blosc2_ext.pyx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,21 +1924,32 @@ cdef int aux_miniexpr(me_udata *udata, int64_t nchunk, int32_t nblock,
19241924

19251925
cdef me_expr* miniexpr_handle = udata.miniexpr_handle
19261926
cdef void* aux_reduc_ptr
1927-
cdef uintptr_t offset_bytes
1928-
cdef int nblocks_per_chunk = udata.array.chunknitems // udata.array.blocknitems
1927+
# Calculate blocks per chunk using CEILING division (chunks are padded to fit whole blocks)
1928+
cdef int nblocks_per_chunk = (udata.array.chunknitems + udata.array.blocknitems - 1) // udata.array.blocknitems
1929+
# Calculate the global linear block index: nchunk * blocks_per_chunk + nblock
1930+
# This works because blocks never span chunks (chunks are padded to block boundaries)
1931+
cdef int64_t linear_block_index = nchunk * nblocks_per_chunk + nblock
1932+
cdef uintptr_t offset_bytes = typesize * linear_block_index
1933+
19291934
if miniexpr_handle == NULL:
19301935
raise ValueError("miniexpr: handle not assigned")
1936+
1937+
# Skip evaluation if blocknitems is invalid (can happen for padding blocks beyond data)
1938+
if blocknitems <= 0:
1939+
# Free resources
1940+
for i in range(udata.ninputs):
1941+
free(input_buffers[i])
1942+
free(input_buffers)
1943+
return 0
1944+
19311945
# Call thread-safe miniexpr C API
19321946
if udata.aux_reduc_ptr == NULL:
19331947
rc = me_eval(miniexpr_handle, <const void**>input_buffers, udata.ninputs,
19341948
<void*>params_output, blocknitems)
19351949
else:
19361950
# Reduction operation
1937-
offset_bytes = <uintptr_t> typesize * (nchunk * nblocks_per_chunk + nblock)
19381951
aux_reduc_ptr = <void *> (<uintptr_t> udata.aux_reduc_ptr + offset_bytes)
19391952
rc = me_eval(miniexpr_handle, <const void**>input_buffers, udata.ninputs, aux_reduc_ptr, blocknitems)
1940-
# The output buffer is cleared in the prefilter function
1941-
# memset(<void *>params_output, 0, udata.array.sc.blocksize) # clear output buffer
19421953
if rc != 0:
19431954
raise RuntimeError(f"miniexpr: issues during evaluation; error code: {rc}")
19441955

src/blosc2/lazyexpr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2029,7 +2029,8 @@ def reduce_slices( # noqa: C901
20292029
res_eval = blosc2.uninit(shape, dtype, chunks=chunks, blocks=blocks, cparams=cparams, **kwargs)
20302030
# Compute the number of blocks in the result
20312031
nblocks = res_eval.nbytes // res_eval.blocksize
2032-
aux_reduc = np.empty(nblocks, dtype=dtype)
2032+
# Initialize to zeros since some blocks may be padding and won't be written
2033+
aux_reduc = np.zeros(nblocks, dtype=dtype)
20332034
try:
20342035
print("expr->miniexpr:", expression, reduce_op)
20352036
expression = f"{reduce_op_str}({expression})"

0 commit comments

Comments
 (0)