From 8d1ec2b32fca306f3ab5c3e4c89bdd3bd32dbc6e Mon Sep 17 00:00:00 2001 From: JacksonMaxfield Date: Fri, 24 Sep 2021 11:44:06 -0700 Subject: [PATCH 1/4] Add bioformats comparison benchs --- benchmarks/benchmark_image_containers.py | 8 ++-- benchmarks/benchmark_native.py | 49 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 benchmarks/benchmark_native.py diff --git a/benchmarks/benchmark_image_containers.py b/benchmarks/benchmark_image_containers.py index b77433025..fb316b5a0 100644 --- a/benchmarks/benchmark_image_containers.py +++ b/benchmarks/benchmark_image_containers.py @@ -61,7 +61,7 @@ class _ImageContainerTimeSuite: DimensionNames.Samples, ] - def time_init(self, img_path, chunk_dims=None): + def time_init(self, img_path, chunk_dims=None, **kwargs): """ Benchmark how long it takes to validate a file and finish general setup. """ @@ -70,7 +70,7 @@ def time_init(self, img_path, chunk_dims=None): self.ImageContainer(img_path, chunk_dims=chunk_dims) - def time_delayed_array_construct(self, img_path, chunk_dims=None): + def time_delayed_array_construct(self, img_path, chunk_dims=None, **kwargs): """ Benchmark how long it takes to construct the delayed dask array for a file. """ @@ -79,7 +79,7 @@ def time_delayed_array_construct(self, img_path, chunk_dims=None): self.ImageContainer(img_path, chunk_dims=chunk_dims).dask_data - def time_random_single_chunk_read(self, img_path, chunk_dims=None): + def time_random_single_chunk_read(self, img_path, chunk_dims=None, **kwargs): """ Benchmark how long it takes to read a single chunk out of a file. @@ -100,7 +100,7 @@ def time_random_single_chunk_read(self, img_path, chunk_dims=None): ) r.get_image_dask_data(valid_dims_to_return, **random_index_selections).compute() - def time_random_many_chunk_read(self, img_path, chunk_dims=None): + def time_random_many_chunk_read(self, img_path, chunk_dims=None, **kwargs): """ Open a file, get many chunks out of the file at once. diff --git a/benchmarks/benchmark_native.py b/benchmarks/benchmark_native.py new file mode 100644 index 000000000..a92348e87 --- /dev/null +++ b/benchmarks/benchmark_native.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import random +from pathlib import Path + +from aicsimageio.readers.ome_tiff_reader import OmeTiffReader +from aicsimageio.readers.bioformats_reader import BioformatsReader + +from .benchmark_image_containers import _ImageContainerTimeSuite + +############################################################################### + +# We only benchmark against local files as remote files are covered by unit tests +# and are generally slower than local but scale at a similar rate. +LOCAL_RESOURCES_DIR = ( + Path(__file__).parent.parent / "aicsimageio" / "tests" / "resources" +) + +############################################################################### + + +class NativePythonCompareSuite(_ImageContainerTimeSuite): + # This suite measures the effect of switching from Bioformats to a native Python + # file format reader can have. + # All readers will be different, but we do want to show the drawback of reading + # using a Java pipe. + + params = ( + [ + str(LOCAL_RESOURCES_DIR / "pre-variance-cfe.ome.tiff"), + str(LOCAL_RESOURCES_DIR / "variance-cfe.ome.tiff"), + ], + # We don't go above chunking by three dims because it would be rare + # to do so... if you can read four-plus dims in a single chunk why can't you + # just read in the whole image at once. + # We also use CYX here to show that chunking with the _wrong_ dimensions can + # result in longer processing times. + [ + "YX", + "ZYX", + "CYX", + ], + [OmeTiffReader, BioformatsReader], + ) + + def setup(self, img_path, chunk_dims, reader): + random.seed(42) + self.ImageContainer = reader From 98cab304adf0fdd358359e4190292e27e1887c73 Mon Sep 17 00:00:00 2001 From: JacksonMaxfield Date: Fri, 24 Sep 2021 11:59:06 -0700 Subject: [PATCH 2/4] Allow kwargs to all readers --- aicsimageio/readers/bioformats_reader.py | 6 +++++- aicsimageio/readers/czi_reader.py | 1 + aicsimageio/readers/lif_reader.py | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/aicsimageio/readers/bioformats_reader.py b/aicsimageio/readers/bioformats_reader.py index a837f5ea9..e9a9c5340 100644 --- a/aicsimageio/readers/bioformats_reader.py +++ b/aicsimageio/readers/bioformats_reader.py @@ -67,7 +67,11 @@ def _is_supported_image(fs: AbstractFileSystem, path: str, **kwargs: Any) -> boo except Exception: return False - def __init__(self, image: types.PathLike): + def __init__( + self, + image: types.PathLike, + **kwargs: Any, + ): self._fs, self._path = io_utils.pathlike_to_fs(image, enforce_exists=True) # Catch non-local file system if not isinstance(self._fs, LocalFileSystem): diff --git a/aicsimageio/readers/czi_reader.py b/aicsimageio/readers/czi_reader.py index e6834e50c..abb2f3e5c 100644 --- a/aicsimageio/readers/czi_reader.py +++ b/aicsimageio/readers/czi_reader.py @@ -88,6 +88,7 @@ def __init__( image: types.PathLike, chunk_dims: Union[str, List[str]] = DEFAULT_CHUNK_DIMS, chunk_by_dims: Optional[Union[str, List[str]]] = None, + **kwargs: Any, ): # Expand details of provided image self._fs, self._path = io_utils.pathlike_to_fs(image, enforce_exists=True) diff --git a/aicsimageio/readers/lif_reader.py b/aicsimageio/readers/lif_reader.py index 189a739f0..11defb1cb 100644 --- a/aicsimageio/readers/lif_reader.py +++ b/aicsimageio/readers/lif_reader.py @@ -69,6 +69,7 @@ def __init__( self, image: types.PathLike, chunk_dims: Union[str, List[str]] = DEFAULT_CHUNK_DIMS, + **kwargs: Any, ): # Expand details of provided image self._fs, self._path = io_utils.pathlike_to_fs(image, enforce_exists=True) From 8d52f3b1fbc69bd1bde5c2720297c6cd214c1a22 Mon Sep 17 00:00:00 2001 From: JacksonMaxfield Date: Fri, 24 Sep 2021 12:27:37 -0700 Subject: [PATCH 3/4] Update comment on compare suite --- benchmarks/benchmark_native.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/benchmarks/benchmark_native.py b/benchmarks/benchmark_native.py index a92348e87..e736aa1a2 100644 --- a/benchmarks/benchmark_native.py +++ b/benchmarks/benchmark_native.py @@ -21,11 +21,11 @@ class NativePythonCompareSuite(_ImageContainerTimeSuite): - # This suite measures the effect of switching from Bioformats to a native Python - # file format reader can have. - # All readers will be different, but we do want to show the drawback of reading - # using a Java pipe. - + # This suite compares the time it takes to do common operations for file formats + # covered by multiple readers + # (specifically, a native Python reader and the BioformatsReader). + # Where our native implementation is faster or slower than the Bioformats jpype + # implementation. params = ( [ str(LOCAL_RESOURCES_DIR / "pre-variance-cfe.ome.tiff"), From 316a6ebb2334feda067545d13778ddf5b2d6a133 Mon Sep 17 00:00:00 2001 From: JacksonMaxfield Date: Fri, 24 Sep 2021 13:01:04 -0700 Subject: [PATCH 4/4] Pass reader instead of allowing kwargs --- benchmarks/benchmark_image_containers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/benchmark_image_containers.py b/benchmarks/benchmark_image_containers.py index fb316b5a0..e4e050fa7 100644 --- a/benchmarks/benchmark_image_containers.py +++ b/benchmarks/benchmark_image_containers.py @@ -61,7 +61,7 @@ class _ImageContainerTimeSuite: DimensionNames.Samples, ] - def time_init(self, img_path, chunk_dims=None, **kwargs): + def time_init(self, img_path, chunk_dims=None, reader=None): """ Benchmark how long it takes to validate a file and finish general setup. """ @@ -70,7 +70,7 @@ def time_init(self, img_path, chunk_dims=None, **kwargs): self.ImageContainer(img_path, chunk_dims=chunk_dims) - def time_delayed_array_construct(self, img_path, chunk_dims=None, **kwargs): + def time_delayed_array_construct(self, img_path, chunk_dims=None, reader=None): """ Benchmark how long it takes to construct the delayed dask array for a file. """ @@ -79,7 +79,7 @@ def time_delayed_array_construct(self, img_path, chunk_dims=None, **kwargs): self.ImageContainer(img_path, chunk_dims=chunk_dims).dask_data - def time_random_single_chunk_read(self, img_path, chunk_dims=None, **kwargs): + def time_random_single_chunk_read(self, img_path, chunk_dims=None, reader=None): """ Benchmark how long it takes to read a single chunk out of a file. @@ -100,7 +100,7 @@ def time_random_single_chunk_read(self, img_path, chunk_dims=None, **kwargs): ) r.get_image_dask_data(valid_dims_to_return, **random_index_selections).compute() - def time_random_many_chunk_read(self, img_path, chunk_dims=None, **kwargs): + def time_random_many_chunk_read(self, img_path, chunk_dims=None, reader=None): """ Open a file, get many chunks out of the file at once.