On Thu, 20 Jul 2023 14:15:15 GMT, Maurizio Cimadamore <mcimadam...@openjdk.org> 
wrote:

>>> Also... `Integer::toString` seems to be `@IntrinsicCandidate` ?
>> 
>> It's just a bytecode intrinsics, it is only replaced when used in a 
>> fluent-chain of StringBuilder/Buffer.
>
> Also, note that ByteBuffer exposes its backing array (at least if the buffer 
> is not read only) via ByteBuffer::array. This does no copy. So in all the 
> various stream implementations, I believe we can really just use a ByteBuffer 
> instead of an array - and use ByteBuffer::array when we really need an array.
> 
> This makes it very easy to migrate some of the classes that use ByteArray. 
> Here's the patch for DataInputStream:
> 
> 
> diff --git a/src/java.base/share/classes/java/io/DataInputStream.java 
> b/src/java.base/share/classes/java/io/DataInputStream.java
> index 7192b30d5f2..b5b013cdd50 100644
> --- a/src/java.base/share/classes/java/io/DataInputStream.java
> +++ b/src/java.base/share/classes/java/io/DataInputStream.java
> @@ -27,6 +27,8 @@ package java.io;
>  
>  import jdk.internal.util.ByteArray;
>  
> +import java.nio.ByteBuffer;
> +import java.nio.ByteOrder;
>  import java.util.Objects;
>  
>  /**
> @@ -59,7 +61,7 @@ public class DataInputStream extends FilterInputStream 
> implements DataInput {
>          super(in);
>      }
>  
> -    private final byte[] readBuffer = new byte[8];
> +    private final ByteBuffer readBuffer = ByteBuffer.allocate(8); // 
> BIG_ENDIAN
>  
>      /**
>       * working arrays initialized on demand by readUTF
> @@ -316,8 +318,8 @@ public class DataInputStream extends FilterInputStream 
> implements DataInput {
>       * @see        java.io.FilterInputStream#in
>       */
>      public final short readShort() throws IOException {
> -        readFully(readBuffer, 0, 2);
> -        return ByteArray.getShort(readBuffer, 0);
> +        readFully(readBuffer.array(), 0, 2);
> +        return readBuffer.getShort(0);
>      }
>  
>      /**
> @@ -338,8 +340,8 @@ public class DataInputStream extends FilterInputStream 
> implements DataInput {
>       * @see        java.io.FilterInputStream#in
>       */
>      public final int readUnsignedShort() throws IOException {
> -        readFully(readBuffer, 0, 2);
> -        return ByteArray.getUnsignedShort(readBuffer, 0);
> +        readFully(readBuffer.array(), 0, 2);
> +        return Short.toUnsignedInt(readBuffer.getShort(0));
>      }
>  
>      /**
> @@ -360,8 +362,8 @@ public class DataInputStream extends FilterInputStream 
> implements DataInput {
>       * @see        java.io.FilterInputStream#in
>       */
>      public final char readChar() throws IOException {
> -        readFully(readBuffer, 0, 2);
> -        return ByteArray.getChar(readBuffer, 0);
> +        readFully(readBuffer.array(), 0, 2);
> +        return readBuffer.getChar(0);
>      }
>  
>      /**
> @@ -382,8 +384,8 @@ public class DataInputS...

@mcimadamore I compared the performance of `ByteBuffer` and `VarHandle` using a 
JMH benchmark:


public class ByteArray {

    private byte[] array;
    private ByteBuffer byteBuffer;

    private static final VarHandle INT = 
MethodHandles.byteArrayViewVarHandle(int[].class, LITTLE_ENDIAN);
    private static final VarHandle LONG = 
MethodHandles.byteArrayViewVarHandle(long[].class, LITTLE_ENDIAN);

    @Setup
    public void setup() {
        array = new byte[8];
        byteBuffer = ByteBuffer.wrap(array).order(LITTLE_ENDIAN);

        new Random(0).nextBytes(array);
    }

    @Benchmark
    public byte readByte() {
        return array[0];
    }

    @Benchmark
    public byte readByteFromBuffer() {
        return byteBuffer.get(0);
    }

    @Benchmark
    public int readInt() {
        return (int) INT.get(array, 0);
    }

    @Benchmark
    public int readIntFromBuffer() {
        return byteBuffer.getInt(0);
    }


    @Benchmark
    public long readLong() {
        return (long) LONG.get(array, 0);
    }

    @Benchmark
    public long readLongFromBuffer() {
        return byteBuffer.getLong(0);
    }
}


Result:

Benchmark                      Mode  Cnt        Score       Error   Units
ByteArray.readByte            thrpt    5  1270230.180 ± 29172.551  ops/ms
ByteArray.readByteFromBuffer  thrpt    5   623862.080 ± 12167.410  ops/ms
ByteArray.readInt             thrpt    5  1252719.463 ± 77598.672  ops/ms
ByteArray.readIntFromBuffer   thrpt    5   571070.474 ±  1500.426  ops/ms
ByteArray.readLong            thrpt    5  1262720.686 ±   728.100  ops/ms
ByteArray.readLongFromBuffer  thrpt    5   571594.800 ±  3376.735  ops/ms


In this result, ByteBuffer is much slower than VarHandle. Am I doing something 
wrong? What conditions are needed to make the performance of ByteBuffer close 
to that of Unsafe?

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/14636#discussion_r1269578107

Reply via email to