From d0e8aec041d7e0a8a8e72da079b428afff3fcd26 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 26 Apr 2023 16:37:18 +0000 Subject: [PATCH] 8306374: (bf) Improve performance of DirectCharBuffer::append(CharSequence[,int,int]) Reviewed-by: liach, alanb --- .../java/nio/Direct-X-Buffer.java.template | 63 +++++++++++++++++++ .../classes/java/nio/X-Buffer.java.template | 2 +- .../jdk/java/nio/Buffer/Basic-X.java.template | 28 ++++++--- test/jdk/java/nio/Buffer/Basic.java | 2 +- test/jdk/java/nio/Buffer/BasicChar.java | 28 ++++++--- .../bench/java/nio/CharBufferAppend.java | 38 ++++++++++- 6 files changed, 142 insertions(+), 19 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template index 3f444d93568..f7f1d33228d 100644 --- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template @@ -446,6 +446,69 @@ class Direct$Type$Buffer$RW$$BO$ // --- Methods to support CharSequence --- +#if[rw] + private static final int APPEND_BUF_SIZE = 1024; + + private $Type$Buffer appendChars(CharSequence csq, int start, int end) { + Objects.checkFromToIndex(start, end, csq.length()); + + int pos = position(); + int lim = limit(); + int rem = (pos <= lim) ? lim - pos : 0; + int length = end - start; + if (length > rem) + throw new BufferOverflowException(); + + char[] buf = new char[Math.min(APPEND_BUF_SIZE, length)]; + int index = pos; + while (start < end) { + int count = end - start; + if (count > buf.length) + count = buf.length; + + if (csq instanceof String str) { + str.getChars(start, start + count, buf, 0); + } else if (csq instanceof StringBuilder sb) { + sb.getChars(start, start + count, buf, 0); + } else if (csq instanceof StringBuffer sb) { + sb.getChars(start, start + count, buf, 0); + } + + putArray(index, buf, 0, count); + + start += count; + index += count; + } + + position(pos + length); + + return this; + } +#end[rw] + + public $Type$Buffer append(CharSequence csq) { +#if[rw] + if (csq instanceof StringBuilder) + return appendChars(csq, 0, csq.length()); + + return super.append(csq); +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer append(CharSequence csq, int start, int end) { +#if[rw] + if (csq instanceof String || csq instanceof StringBuffer || + csq instanceof StringBuilder) + return appendChars(csq, start, end); + + return super.append(csq, start, end); +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + public CharBuffer subSequence(int start, int end) { int pos = position(); int lim = limit(); diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template index 1261e325515..698ecbfc9e4 100644 --- a/src/java.base/share/classes/java/nio/X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template @@ -1319,7 +1319,7 @@ public abstract sealed class $Type$Buffer return put(index, src, 0, src.length); } - private $Type$Buffer putArray(int index, $type$[] src, int offset, int length) { + $Type$Buffer putArray(int index, $type$[] src, int offset, int length) { #if[rw] if ( #if[char] diff --git a/test/jdk/java/nio/Buffer/Basic-X.java.template b/test/jdk/java/nio/Buffer/Basic-X.java.template index 25ba1e2e26d..53982769694 100644 --- a/test/jdk/java/nio/Buffer/Basic-X.java.template +++ b/test/jdk/java/nio/Buffer/Basic-X.java.template @@ -41,6 +41,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Random; #end[byte] +#if[char] +import java.util.function.IntFunction; +#end[char] public class Basic$Type$ @@ -646,15 +649,24 @@ public class Basic$Type$ {cslen/2, cslen + 1} // end > cslen }; - for (CharSequence csq : csqs) { - // append() should throw BufferOverflowException - tryCatch(b, BufferOverflowException.class, () -> - CharBuffer.allocate(cslen/8).append(csq, cslen/4, cslen/2)); + IntFunction[] producers = new IntFunction[] { + (i) -> CharBuffer.allocate(i), + (i) -> ByteBuffer.allocateDirect(2*i).asCharBuffer() + }; - // append() should throw IndexOutOfBoundsException - for (int[] bds : bounds) - tryCatch(b, IndexOutOfBoundsException.class, () -> - CharBuffer.allocate(cslen + 1).append(csq, bds[0], bds[1])); + for (IntFunction f : producers) { + for (CharSequence csq : csqs) { + // append() should throw BufferOverflowException + final CharBuffer cbBOE = f.apply(cslen/8); + tryCatch(cbBOE, BufferOverflowException.class, () -> + cbBOE.append(csq, cslen/4, cslen/2)); + + // append() should throw IndexOutOfBoundsException + final CharBuffer cbIOOBE = f.apply(cslen + 1); + for (int[] bds : bounds) + tryCatch(cbIOOBE, IndexOutOfBoundsException.class, () -> + cbIOOBE.append(csq, bds[0], bds[1])); + } } // end 8306623 diff --git a/test/jdk/java/nio/Buffer/Basic.java b/test/jdk/java/nio/Buffer/Basic.java index 6bdf901012b..0eac87b765e 100644 --- a/test/jdk/java/nio/Buffer/Basic.java +++ b/test/jdk/java/nio/Buffer/Basic.java @@ -26,7 +26,7 @@ * @bug 4413135 4414911 4416536 4416562 4418782 4471053 4472779 4490253 4523725 * 4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 5029431 * 5071718 6231529 6221101 6234263 6535542 6591971 6593946 6795561 7190219 - * 7199551 8065556 8149469 8230665 8237514 8306623 + * 7199551 8065556 8149469 8230665 8237514 8306374 8306623 * @modules java.base/java.nio:open * java.base/jdk.internal.misc * @author Mark Reinhold diff --git a/test/jdk/java/nio/Buffer/BasicChar.java b/test/jdk/java/nio/Buffer/BasicChar.java index 58cbd0799ec..813b9cff429 100644 --- a/test/jdk/java/nio/Buffer/BasicChar.java +++ b/test/jdk/java/nio/Buffer/BasicChar.java @@ -42,6 +42,9 @@ import java.nio.*; +import java.util.function.IntFunction; + + public class BasicChar extends Basic @@ -646,15 +649,24 @@ public class BasicChar {cslen/2, cslen + 1} // end > cslen }; - for (CharSequence csq : csqs) { - // append() should throw BufferOverflowException - tryCatch(b, BufferOverflowException.class, () -> - CharBuffer.allocate(cslen/8).append(csq, cslen/4, cslen/2)); + IntFunction[] producers = new IntFunction[] { + (i) -> CharBuffer.allocate(i), + (i) -> ByteBuffer.allocateDirect(2*i).asCharBuffer() + }; - // append() should throw IndexOutOfBoundsException - for (int[] bds : bounds) - tryCatch(b, IndexOutOfBoundsException.class, () -> - CharBuffer.allocate(cslen + 1).append(csq, bds[0], bds[1])); + for (IntFunction f : producers) { + for (CharSequence csq : csqs) { + // append() should throw BufferOverflowException + final CharBuffer cbBOE = f.apply(cslen/8); + tryCatch(cbBOE, BufferOverflowException.class, () -> + cbBOE.append(csq, cslen/4, cslen/2)); + + // append() should throw IndexOutOfBoundsException + final CharBuffer cbIOOBE = f.apply(cslen + 1); + for (int[] bds : bounds) + tryCatch(cbIOOBE, IndexOutOfBoundsException.class, () -> + cbIOOBE.append(csq, bds[0], bds[1])); + } } // end 8306623 diff --git a/test/micro/org/openjdk/bench/java/nio/CharBufferAppend.java b/test/micro/org/openjdk/bench/java/nio/CharBufferAppend.java index ea3ef4ab0fe..1d4390c1362 100644 --- a/test/micro/org/openjdk/bench/java/nio/CharBufferAppend.java +++ b/test/micro/org/openjdk/bench/java/nio/CharBufferAppend.java @@ -44,7 +44,7 @@ import org.openjdk.jmh.annotations.Warmup; @Fork(1) public class CharBufferAppend { - static final int SIZE = 8192; + static final int SIZE = 32768; static String str; static StringBuffer strbuf; @@ -138,4 +138,40 @@ public class CharBufferAppend { hbDst.clear(); return hbDst.append(strbld, SIZE/4, 3*SIZE/4); } + + @Benchmark + public CharBuffer appendStringToDirect() { + dbDst.clear(); + return dbDst.append(str); + } + + @Benchmark + public CharBuffer appendStringBufferToDirect() { + dbDst.clear(); + return dbDst.append(strbuf); + } + + @Benchmark + public CharBuffer appendStringBuilderToDirect() { + dbDst.clear(); + return dbDst.append(strbld); + } + + @Benchmark + public CharBuffer appendSubStringToDirect() { + dbDst.clear(); + return dbDst.append(str, SIZE/4, 3*SIZE/4); + } + + @Benchmark + public CharBuffer appendSubStringBufferToDirect() { + dbDst.clear(); + return dbDst.append(strbuf, SIZE/4, 3*SIZE/4); + } + + @Benchmark + public CharBuffer appendSubStringBuilderToDirect() { + dbDst.clear(); + return dbDst.append(strbld, SIZE/4, 3*SIZE/4); + } }