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 2022/06/29 17:15:31 UTC

[sis] branch geoapi-4.0 updated: Adjust the size of the temporary buffer for TIFF decompression.

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 748a5a1fff Adjust the size of the temporary buffer for TIFF decompression.
748a5a1fff is described below

commit 748a5a1fff56952bdb47b7bc6a0c81385bc27376
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Jun 29 19:15:08 2022 +0200

    Adjust the size of the temporary buffer for TIFF decompression.
---
 .../main/java/org/apache/sis/image/DataType.java   | 14 ++++++++++-
 .../java/org/apache/sis/image/package-info.java    |  2 +-
 .../storage/inflater/CompressionChannel.java       | 28 +++++++++++++++++-----
 .../sis/internal/storage/inflater/Inflater.java    |  5 ++--
 4 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java b/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java
index 9c18299b04..56239f37dc 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java
@@ -34,7 +34,7 @@ import static org.apache.sis.internal.util.Numerics.MAX_INTEGER_CONVERTIBLE_TO_F
  * This is a type-safe version of the {@code TYPE_*} constants defined in {@link DataBuffer}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
  * @since   1.1
  * @module
  */
@@ -257,6 +257,18 @@ public enum DataType {
         return DataBuffer.getDataTypeSize(ordinal());
     }
 
+    /**
+     * Returns the size in bytes of this data type.
+     * If the {@linkplain #size() number of bits} is smaller than {@value Byte#SIZE}, then this method returns 1.
+     *
+     * @return size in bytes of this data type, not smaller than 1.
+     *
+     * @since 1.3
+     */
+    public final int bytes() {
+        return Math.max(size() >>> 3, 1);
+    }
+
     /**
      * Returns whether this type is an unsigned integer type.
      * Unsigned types are {@link #BYTE} and {@link #USHORT}.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/package-info.java b/core/sis-feature/src/main/java/org/apache/sis/image/package-info.java
index 0862082562..234e989c43 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/package-info.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/package-info.java
@@ -42,7 +42,7 @@
  * @author  Rémi Maréchal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.2
+ * @version 1.3
  * @since   1.0
  * @module
  */
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java
index 95e5473fb2..f80239ab1c 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/CompressionChannel.java
@@ -16,8 +16,11 @@
  */
 package org.apache.sis.internal.storage.inflater;
 
+import java.util.Arrays;
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import org.apache.sis.math.MathFunctions;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.geotiff.Resources;
 import org.apache.sis.internal.storage.io.ChannelDataInput;
 
@@ -29,15 +32,16 @@ import org.apache.sis.internal.storage.io.ChannelDataInput;
  * <p>The {@link #close()} method shall be invoked when this channel is no longer used.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
  * @since   1.1
  * @module
  */
 abstract class CompressionChannel extends PixelChannel {
     /**
-     * Size of the buffer where to temporarily copy decompressed data.
+     * Desired size of the buffer where to temporarily copy decompressed data.
+     * The actual buffer size may be larger, but should not be smaller.
      */
-    private static final int BUFFER_SIZE = 4096;
+    private static final int BUFFER_SIZE = 8192;
 
     /**
      * The source of data to decompress.
@@ -86,13 +90,25 @@ abstract class CompressionChannel extends PixelChannel {
      * Creates the data input stream to use for getting uncompressed data.
      * The {@linkplain #input} stream must be on the start position before to invoke this method.
      *
-     * @param  channel  the channel to wrap. This is {@code this} unless a {@link Predictor} is applied.
+     * <p>This method tries to create a buffer of the size of scanline stride, or a multiple of that size,
+     * for performance reasons. A well adjusted buffer size reduces calls to {@link ByteBuffer#compact()},
+     * which in turn reduces the amount of copy operations between different regions of the buffer.</p>
+     *
+     * @param  channel         the channel to wrap. This is {@code this} unless a {@link Predictor} is applied.
+     * @param  scanlineStride  the scanline stride of the image to read. Used for choosing a buffer size.
      * @throws IOException if an error occurred while filling the buffer with initial data.
      * @return the data input for uncompressed data.
      */
-    final ChannelDataInput createDataInput(final PixelChannel channel) throws IOException {
+    final ChannelDataInput createDataInput(final PixelChannel channel, int scanlineStride) throws IOException {
+        if (scanlineStride > BUFFER_SIZE) {
+            final int[] divisors = MathFunctions.divisors(scanlineStride);
+            int i = Arrays.binarySearch(divisors, BUFFER_SIZE);
+            if (i < 0) i = ~i;      // Really tild, not minus.
+            scanlineStride = divisors[i];
+        }
+        final int capacity = Numerics.ceilDiv(BUFFER_SIZE, scanlineStride) * scanlineStride;
         // TODO: remove cast with JDK9.
-        final ByteBuffer buffer = (ByteBuffer) ByteBuffer.allocate(BUFFER_SIZE).order(input.buffer.order()).limit(0);
+        final ByteBuffer buffer = (ByteBuffer) ByteBuffer.allocate(capacity).order(input.buffer.order()).limit(0);
         return new ChannelDataInput(input.filename, channel, buffer, true);
     }
 
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java
index 7321c5ed6e..cb6137895b 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/Inflater.java
@@ -239,8 +239,9 @@ public abstract class Inflater implements Closeable {
                 throw unsupportedEncoding(caller, Resources.Keys.UnsupportedPredictor_1, predictor);
             }
         }
-        return CopyFromBytes.create(inflater.createDataInput(channel), dataType,
-                chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement);
+        final int scanlineStride = Math.multiplyExact(sourceWidth, sourcePixelStride * dataType.bytes());
+        return CopyFromBytes.create(inflater.createDataInput(channel, scanlineStride),
+                dataType, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement);
     }
 
     /**