@@ -204,81 +204,6 @@ def test_sharding_partial_read(
204204 assert np .all (read_data == 1 )
205205
206206
207- @pytest .mark .skip ("This is profiling rather than a test" )
208- @pytest .mark .slow_hypothesis
209- @pytest .mark .parametrize ("store" , ["local" ], indirect = ["store" ])
210- def test_partial_shard_read_performance (store : Store ) -> None :
211- import asyncio
212- import json
213- from functools import partial
214- from itertools import product
215- from timeit import timeit
216- from unittest .mock import AsyncMock
217-
218- # The whole test array is a single shard to keep runtime manageable while
219- # using a realistic shard size (256 MiB uncompressed, ~115 MiB compressed).
220- # In practice, the array is likely to be much larger with many shards of this
221- # rough order of magnitude. There are 512 chunks per shard in this example.
222- array_shape = (512 , 512 , 512 )
223- shard_shape = (512 , 512 , 512 ) # 256 MiB uncompressed unit16s
224- chunk_shape = (64 , 64 , 64 ) # 512 KiB uncompressed unit16s
225- dtype = np .uint16
226-
227- a = zarr .create_array (
228- StorePath (store ),
229- shape = array_shape ,
230- chunks = chunk_shape ,
231- shards = shard_shape ,
232- compressors = BloscCodec (cname = "zstd" ),
233- dtype = dtype ,
234- fill_value = np .iinfo (dtype ).max ,
235- )
236- # Narrow range of values lets zstd compress to about 1/2 of uncompressed size
237- a [:] = np .random .default_rng (123 ).integers (low = 0 , high = 50 , size = array_shape , dtype = dtype )
238-
239- num_calls = 20
240- experiments = []
241- for concurrency , get_latency , coalesce_max_gap , statement in product (
242- [1 , 10 , 100 ],
243- [0.0 , 0.01 ],
244- [- 1 , 2 ** 20 , 10 * 2 ** 20 ],
245- ["a[0, :, :]" , "a[:, 0, :]" , "a[:, :, 0]" ],
246- ):
247- zarr .config .set (
248- {
249- "async.concurrency" : concurrency ,
250- "sharding.read.coalesce_max_gap_bytes" : coalesce_max_gap ,
251- }
252- )
253-
254- async def get_with_latency (* args : Any , get_latency : float , ** kwargs : Any ) -> Any :
255- await asyncio .sleep (get_latency )
256- return await store .get (* args , ** kwargs )
257-
258- store_mock = AsyncMock (wraps = store , spec = store .__class__ )
259- store_mock .get .side_effect = partial (get_with_latency , get_latency = get_latency )
260-
261- a = zarr .open_array (StorePath (store_mock ))
262-
263- store_mock .reset_mock ()
264-
265- # Each timeit call accesses a 512x512 slice covering 64 chunks
266- time = timeit (statement , number = num_calls , globals = {"a" : a }) / num_calls
267- experiments .append (
268- {
269- "concurrency" : concurrency ,
270- "coalesce_max_gap" : coalesce_max_gap ,
271- "get_latency" : get_latency ,
272- "statement" : statement ,
273- "time" : time ,
274- "store_get_calls" : store_mock .get .call_count ,
275- }
276- )
277-
278- with open ("zarr-python-partial-shard-read-performance-with-coalesce.json" , "w" ) as f :
279- json .dump (experiments , f )
280-
281-
282207@pytest .mark .parametrize ("index_location" , ["start" , "end" ])
283208@pytest .mark .parametrize ("store" , ["local" , "memory" , "zip" ], indirect = ["store" ])
284209@pytest .mark .parametrize ("coalesce_reads" , [True , False ])
0 commit comments