|
| 1 | +"""Test live mask chunk size calculation.""" |
| 2 | + |
| 3 | +from typing import TYPE_CHECKING |
| 4 | + |
| 5 | +import numpy as np |
| 6 | +import pytest |
| 7 | + |
| 8 | +from mdio.core.utils_write import MAX_SIZE_LIVE_MASK |
| 9 | +from mdio.core.utils_write import get_constrained_chunksize |
| 10 | +from mdio.core.utils_write import get_live_mask_chunksize |
| 11 | + |
| 12 | + |
| 13 | +if TYPE_CHECKING: |
| 14 | + from numpy.typing import DTypeLike |
| 15 | + |
| 16 | + |
| 17 | +@pytest.mark.parametrize( |
| 18 | + ("shape", "dtype", "limit", "expected_chunks"), |
| 19 | + [ |
| 20 | + ((100,), "int8", 100, (100,)), # 1D full chunk |
| 21 | + ((8, 6), "int8", 20, (4, 4)), # 2D adjusted int8 |
| 22 | + ((6, 8), "int16", 96, (6, 8)), # 2D small int16 |
| 23 | + ((9, 6, 4), "int8", 100, (5, 5, 4)), # 3D adjusted |
| 24 | + ((4, 5), "int32", 4, (1, 1)), # test minimum edge case |
| 25 | + ((10, 10), "int8", 1000, (10, 10)), # big limit |
| 26 | + ((7, 5), "int8", 35, (7, 5)), # test full primes |
| 27 | + ((7, 5), "int8", 23, (4, 4)), # test adjusted primes |
| 28 | + ], |
| 29 | +) |
| 30 | +def test_auto_chunking( |
| 31 | + shape: tuple[int, ...], |
| 32 | + dtype: "DTypeLike", |
| 33 | + limit: int, |
| 34 | + expected_chunks: tuple[int, ...], |
| 35 | +) -> None: |
| 36 | + """Test automatic chunking based on size limit and an array spec.""" |
| 37 | + result = get_constrained_chunksize(shape, dtype, limit) |
| 38 | + assert result == expected_chunks |
| 39 | + |
| 40 | + |
| 41 | +class TestAutoChunkLiveMask: |
| 42 | + """Test class for live mask auto chunking.""" |
| 43 | + |
| 44 | + @pytest.mark.parametrize( |
| 45 | + ("shape", "expected_chunks"), |
| 46 | + [ |
| 47 | + ((100,), (100,)), # small 1d |
| 48 | + ((100, 100), (100, 100)), # small 2d |
| 49 | + ((50000, 50000), (25000, 25000)), # large 2d |
| 50 | + ((1500, 1500, 1500), (750, 750, 750)), # large 3d |
| 51 | + ((1000, 1000, 100, 36), (334, 334, 100, 36)), # large 4d |
| 52 | + ], |
| 53 | + ) |
| 54 | + def test_auto_chunk_live_mask( |
| 55 | + self, |
| 56 | + shape: tuple[int, ...], |
| 57 | + expected_chunks: tuple[int, ...], |
| 58 | + ) -> None: |
| 59 | + """Test auto chunked live mask is within expected number of bytes.""" |
| 60 | + result = get_live_mask_chunksize(shape) |
| 61 | + assert result == expected_chunks |
| 62 | + |
| 63 | + @pytest.mark.parametrize( |
| 64 | + "shape", |
| 65 | + [ |
| 66 | + # Below are >500MiB. Smaller ones tested above |
| 67 | + (32768, 32768), |
| 68 | + (46341, 46341), |
| 69 | + (86341, 96341), |
| 70 | + (55000, 97500), |
| 71 | + (100000, 100000), |
| 72 | + (1024, 1024, 1024), |
| 73 | + (215, 215, 215, 215), |
| 74 | + (512, 216, 512, 400), |
| 75 | + (74, 74, 74, 74, 74), |
| 76 | + (512, 17, 43, 200, 50), |
| 77 | + ], |
| 78 | + ) |
| 79 | + def test_auto_chunk_live_mask_nbytes(self, shape: tuple[int, ...]) -> None: |
| 80 | + """Test auto chunked live mask is within expected number of bytes.""" |
| 81 | + result = get_live_mask_chunksize(shape) |
| 82 | + chunk_elements = np.prod(result) |
| 83 | + |
| 84 | + # We want them to be 500MB +/- 25% |
| 85 | + assert chunk_elements > MAX_SIZE_LIVE_MASK * 0.75 |
| 86 | + assert chunk_elements < MAX_SIZE_LIVE_MASK * 1.25 |
0 commit comments