Skip to content

Commit

Permalink
Add requested changes
Browse files Browse the repository at this point in the history
  • Loading branch information
martaiborra committed Sep 12, 2024
1 parent 01d9986 commit 296712f
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 72 deletions.
60 changes: 60 additions & 0 deletions bench/fill_special.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#######################################################################
# Copyright (c) 2019-present, Blosc Development Team <blosc@blosc.org>
# All rights reserved.
#
# This source code is licensed under a BSD-style license (found in the
# LICENSE file in the root directory of this source tree)
#######################################################################

import sys
from time import time

import numpy as np

import blosc2

# Dimensions, type and persistence properties for the arrays
shape = 1_000 * 1_000
chunksize = 10_000
blocksize = 1_000

dtype = np.float64

nchunks = shape // chunksize
# Set the compression and decompression parameters
cparams = {"codec": blosc2.Codec.BLOSCLZ, "typesize": 8, "blocksize": blocksize * 8}
dparams = {}
contiguous = True
persistent = bool(sys.argv[1]) if len(sys.argv) > 1 else False

if persistent:
urlpath = "bench_fill_special.b2frame"
else:
urlpath = None


def create_schunk(data=None):
storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams, "dparams": dparams}
blosc2.remove_urlpath(urlpath)
# Create the empty SChunk
return blosc2.SChunk(chunksize=chunksize * cparams["typesize"], data=data, **storage)

t0 = time()
schunk = create_schunk(data=np.full(shape, np.pi, dtype))
t1 = time()
print("Time for filling the schunk with `data` argument in the constructor: {:.3f}s".format(t1 - t0))

schunk = create_schunk()
t0 = time()
schunk.fill_special(shape, blosc2.SpecialValue.UNINIT)
schunk[:] = np.full(shape, np.pi, dtype)
t1 = time()
print("Time for filling the schunk without passing directly the value: {:.3f}s".format(t1 - t0))

schunk = create_schunk()
t0 = time()
schunk.fill_special(shape, blosc2.SpecialValue.VALUE, np.pi)
t1 = time()
print("Time for filling the schunk passing directly the value to `fill_special`: {:.3f}s".format(t1 - t0))

blosc2.remove_urlpath(urlpath)
12 changes: 6 additions & 6 deletions src/blosc2/blosc2_ext.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@ cdef class SChunk:
raise RuntimeError("nitems is too large. Try increasing the chunksize")
if self.nbytes > 0 or self.cbytes > 0:
raise RuntimeError("Filling with special values only works on empty SChunks")

# Get a void pointer to the value
array = np.array([value])
if array.dtype.itemsize != self.typesize:
if isinstance(value, int):
Expand All @@ -1241,7 +1241,7 @@ cdef class SChunk:
array = np.array([value], dtype=dtype)
cdef Py_buffer *buf = <Py_buffer *> malloc(sizeof(Py_buffer))
PyObject_GetBuffer(array, buf, PyBUF_SIMPLE)

# Create chunk with repeated values
nchunks = nitems // self.chunkshape
cdef blosc2_schunk *c_schunk = <blosc2_schunk *> self.c_schunk
cdef blosc2_cparams *cparams = self.schunk.storage.cparams
Expand All @@ -1255,11 +1255,11 @@ cdef class SChunk:
PyBuffer_Release(buf)
free(buf)
raise RuntimeError("Error while appending the chunk")

last_nitems = nitems % self.chunkshape
# Create and append last chunk if it is smaller than chunkshape
remainder = nitems % self.chunkshape
rc = 0
if last_nitems != 0:
get_chunk_repeatval(dereference(cparams), last_nitems * self.typesize, chunk, chunksize, buf)
if remainder != 0:
get_chunk_repeatval(dereference(cparams), remainder * self.typesize, chunk, chunksize, buf)
rc = blosc2_schunk_append_chunk(self.schunk, <uint8_t *>chunk, True)
free(chunk)
PyBuffer_Release(buf)
Expand Down
2 changes: 1 addition & 1 deletion src/blosc2/schunk.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def fill_special(self, nitems, special_value, value=None):
The number of items to fill with the special value.
special_value: SpecialValue
The special value to be used for filling the SChunk.
value: bytes, int, float or bool (optional)
value: bytes, int, float, bool (optional)
The value to fill the SChunk. This parameter is only supported if
:paramref:`special_value` is ``blosc2.SpecialValue.VALUE``.
Expand Down
50 changes: 50 additions & 0 deletions tests/test_schunk_constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,53 @@ def test_schunk(contiguous, urlpath, cparams, dparams, chunksize):
assert schunk.typesize == 1

blosc2.remove_urlpath(urlpath)


@pytest.mark.parametrize("contiguous", [True, False])
@pytest.mark.parametrize("urlpath", [None, "b2frame"])
@pytest.mark.parametrize(
"cparams, nitems",
[
({"codec": blosc2.Codec.LZ4, "clevel": 6, "typesize": 4}, 0),
({"typesize": 4}, 200 * 1000),
({"splitmode": blosc2.SplitMode.ALWAYS_SPLIT, "nthreads": 5, "typesize": 4}, 200 * 1000 * 2 + 17),
],
)
@pytest.mark.parametrize("special_value, expected_value",
[
(blosc2.SpecialValue.ZERO, 0),
(blosc2.SpecialValue.NAN, np.nan),
(blosc2.SpecialValue.UNINIT, 0),
(blosc2.SpecialValue.VALUE, 34),
(blosc2.SpecialValue.VALUE, np.pi),
(blosc2.SpecialValue.VALUE, b"0123"),
(blosc2.SpecialValue.VALUE, True),
],
)
def test_schunk_fill_special(contiguous, urlpath, cparams, nitems, special_value, expected_value):
storage = {"contiguous": contiguous, "urlpath": urlpath, "cparams": cparams}
blosc2.remove_urlpath(urlpath)

chunk_len = 200 * 1000
schunk = blosc2.SChunk(chunksize=chunk_len * 4, **storage)
if special_value in [blosc2.SpecialValue.ZERO, blosc2.SpecialValue.NAN, blosc2.SpecialValue.UNINIT]:
schunk.fill_special(nitems, special_value)
else:
schunk.fill_special(nitems, special_value, expected_value)
assert len(schunk) == nitems

if special_value != blosc2.SpecialValue.UNINIT:
dtype = np.int32
if isinstance(expected_value, float):
dtype = np.float32
elif isinstance(expected_value, bytes):
dtype = np.dtype('|S' + str(len(expected_value)))
array = np.full(nitems, expected_value, dtype=dtype)
dest = np.empty(nitems, dtype=dtype)
schunk.get_slice(out=dest)
if dtype in [np.float32, np.float64]:
np.testing.assert_allclose(dest, array)
else:
np.testing.assert_equal(dest, array)

blosc2.remove_urlpath(urlpath)
65 changes: 0 additions & 65 deletions tests/test_schunk_fill.py

This file was deleted.

0 comments on commit 296712f

Please sign in to comment.