<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blosc Home Page  (Posts about caterva slicing perf)</title><link>https://blosc.org/</link><description></description><atom:link href="https://blosc.org/categories/caterva-slicing-perf.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:blosc@blosc.org"&gt;The Blosc Developers&lt;/a&gt; </copyright><lastBuildDate>Sun, 19 Jul 2026 11:09:13 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Caterva Slicing Performance: A Study</title><link>https://blosc.org/posts/caterva-slicing-perf/</link><dc:creator>Oscar Guiñon, Francesc Alted</dc:creator><description>&lt;img alt="/images/cat_slicing/caterva.png" class="align-center" src="https://blosc.org/images/cat_slicing/caterva.png" style="width: 50%;"&gt;
&lt;p&gt;&lt;a class="reference external" href="https://caterva.readthedocs.io/en/latest/getting_started/overview.html"&gt;Caterva&lt;/a&gt; is a C library for handling multi-dimensional, chunked, compressed datasets in an easy and fast way.  It is build on top of the &lt;a class="reference external" href="https://c-blosc2.readthedocs.io/en/latest/"&gt;C-Blosc2&lt;/a&gt; library, leveraging all its &lt;a class="reference external" href="https://www.blosc.org/posts/blosc2-ready-general-review/"&gt;avantages on modern CPUs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Caterva can be used in a lot of different situations; however, where it really stands out is for extracting multidimensional slices of compressed datasets because, thanks to the double partitioning schema that it implements, the amount of data that has to be decompressed so as to get the slice is minimized, making data extraction faster (usually).  In this installment, you will be offered a rational on how double partitioning works, together with some examples where it shines, and others where it is not that good.&lt;/p&gt;
&lt;section id="double-partitioning"&gt;
&lt;h2&gt;Double partitioning&lt;/h2&gt;
&lt;img alt="/images/cat_slicing/cat_vs_zarr,hdf5.png" class="align-center" src="https://blosc.org/images/cat_slicing/cat_vs_zarr,hdf5.png" style="width: 70%;"&gt;
&lt;p&gt;Some libraries like &lt;a class="reference external" href="https://www.hdfgroup.org/solutions/hdf5/"&gt;HDF5&lt;/a&gt; or &lt;a class="reference external" href="https://zarr.readthedocs.io/en/stable/"&gt;Zarr&lt;/a&gt; store data into multidimensional chunks. This makes slice extraction from compressed datasets more efficient than using monolithic compression, since only the chunks containing the interesting slice are decompressed instead of the entire array.&lt;/p&gt;
&lt;p&gt;In addition, Caterva introduces a new level of partitioning.  Within each chunk, the data is re-partitioned into smaller multidimensional sets called blocks.  This generally improves the slice extraction, since this allows to decompress only the blocks containing the data in desired slice instead of the whole chunks.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="slice-extraction-with-caterva-hdf5-and-zarr"&gt;
&lt;h2&gt;Slice extraction with Caterva, HDF5 and Zarr&lt;/h2&gt;
&lt;p&gt;So as to see how the double partitioning performs with respect to a traditional single partition schema, we are going to compare the ability to extract multidimensional slices from compressed data of Caterva, HDF5 and Zarr. The examples below consist on extracting some hyper-planes from chunked arrays with different properties and seeing how Caterva performs compared with traditional libraries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; So as to better compare apples with apples, all the benchmarks below have been run using Blosc (with LZ4 as the internal codec) as the compressor by default, with the shuffle filter.  Even if Caterva uses the newest C-Blosc2 compressor, and HDF5 and Zarr uses its C-Blosc(1) antecessor, the performance of both libraries are very similar.  Also, for easier interactivity, we have used the libraries via Python wrappers (&lt;a class="reference external" href="https://python-caterva.readthedocs.io/en/latest/"&gt;python-caterva&lt;/a&gt;, &lt;a class="reference external" href="http://www.h5py.org"&gt;h5py&lt;/a&gt;, &lt;a class="reference external" href="https://zarr.readthedocs.io/en/stable/"&gt;Zarr&lt;/a&gt;).&lt;/p&gt;
&lt;/section&gt;
&lt;section id="dimensional-array"&gt;
&lt;h2&gt;2-dimensional array&lt;/h2&gt;
&lt;p&gt;This is a 2-dimensional array and has the following properties, designed to optimize slice extraction from the second dimension:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code console"&gt;&lt;a id="rest_code_3ab08c4a1d594270889f66f45663157d-1" name="rest_code_3ab08c4a1d594270889f66f45663157d-1" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_3ab08c4a1d594270889f66f45663157d-1"&gt;&lt;/a&gt;&lt;span class="go"&gt;shape = (8_000, 8_000)&lt;/span&gt;
&lt;a id="rest_code_3ab08c4a1d594270889f66f45663157d-2" name="rest_code_3ab08c4a1d594270889f66f45663157d-2" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_3ab08c4a1d594270889f66f45663157d-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;chunkshape = (4_000, 100)&lt;/span&gt;
&lt;a id="rest_code_3ab08c4a1d594270889f66f45663157d-3" name="rest_code_3ab08c4a1d594270889f66f45663157d-3" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_3ab08c4a1d594270889f66f45663157d-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;blockshape = (500, 25)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we can see that the ratio between chunkshape and blockshape is 8x in dimension 0 and 4x in dimension 1.&lt;/p&gt;
&lt;img alt="/images/cat_slicing/dim0.png" class="align-center" src="https://blosc.org/images/cat_slicing/dim0.png" style="width: 70%;"&gt;
&lt;img alt="/images/cat_slicing/dim1.png" class="align-center" src="https://blosc.org/images/cat_slicing/dim1.png" style="width: 70%;"&gt;
&lt;p&gt;Now we are going to extract some planes from the chunked arrays and will plot the performance. For dimension 0 we extract a hyperplane &lt;cite&gt;[i, :]&lt;/cite&gt;, and for dimension 1, &lt;cite&gt;[:, i]&lt;/cite&gt;, where &lt;em&gt;i&lt;/em&gt; is a random integer.&lt;/p&gt;
&lt;img alt="/images/cat_slicing/2dim.png" class="align-center" src="https://blosc.org/images/cat_slicing/2dim.png" style="width: 80%;"&gt;
&lt;p&gt;Here we see that the slicing times are similar in the dimension 1. However, Caterva performs better in the dimension 0. This is because with double partitioning you only have to decompress the blocks containing the slice instead of the whole chunk.&lt;/p&gt;
&lt;p&gt;In fact, Caterva is around 12x faster than HDF5 and 9x faster than Zarr for slicing the dimension 0, which makes sense since Caterva decompresses 8x less data.
For the dimension 1, Caterva is approximately 3x faster than HDF5 and Zarr; in this case Caterva has to decompress 4x less data.&lt;/p&gt;
&lt;p&gt;That is, the difference in slice extraction speed depends largely on the ratio between the chunk size and the block size. Therefore, for slices where the chunks that contain the slice also have many items that do not belong to it, the existence of blocks (i.e. the second partition) allows to significantly reduce the amount of data to decompress.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="overhead-of-the-second-partition"&gt;
&lt;h2&gt;Overhead of the second partition&lt;/h2&gt;
&lt;p&gt;So as to better assess the possible performance cost of the second partition, let's analyze a new case of a 3-dimensional array with the following parameters:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code console"&gt;&lt;a id="rest_code_5da26a1254e3454aad948be93335ae9d-1" name="rest_code_5da26a1254e3454aad948be93335ae9d-1" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_5da26a1254e3454aad948be93335ae9d-1"&gt;&lt;/a&gt;&lt;span class="go"&gt;shape = (800, 600, 300)&lt;/span&gt;
&lt;a id="rest_code_5da26a1254e3454aad948be93335ae9d-2" name="rest_code_5da26a1254e3454aad948be93335ae9d-2" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_5da26a1254e3454aad948be93335ae9d-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;chunkshape = (200, 100, 80)&lt;/span&gt;
&lt;a id="rest_code_5da26a1254e3454aad948be93335ae9d-3" name="rest_code_5da26a1254e3454aad948be93335ae9d-3" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_5da26a1254e3454aad948be93335ae9d-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;blockshape = (20, 100, 10)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So, in the dimensions 0 and 2 the difference between shape and chunkshape is not too big whereas the difference between chunkshape and blockshape is remarkable.&lt;/p&gt;
&lt;p&gt;However, for the dimension 1, there is not a difference at all between chunkshape and blockshape.  This means that in dim 1 the Caterva machinery will make extra work because of the double partitioning, but it will not get any advantage of it since the block size is going to be equal to the chunk size.  This a perfect scenario for measuring the overhead of the second partition.&lt;/p&gt;
&lt;p&gt;The slices to extract will be &lt;cite&gt;[i, :, :]&lt;/cite&gt;, &lt;cite&gt;[:, i, :]&lt;/cite&gt; or &lt;cite&gt;[:, :, i]&lt;/cite&gt;. Let's see the execution times for slicing these planes:&lt;/p&gt;
&lt;img alt="/images/cat_slicing/3dim.png" class="align-center" src="https://blosc.org/images/cat_slicing/3dim.png" style="width: 80%;"&gt;
&lt;p&gt;As we can see, the performance in dim 1 is around the same order than HDF5 and Zarr (Zarr being a bit faster actually), but difference is not large, so that means that the overhead introduced purely by the second partition is not that important.
However, in the other dimensions Caterva still outperforms (by far) Zarr and HDF5.  This is because the two level partitioning works as intended here.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="a-last-hyper-slicing-example"&gt;
&lt;h2&gt;A last hyper-slicing example&lt;/h2&gt;
&lt;p&gt;Let's see a final example showing the double partitioning working on a wide range of dimensions.  In this case we choose a 4-dimensional array with the following parameters:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code console"&gt;&lt;a id="rest_code_b1195a523a22483b82ce6dc110456acd-1" name="rest_code_b1195a523a22483b82ce6dc110456acd-1" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_b1195a523a22483b82ce6dc110456acd-1"&gt;&lt;/a&gt;&lt;span class="go"&gt;shape = (400, 80, 100, 50)&lt;/span&gt;
&lt;a id="rest_code_b1195a523a22483b82ce6dc110456acd-2" name="rest_code_b1195a523a22483b82ce6dc110456acd-2" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_b1195a523a22483b82ce6dc110456acd-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;chunkshape = (100, 40, 10, 50)&lt;/span&gt;
&lt;a id="rest_code_b1195a523a22483b82ce6dc110456acd-3" name="rest_code_b1195a523a22483b82ce6dc110456acd-3" href="https://blosc.org/posts/caterva-slicing-perf/#rest_code_b1195a523a22483b82ce6dc110456acd-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;blockshape = (30, 5, 2, 10)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here the last dimension (3) is not optimized for getting hyper-slices, specially in containers with just single partitioning (Zarr and HDF5).  However, Caterva should still perform well in this situation because of the double partitioning.&lt;/p&gt;
&lt;p&gt;The slices we are going to extract will be &lt;cite&gt;[i, :, :, :]&lt;/cite&gt;, &lt;cite&gt;[:, i, :, :]&lt;/cite&gt;, &lt;cite&gt;[:, :, i, :]&lt;/cite&gt; or &lt;cite&gt;[:, :, :, i]&lt;/cite&gt;. Let's see the execution times for slicing these hyperplanes:&lt;/p&gt;
&lt;img alt="/images/cat_slicing/4dim.png" class="align-center" src="https://blosc.org/images/cat_slicing/4dim.png" style="width: 80%;"&gt;
&lt;p&gt;As we can see, in this case Caterva outperforms Zarr and HDF5 in all dimensions.  However, the advantage is not that important for the last dimension.  The reason is that in this last dimension Caterva has a noticeably lower ratio between its shape and blockshape than in the other dimensions.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="final-thoughts"&gt;
&lt;h2&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;We have seen that adding a second partition is beneficial for improving slicing performance in general.  Of course, there are some situations where the overhead of the second partition can be noticeable, but the good news is that such an overhead does not get too large when compared with containers with only one level of partitioning.&lt;/p&gt;
&lt;p&gt;Finally, we can conclude that Caterva usually obtains better results due to its second partitioning, but when it shines the most is when the two levels of partitioning are well balanced among them and also with respect to the shape of the container.&lt;/p&gt;
&lt;p&gt;As always, there is no replacement for experimentation so, in case you want to try Caterva by yourself (and you should if you really care about this problem), you can use &lt;a class="reference external" href="https://github.com/Blosc/caterva-scipy21"&gt;our Caterva poster&lt;/a&gt;; it is based on a Jupyter notebook that you can adapt to your own scenarios.&lt;/p&gt;
&lt;/section&gt;</description><category>caterva slicing perf</category><guid>https://blosc.org/posts/caterva-slicing-perf/</guid><pubDate>Mon, 26 Jul 2021 04:32:20 GMT</pubDate></item></channel></rss>