You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2021/07/29 21:38:28 UTC

[sis] branch geoapi-4.0 updated: Minor optimization for the case where the bands to read are consecutive.

This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 79d5221  Minor optimization for the case where the bands to read are consecutive.
79d5221 is described below

commit 79d5221c53a6fefd0f4eab7aab2f061007f7eb16
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Jul 29 23:10:42 2021 +0200

    Minor optimization for the case where the bands to read are consecutive.
---
 .../sis/storage/geotiff/CompressedSubset.java      | 47 +++++++++++++++++-----
 1 file changed, 38 insertions(+), 9 deletions(-)

diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
index 1b36eb1..f49ed60 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CompressedSubset.java
@@ -107,19 +107,36 @@ final class CompressedSubset extends DataSubset {
         final int between = sourcePixelStride * (getSubsampling(0) - 1);
         int afterLastBand = sourcePixelStride * (getTileSize(0) - 1);
         if (selectedBands != null && sourcePixelStride > 1) {
-            final int n = selectedBands.length;
-            skipAfterElements = new int[n];
+            final int[] skips = new int[selectedBands.length];
+            final int m = skips.length - 1;
             int b = sourcePixelStride;
-            for (int i = n; --i >= 0;) {
+            for (int i=m; i >= 0; --i) {
                 // Number of sample values to skip after each band.
-                skipAfterElements[i] = b - (b = selectedBands[i]) - 1;
+                skips[i] = b - (b = selectedBands[i]) - 1;
+            }
+            beforeFirstBand = b;
+            afterLastBand  += skips[m];                     // Add trailing bands that were left unread.
+            skips[m]       += between + beforeFirstBand;    // Add pixels skipped by subsampling and move to first band.
+            /*
+             * If there is more than one band and all of them are consecutive, then we can optimize a little bit
+             * by reading "chunks" of the size of those consecutive bands instead of reading each band separately.
+             *
+             * Example: if the image has 5 bands and users requested bands 1, 2 and 3 (no empty space between bands),
+             * then we can read those 3 bands as a "chunk" on 3 sample values instead of reading 3 chunks of 1 value.
+             */
+            if (m != 0 && startsWithZeros(skips, m)) {
+                samplesPerElement = selectedBands.length;
+                skipAfterElements = new int[] {skips[m]};
+            } else {
+                samplesPerElement = 1;
+                skipAfterElements = skips;
             }
-            beforeFirstBand         = b;
-            afterLastBand          += skipAfterElements[n-1];       // Add trailing bands that were left unread.
-            skipAfterElements[n-1] += between + beforeFirstBand;    // Add pixels skipped by subsampling and move to first band.
-            samplesPerElement       = 1;
-            // TODO: we could optimize if we find that all sample values to read are consecutive.
         } else {
+            /*
+             * Case when all bands are read. If there is a subsampling, then `between` is the space (in number of
+             * sample values) between two pixels. If that space is zero, it will be possible to read the whole row
+             * in a single read operation, but that optimization is done in `Inflater` constructor.
+             */
             skipAfterElements = (between != 0) ? new int[] {between} : null;
             samplesPerElement = sourcePixelStride;
             beforeFirstBand   = 0;
@@ -133,6 +150,18 @@ final class CompressedSubset extends DataSubset {
     }
 
     /**
+     * Returns {@code true} if all array elements except the last one are zeros.
+     * A {@code true} value means that all sample values in a pixel are consecutive.
+     *
+     * @param  m  {@code skipAfterElements.length} - 1. Shall be greater than zero.
+     */
+    private static boolean startsWithZeros(final int[] skipAfterElements, int m) {
+        do if (skipAfterElements[--m] != 0) return false;
+        while (m != 0);
+        return true;
+    }
+
+    /**
      * Computes the number of pixels to read in dimension <var>i</var>
      * The arguments given to this method are the ones given to the {@code readSlice(…)} method.
      */