From 23dba8c52454ae90eab4cb1b0a168c6e7249dd38 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 19 Mar 2025 10:48:37 +0800 Subject: [PATCH 1/9] more MergeStoreBench --- .../bench/vm/compiler/MergeStoreBench.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index 88b6886881363..f1ec54593cc9c 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -29,6 +29,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -51,6 +52,13 @@ public class MergeStoreBench { CHAR_L = MethodHandles.byteArrayViewVarHandle(char[].class, ByteOrder.LITTLE_ENDIAN), CHAR_B = MethodHandles.byteArrayViewVarHandle(char[].class, ByteOrder.BIG_ENDIAN); + private static final String NULL_STR = "null"; + private static final byte[] NULL_BYTES_LATIN1 = NULL_STR.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); + private static final byte[] NULL_BYTES_UTF16 = NULL_STR.getBytes( + ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? StandardCharsets.UTF_16BE : StandardCharsets.UTF_16LE); + private static final int NULL_INT = UNSAFE.getInt(NULL_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final long NULL_LONG = UNSAFE.getLong(NULL_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); + final static int NUMBERS = 8192; final byte[] bytes4 = new byte[NUMBERS * 4]; @@ -58,6 +66,9 @@ public class MergeStoreBench { final int [] ints = new int [NUMBERS ]; final long[] longs = new long[NUMBERS ]; final char[] chars = new char[NUMBERS ]; + final char[] chars4 = new char[NUMBERS * 4]; + final StringBuilder sb = new StringBuilder(NUMBERS * 4); + final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 8).append('\u4e2d'); @Setup public void setup() { @@ -491,6 +502,111 @@ public void putChars4S(Blackhole BH) { BH.consume(off); } + /** + * Test whether a constant String of length 4 is MergeStored when calling getBytes + */ + @Benchmark + @SuppressWarnings("deprecation") + public void putNull_getBytes(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + NULL_STR.getBytes(0, 4, bytes4, off); + off += 4; + } + BH.consume(off); + } + + /** + * Test whether a constant byte[] with a length of 4 is MergeStored when arraycopy is called + */ + @Benchmark + public void putNull_arraycopy(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + System.arraycopy(NULL_BYTES_LATIN1, 0, bytes4, off, 4); + off += 4; + } + BH.consume(off); + } + + /** + * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other putNull Benchmarks + */ + @Benchmark + public void putNull_unsafePutInt(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + UNSAFE.putInt(bytes4, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, NULL_INT); + off += 4; + } + BH.consume(off); + } + + /** + * Test whether StringBuilder is MergeStored when appending a constant String of length 4 + */ + @Benchmark + public void putNull_string_builder(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb.append(NULL_STR); + } + BH.consume(sb_utf16.length()); + } + + /** + * Test whether the constant String with a length of 4 calls the getChars method to mergestore + */ + @Benchmark + public void putNull_getChars(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + NULL_STR.getChars(0, 4, chars4, off); + off += 4; + } + BH.consume(off); + } + + /** + * Test the performance of putLong for comparison with other putNull_utf16 benchmarks + */ + @Benchmark + public void putNull_utf16_unsafePutLong(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + UNSAFE.putLong(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, NULL_LONG); + off += 8; + } + BH.consume(off); + } + + /** + * Test whether the byte[] arraycopy with a length of 8 is MergeStore + */ + @Benchmark + public void putNull_utf16_arrayCopy(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + System.arraycopy(NULL_BYTES_UTF16, 0, bytes8, off, 8); + off += 8; + } + BH.consume(off); + } + + /** + * Test whether the UTF16 StringBuilder appends a constant String of length 4 to MergeStore + */ + @Benchmark + public void putNull_utf16_string_builder(Blackhole BH) { + sb_utf16.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb_utf16.append(NULL_STR); + } + BH.consume(sb_utf16.length()); + } + static void setIntB(byte[] array, int offset, int value) { array[offset ] = (byte) (value >> 24); array[offset + 1] = (byte) (value >> 16); From 48d1f3af9945244fb245c01075068ec476330296 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 10:27:24 +0800 Subject: [PATCH 2/9] fix naming --- .../bench/vm/compiler/MergeStoreBench.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index f1ec54593cc9c..0ab817ad7a972 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -52,12 +52,12 @@ public class MergeStoreBench { CHAR_L = MethodHandles.byteArrayViewVarHandle(char[].class, ByteOrder.LITTLE_ENDIAN), CHAR_B = MethodHandles.byteArrayViewVarHandle(char[].class, ByteOrder.BIG_ENDIAN); - private static final String NULL_STR = "null"; - private static final byte[] NULL_BYTES_LATIN1 = NULL_STR.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); - private static final byte[] NULL_BYTES_UTF16 = NULL_STR.getBytes( + private static final String STR_4 = "null"; + private static final byte[] STR_4_BYTES_LATIN1 = STR_4.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); + private static final byte[] STR_4_BYTES_UTF16 = STR_4.getBytes( ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? StandardCharsets.UTF_16BE : StandardCharsets.UTF_16LE); - private static final int NULL_INT = UNSAFE.getInt(NULL_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET); - private static final long NULL_LONG = UNSAFE.getLong(NULL_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final int STR_4_BYTES_LATIN1_INT = UNSAFE.getInt(STR_4_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final long STR_4_BYTES_UTF16_LONG = UNSAFE.getLong(STR_4_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); final static int NUMBERS = 8192; @@ -510,7 +510,7 @@ public void putChars4S(Blackhole BH) { public void putNull_getBytes(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - NULL_STR.getBytes(0, 4, bytes4, off); + STR_4.getBytes(0, 4, bytes4, off); off += 4; } BH.consume(off); @@ -520,10 +520,10 @@ public void putNull_getBytes(Blackhole BH) { * Test whether a constant byte[] with a length of 4 is MergeStored when arraycopy is called */ @Benchmark - public void putNull_arraycopy(Blackhole BH) { + public void str4Arraycopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(NULL_BYTES_LATIN1, 0, bytes4, off, 4); + System.arraycopy(STR_4_BYTES_LATIN1, 0, bytes4, off, 4); off += 4; } BH.consume(off); @@ -533,10 +533,10 @@ public void putNull_arraycopy(Blackhole BH) { * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other putNull Benchmarks */ @Benchmark - public void putNull_unsafePutInt(Blackhole BH) { + public void str4UnsafePutInt(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putInt(bytes4, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, NULL_INT); + UNSAFE.putInt(bytes4, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_LATIN1_INT); off += 4; } BH.consume(off); @@ -546,11 +546,11 @@ public void putNull_unsafePutInt(Blackhole BH) { * Test whether StringBuilder is MergeStored when appending a constant String of length 4 */ @Benchmark - public void putNull_string_builder(Blackhole BH) { + public void str4StringBuilder(Blackhole BH) { sb.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb.append(NULL_STR); + sb.append(STR_4); } BH.consume(sb_utf16.length()); } @@ -559,10 +559,10 @@ public void putNull_string_builder(Blackhole BH) { * Test whether the constant String with a length of 4 calls the getChars method to mergestore */ @Benchmark - public void putNull_getChars(Blackhole BH) { + public void str4GetChars(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - NULL_STR.getChars(0, 4, chars4, off); + STR_4.getChars(0, 4, chars4, off); off += 4; } BH.consume(off); @@ -572,10 +572,10 @@ public void putNull_getChars(Blackhole BH) { * Test the performance of putLong for comparison with other putNull_utf16 benchmarks */ @Benchmark - public void putNull_utf16_unsafePutLong(Blackhole BH) { + public void str4Utf16UnsafePutLong(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putLong(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, NULL_LONG); + UNSAFE.putLong(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_UTF16_LONG); off += 8; } BH.consume(off); @@ -585,10 +585,10 @@ public void putNull_utf16_unsafePutLong(Blackhole BH) { * Test whether the byte[] arraycopy with a length of 8 is MergeStore */ @Benchmark - public void putNull_utf16_arrayCopy(Blackhole BH) { + public void str4Utf16ArrayCopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(NULL_BYTES_UTF16, 0, bytes8, off, 8); + System.arraycopy(STR_4_BYTES_UTF16, 0, bytes8, off, 8); off += 8; } BH.consume(off); @@ -598,11 +598,11 @@ public void putNull_utf16_arrayCopy(Blackhole BH) { * Test whether the UTF16 StringBuilder appends a constant String of length 4 to MergeStore */ @Benchmark - public void putNull_utf16_string_builder(Blackhole BH) { + public void str4Utf16StringBuilder(Blackhole BH) { sb_utf16.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb_utf16.append(NULL_STR); + sb_utf16.append(STR_4); } BH.consume(sb_utf16.length()); } From 5fad851cb1542e952d8e4909b308bbcde541561e Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 11:10:41 +0800 Subject: [PATCH 3/9] bug fix & fix comments & add str5 --- .../bench/vm/compiler/MergeStoreBench.java | 115 +++++++++++++++++- 1 file changed, 110 insertions(+), 5 deletions(-) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index 0ab817ad7a972..f3dc9f1c1d08b 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -59,16 +59,28 @@ public class MergeStoreBench { private static final int STR_4_BYTES_LATIN1_INT = UNSAFE.getInt(STR_4_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET); private static final long STR_4_BYTES_UTF16_LONG = UNSAFE.getLong(STR_4_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final String STR_5 = "false"; + private static final byte[] STR_5_BYTES_LATIN1 = STR_5.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); + private static final byte[] STR_5_BYTES_UTF16 = STR_5.getBytes( + ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? StandardCharsets.UTF_16BE : StandardCharsets.UTF_16LE); + private static final int STR_5_BYTES_LATIN1_INT = UNSAFE.getInt(STR_5_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final byte STR_5_BYTES_LATIN1_BYTE = STR_5_BYTES_LATIN1[4]; + private static final long STR_5_BYTES_UTF16_LONG = UNSAFE.getLong(STR_5_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final short STR_5_BYTES_UTF16_SHORT = UNSAFE.getShort(STR_5_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET + 8); + final static int NUMBERS = 8192; final byte[] bytes4 = new byte[NUMBERS * 4]; + final byte[] bytes5 = new byte[NUMBERS * 5]; final byte[] bytes8 = new byte[NUMBERS * 8]; + final byte[] bytes10 = new byte[NUMBERS * 10]; final int [] ints = new int [NUMBERS ]; final long[] longs = new long[NUMBERS ]; final char[] chars = new char[NUMBERS ]; final char[] chars4 = new char[NUMBERS * 4]; - final StringBuilder sb = new StringBuilder(NUMBERS * 4); - final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 8).append('\u4e2d'); + final char[] chars5 = new char[NUMBERS * 5]; + final StringBuilder sb = new StringBuilder(NUMBERS * 5); + final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 10).append('\u4e2d'); @Setup public void setup() { @@ -530,7 +542,7 @@ public void str4Arraycopy(Blackhole BH) { } /** - * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other putNull Benchmarks + * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other str4 Benchmarks */ @Benchmark public void str4UnsafePutInt(Blackhole BH) { @@ -552,7 +564,7 @@ public void str4StringBuilder(Blackhole BH) { for (int i = 0; i < NUMBERS; i++) { sb.append(STR_4); } - BH.consume(sb_utf16.length()); + BH.consume(sb.length()); } /** @@ -569,7 +581,7 @@ public void str4GetChars(Blackhole BH) { } /** - * Test the performance of putLong for comparison with other putNull_utf16 benchmarks + * Test the performance of putLong for comparison with other str4Utf16 benchmarks */ @Benchmark public void str4Utf16UnsafePutLong(Blackhole BH) { @@ -607,6 +619,99 @@ public void str4Utf16StringBuilder(Blackhole BH) { BH.consume(sb_utf16.length()); } + /** + * Test whether a constant byte[] with a length of 5 is MergeStored when arraycopy is called + */ + @Benchmark + public void str5Arraycopy(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + System.arraycopy(STR_5_BYTES_LATIN1, 0, bytes5, off, 5); + off += 5; + } + BH.consume(off); + } + + /** + * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other str5 Benchmarks + */ + @Benchmark + public void str5UnsafePutInt(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + UNSAFE.putInt(bytes5, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_LATIN1_INT); + UNSAFE.putByte(bytes5, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 4, STR_5_BYTES_LATIN1_BYTE); + off += 5; + } + BH.consume(off); + } + + /** + * Test whether StringBuilder is MergeStored when appending a constant String of length 5 + */ + @Benchmark + public void str5StringBuilder(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb.append(STR_5); + } + BH.consume(sb.length()); + } + + /** + * Test whether the constant String with a length of 5 calls the getChars method to mergestore + */ + @Benchmark + public void str5GetChars(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + STR_5.getChars(0, 5, chars5, off); + off += 5; + } + BH.consume(off); + } + + /** + * Test the performance of putLong for comparison with other str5Utf16 benchmarks + */ + @Benchmark + public void str5Utf16UnsafePutLong(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + UNSAFE.putLong(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_UTF16_LONG); + UNSAFE.putShort(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_5_BYTES_UTF16_SHORT); + off += 10; + } + BH.consume(off); + } + + /** + * Test whether the byte[] arraycopy with a length of 10 is MergeStore + */ + @Benchmark + public void str5Utf16ArrayCopy(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + System.arraycopy(STR_5_BYTES_UTF16, 0, bytes8, off, 10); + off += 10; + } + BH.consume(off); + } + + /** + * Test whether the UTF16 StringBuilder appends a constant String of length 5 to MergeStore + */ + @Benchmark + public void str5Utf16StringBuilder(Blackhole BH) { + sb_utf16.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb_utf16.append(STR_5); + } + BH.consume(sb_utf16.length()); + } + static void setIntB(byte[] array, int offset, int value) { array[offset ] = (byte) (value >> 24); array[offset + 1] = (byte) (value >> 16); From 4ab0c1edef075e76d4e10b2efe659a2f831ff285 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 11:11:27 +0800 Subject: [PATCH 4/9] bug fix for str5Utf16ArrayCopy --- test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index f3dc9f1c1d08b..09d98354cff90 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -693,7 +693,7 @@ public void str5Utf16UnsafePutLong(Blackhole BH) { public void str5Utf16ArrayCopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_5_BYTES_UTF16, 0, bytes8, off, 10); + System.arraycopy(STR_5_BYTES_UTF16, 0, bytes10, off, 10); off += 10; } BH.consume(off); From f1fb0dfcd1069f8faa624cccdb41046c35997457 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 12:10:19 +0800 Subject: [PATCH 5/9] bug fix & add str benchmark --- .../bench/vm/compiler/MergeStoreBench.java | 179 +++++++++++++++--- 1 file changed, 157 insertions(+), 22 deletions(-) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index 09d98354cff90..827c902e9f94f 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -68,19 +68,31 @@ public class MergeStoreBench { private static final long STR_5_BYTES_UTF16_LONG = UNSAFE.getLong(STR_5_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); private static final short STR_5_BYTES_UTF16_SHORT = UNSAFE.getShort(STR_5_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET + 8); + private static final String STR_7 = "truefalse"; + private static final byte[] STR_7_BYTES_LATIN1 = STR_7.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); + private static final byte[] STR_7_BYTES_UTF16 = STR_7.getBytes( + ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? StandardCharsets.UTF_16BE : StandardCharsets.UTF_16LE); + private static final int STR_7_BYTES_LATIN1_INT = UNSAFE.getInt(STR_7_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final short STR_7_BYTES_LATIN1_SHORT = UNSAFE.getShort(STR_7_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET + 4); + private static final byte STR_7_BYTES_LATIN1_BYTE = STR_7_BYTES_LATIN1[6]; + private static final long STR_7_BYTES_UTF16_LONG = UNSAFE.getLong(STR_7_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final int STR_7_BYTES_UTF16_INT = UNSAFE.getInt(STR_7_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET + 8); + private static final short STR_7_BYTES_UTF16_SHORT = UNSAFE.getShort(STR_7_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET + 12); + final static int NUMBERS = 8192; final byte[] bytes4 = new byte[NUMBERS * 4]; final byte[] bytes5 = new byte[NUMBERS * 5]; final byte[] bytes8 = new byte[NUMBERS * 8]; final byte[] bytes10 = new byte[NUMBERS * 10]; + final byte[] bytes14 = new byte[NUMBERS * 14]; final int [] ints = new int [NUMBERS ]; final long[] longs = new long[NUMBERS ]; final char[] chars = new char[NUMBERS ]; - final char[] chars4 = new char[NUMBERS * 4]; final char[] chars5 = new char[NUMBERS * 5]; - final StringBuilder sb = new StringBuilder(NUMBERS * 5); - final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 10).append('\u4e2d'); + final char[] chars7 = new char[NUMBERS * 7]; + final StringBuilder sb = new StringBuilder(NUMBERS * 7); + final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 14).append('\u4e2d'); @Setup public void setup() { @@ -519,11 +531,11 @@ public void putChars4S(Blackhole BH) { */ @Benchmark @SuppressWarnings("deprecation") - public void putNull_getBytes(Blackhole BH) { + public void str4GetBytes(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - STR_4.getBytes(0, 4, bytes4, off); - off += 4; + STR_4.getBytes(0, 4, bytes5, off); + off += 5; // disable auto vector } BH.consume(off); } @@ -535,8 +547,8 @@ public void putNull_getBytes(Blackhole BH) { public void str4Arraycopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_4_BYTES_LATIN1, 0, bytes4, off, 4); - off += 4; + System.arraycopy(STR_4_BYTES_LATIN1, 0, bytes5, off, 4); + off += 5; // disable auto vector } BH.consume(off); } @@ -545,11 +557,11 @@ public void str4Arraycopy(Blackhole BH) { * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other str4 Benchmarks */ @Benchmark - public void str4UnsafePutInt(Blackhole BH) { + public void str4UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putInt(bytes4, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_LATIN1_INT); - off += 4; + UNSAFE.putInt(bytes5, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_LATIN1_INT); + off += 5; // disable auto vector } BH.consume(off); } @@ -574,8 +586,8 @@ public void str4StringBuilder(Blackhole BH) { public void str4GetChars(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - STR_4.getChars(0, 4, chars4, off); - off += 4; + STR_4.getChars(0, 4, chars5, off); + off += 5; // disable auto vector } BH.consume(off); } @@ -584,11 +596,11 @@ public void str4GetChars(Blackhole BH) { * Test the performance of putLong for comparison with other str4Utf16 benchmarks */ @Benchmark - public void str4Utf16UnsafePutLong(Blackhole BH) { + public void str4Utf16UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putLong(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_UTF16_LONG); - off += 8; + UNSAFE.putLong(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_UTF16_LONG); + off += 10; // disable auto vector } BH.consume(off); } @@ -600,8 +612,8 @@ public void str4Utf16UnsafePutLong(Blackhole BH) { public void str4Utf16ArrayCopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_4_BYTES_UTF16, 0, bytes8, off, 8); - off += 8; + System.arraycopy(STR_4_BYTES_UTF16, 0, bytes10, off, 8); + off += 10; } BH.consume(off); } @@ -619,6 +631,20 @@ public void str4Utf16StringBuilder(Blackhole BH) { BH.consume(sb_utf16.length()); } + /** + * Test whether a constant String of length 5 is MergeStored when calling getBytes + */ + @Benchmark + @SuppressWarnings("deprecation") + public void str5GetBytes(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + STR_5.getBytes(0, 4, bytes5, off); + off += 5; + } + BH.consume(off); + } + /** * Test whether a constant byte[] with a length of 5 is MergeStored when arraycopy is called */ @@ -636,7 +662,7 @@ public void str5Arraycopy(Blackhole BH) { * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other str5 Benchmarks */ @Benchmark - public void str5UnsafePutInt(Blackhole BH) { + public void str5UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { UNSAFE.putInt(bytes5, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_LATIN1_INT); @@ -676,11 +702,11 @@ public void str5GetChars(Blackhole BH) { * Test the performance of putLong for comparison with other str5Utf16 benchmarks */ @Benchmark - public void str5Utf16UnsafePutLong(Blackhole BH) { + public void str5Utf16UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putLong(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_UTF16_LONG); - UNSAFE.putShort(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_5_BYTES_UTF16_SHORT); + UNSAFE.putLong(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_UTF16_LONG); + UNSAFE.putShort(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_5_BYTES_UTF16_SHORT); off += 10; } BH.consume(off); @@ -712,6 +738,115 @@ public void str5Utf16StringBuilder(Blackhole BH) { BH.consume(sb_utf16.length()); } + /** + * Test whether a constant String of length 5 is MergeStored when calling getBytes + */ + @Benchmark + @SuppressWarnings("deprecation") + public void str7GetBytes(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + STR_7.getBytes(0, 7, bytes8, off); + off += 7; + } + BH.consume(off); + } + + /** + * Test whether a constant byte[] with a length of 7 is MergeStored when arraycopy is called + */ + @Benchmark + public void str7Arraycopy(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + System.arraycopy(STR_7_BYTES_LATIN1, 0, bytes8, off, 7); + off += 7; + } + BH.consume(off); + } + + /** + * Test the performance of Unsafe.putInt, used as a benchmark for comparison with other str7 Benchmarks + */ + @Benchmark + public void str7UnsafePut(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + UNSAFE.putInt(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_7_BYTES_LATIN1_INT); + UNSAFE.putShort(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 4, STR_7_BYTES_LATIN1_SHORT); + UNSAFE.putByte(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 6, STR_7_BYTES_LATIN1_BYTE); + off += 7; + } + BH.consume(off); + } + + /** + * Test whether StringBuilder is MergeStored when appending a constant String of length 7 + */ + @Benchmark + public void str7StringBuilder(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb.append(STR_7); + } + BH.consume(sb.length()); + } + + /** + * Test whether the constant String with a length of 7 calls the getChars method to mergestore + */ + @Benchmark + public void str7GetChars(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + STR_7.getChars(0, 7, chars7, off); + off += 7; + } + BH.consume(off); + } + + /** + * Test the performance of putLong for comparison with other str7Utf16 benchmarks + */ + @Benchmark + public void str7Utf16UnsafePut(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + UNSAFE.putLong(bytes14, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_7_BYTES_UTF16_LONG); + UNSAFE.putInt(bytes14, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_7_BYTES_UTF16_INT); + UNSAFE.putShort(bytes14, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 12, STR_7_BYTES_UTF16_SHORT); + off += 14; + } + BH.consume(off); + } + + /** + * Test whether the byte[] arraycopy with a length of 14 is MergeStore + */ + @Benchmark + public void str7Utf16ArrayCopy(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + System.arraycopy(STR_7_BYTES_UTF16, 0, bytes14, off, 14); + off += 14; + } + BH.consume(off); + } + + /** + * Test whether the UTF16 StringBuilder appends a constant String of length 7 to MergeStore + */ + @Benchmark + public void str7Utf16StringBuilder(Blackhole BH) { + sb_utf16.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb_utf16.append(STR_7); + } + BH.consume(sb_utf16.length()); + } + static void setIntB(byte[] array, int offset, int value) { array[offset ] = (byte) (value >> 24); array[offset + 1] = (byte) (value >> 16); From a5eb3b98ece8cf1aa6eaa3d1287148e1b0510f4b Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 12:54:48 +0800 Subject: [PATCH 6/9] disable auto vector & more benchmark --- .../bench/vm/compiler/MergeStoreBench.java | 189 ++++++++++++++---- 1 file changed, 155 insertions(+), 34 deletions(-) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index 827c902e9f94f..59a39b930ca14 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -58,6 +58,10 @@ public class MergeStoreBench { ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? StandardCharsets.UTF_16BE : StandardCharsets.UTF_16LE); private static final int STR_4_BYTES_LATIN1_INT = UNSAFE.getInt(STR_4_BYTES_LATIN1, Unsafe.ARRAY_BYTE_BASE_OFFSET); private static final long STR_4_BYTES_UTF16_LONG = UNSAFE.getLong(STR_4_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); + private static final byte STR_4_BYTES_LATIN1_BYTE_0 = STR_4_BYTES_LATIN1[0]; + private static final byte STR_4_BYTES_LATIN1_BYTE_1 = STR_4_BYTES_LATIN1[1]; + private static final byte STR_4_BYTES_LATIN1_BYTE_2 = STR_4_BYTES_LATIN1[2]; + private static final byte STR_4_BYTES_LATIN1_BYTE_3 = STR_4_BYTES_LATIN1[3]; private static final String STR_5 = "false"; private static final byte[] STR_5_BYTES_LATIN1 = STR_5.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); @@ -67,6 +71,11 @@ public class MergeStoreBench { private static final byte STR_5_BYTES_LATIN1_BYTE = STR_5_BYTES_LATIN1[4]; private static final long STR_5_BYTES_UTF16_LONG = UNSAFE.getLong(STR_5_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); private static final short STR_5_BYTES_UTF16_SHORT = UNSAFE.getShort(STR_5_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET + 8); + private static final byte STR_5_BYTES_LATIN1_BYTE_0 = STR_5_BYTES_LATIN1[0]; + private static final byte STR_5_BYTES_LATIN1_BYTE_1 = STR_5_BYTES_LATIN1[1]; + private static final byte STR_5_BYTES_LATIN1_BYTE_2 = STR_5_BYTES_LATIN1[2]; + private static final byte STR_5_BYTES_LATIN1_BYTE_3 = STR_5_BYTES_LATIN1[3]; + private static final byte STR_5_BYTES_LATIN1_BYTE_4 = STR_5_BYTES_LATIN1[4]; private static final String STR_7 = "truefalse"; private static final byte[] STR_7_BYTES_LATIN1 = STR_7.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); @@ -78,6 +87,14 @@ public class MergeStoreBench { private static final long STR_7_BYTES_UTF16_LONG = UNSAFE.getLong(STR_7_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET); private static final int STR_7_BYTES_UTF16_INT = UNSAFE.getInt(STR_7_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET + 8); private static final short STR_7_BYTES_UTF16_SHORT = UNSAFE.getShort(STR_7_BYTES_UTF16, Unsafe.ARRAY_BYTE_BASE_OFFSET + 12); + private static final byte STR_7_BYTES_LATIN1_BYTE_0 = STR_7_BYTES_LATIN1[0]; + private static final byte STR_7_BYTES_LATIN1_BYTE_1 = STR_7_BYTES_LATIN1[1]; + private static final byte STR_7_BYTES_LATIN1_BYTE_2 = STR_7_BYTES_LATIN1[2]; + private static final byte STR_7_BYTES_LATIN1_BYTE_3 = STR_7_BYTES_LATIN1[3]; + private static final byte STR_7_BYTES_LATIN1_BYTE_4 = STR_7_BYTES_LATIN1[4]; + private static final byte STR_7_BYTES_LATIN1_BYTE_5 = STR_7_BYTES_LATIN1[5]; + private static final byte STR_7_BYTES_LATIN1_BYTE_6 = STR_7_BYTES_LATIN1[6]; + final static int NUMBERS = 8192; @@ -85,12 +102,12 @@ public class MergeStoreBench { final byte[] bytes5 = new byte[NUMBERS * 5]; final byte[] bytes8 = new byte[NUMBERS * 8]; final byte[] bytes10 = new byte[NUMBERS * 10]; - final byte[] bytes14 = new byte[NUMBERS * 14]; + final byte[] bytes16 = new byte[NUMBERS * 16]; final int [] ints = new int [NUMBERS ]; final long[] longs = new long[NUMBERS ]; final char[] chars = new char[NUMBERS ]; final char[] chars5 = new char[NUMBERS * 5]; - final char[] chars7 = new char[NUMBERS * 7]; + final char[] chars10 = new char[NUMBERS * 10]; final StringBuilder sb = new StringBuilder(NUMBERS * 7); final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 14).append('\u4e2d'); @@ -540,6 +557,22 @@ public void str4GetBytes(Blackhole BH) { BH.consume(off); } + /** + * Test the performance of array set 4 constant byte, used as a benchmark for comparison with other str4 Benchmarks + */ + @Benchmark + public void str4ArraySetConst(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + bytes5[off ] = STR_4_BYTES_LATIN1_BYTE_0; + bytes5[off + 1] = STR_4_BYTES_LATIN1_BYTE_1; + bytes5[off + 2] = STR_4_BYTES_LATIN1_BYTE_2; + bytes5[off + 3] = STR_4_BYTES_LATIN1_BYTE_3; + off += 5; // disable auto vector + } + BH.consume(off); + } + /** * Test whether a constant byte[] with a length of 4 is MergeStored when arraycopy is called */ @@ -592,6 +625,22 @@ public void str4GetChars(Blackhole BH) { BH.consume(off); } + /** + * Test the performance of array set 4 constant byte, used as a benchmark for comparison with other str4 Benchmarks + */ + @Benchmark + public void str4Utf16ArraySetConst(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + chars5[off ] = (char) STR_4_BYTES_LATIN1_BYTE_0; + chars5[off + 1] = (char) STR_4_BYTES_LATIN1_BYTE_1; + chars5[off + 2] = (char) STR_4_BYTES_LATIN1_BYTE_2; + chars5[off + 3] = (char) STR_4_BYTES_LATIN1_BYTE_3; + off += 5; // disable auto vector + } + BH.consume(off); + } + /** * Test the performance of putLong for comparison with other str4Utf16 benchmarks */ @@ -599,8 +648,8 @@ public void str4GetChars(Blackhole BH) { public void str4Utf16UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putLong(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_UTF16_LONG); - off += 10; // disable auto vector + UNSAFE.putLong(bytes16, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_4_BYTES_UTF16_LONG); + off += 9; // disable auto vector } BH.consume(off); } @@ -612,8 +661,8 @@ public void str4Utf16UnsafePut(Blackhole BH) { public void str4Utf16ArrayCopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_4_BYTES_UTF16, 0, bytes10, off, 8); - off += 10; + System.arraycopy(STR_4_BYTES_UTF16, 0, bytes16, off, 8); + off += 9; // disable auto vector } BH.consume(off); } @@ -639,8 +688,25 @@ public void str4Utf16StringBuilder(Blackhole BH) { public void str5GetBytes(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - STR_5.getBytes(0, 4, bytes5, off); - off += 5; + STR_5.getBytes(0, 4, bytes8, off); + off += 6; // disable auto vector + } + BH.consume(off); + } + + /** + * Test the performance of array set 5 constant byte, used as a benchmark for comparison with other str5 Benchmarks + */ + @Benchmark + public void str5ArraySetConst(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + bytes8[off ] = STR_7_BYTES_LATIN1_BYTE_0; + bytes8[off + 1] = STR_7_BYTES_LATIN1_BYTE_1; + bytes8[off + 2] = STR_7_BYTES_LATIN1_BYTE_2; + bytes8[off + 3] = STR_7_BYTES_LATIN1_BYTE_3; + bytes8[off + 4] = STR_7_BYTES_LATIN1_BYTE_4; + off += 6; // disable auto vector } BH.consume(off); } @@ -652,8 +718,8 @@ public void str5GetBytes(Blackhole BH) { public void str5Arraycopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_5_BYTES_LATIN1, 0, bytes5, off, 5); - off += 5; + System.arraycopy(STR_5_BYTES_LATIN1, 0, bytes8, off, 5); + off += 6; // disable auto vector } BH.consume(off); } @@ -667,7 +733,7 @@ public void str5UnsafePut(Blackhole BH) { for (int i = 0; i < NUMBERS; i++) { UNSAFE.putInt(bytes5, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_LATIN1_INT); UNSAFE.putByte(bytes5, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 4, STR_5_BYTES_LATIN1_BYTE); - off += 5; + off += 6; // disable auto vector } BH.consume(off); } @@ -692,8 +758,8 @@ public void str5StringBuilder(Blackhole BH) { public void str5GetChars(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - STR_5.getChars(0, 5, chars5, off); - off += 5; + STR_5.getChars(0, 5, chars10, off); + off += 6; // disable auto vector } BH.consume(off); } @@ -705,9 +771,26 @@ public void str5GetChars(Blackhole BH) { public void str5Utf16UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putLong(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_UTF16_LONG); - UNSAFE.putShort(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_5_BYTES_UTF16_SHORT); - off += 10; + UNSAFE.putLong(bytes16, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_5_BYTES_UTF16_LONG); + UNSAFE.putShort(bytes16, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_5_BYTES_UTF16_SHORT); + off += 11; // disable auto vector + } + BH.consume(off); + } + + /** + * Test the performance of array set 5 constant char, used as a benchmark for comparison with other str5 Benchmarks + */ + @Benchmark + public void str5Utf16ArraySetConst(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + chars10[off ] = (char) STR_5_BYTES_LATIN1_BYTE_0; + chars10[off + 1] = (char) STR_5_BYTES_LATIN1_BYTE_1; + chars10[off + 2] = (char) STR_5_BYTES_LATIN1_BYTE_2; + chars10[off + 3] = (char) STR_5_BYTES_LATIN1_BYTE_3; + chars10[off + 4] = (char) STR_5_BYTES_LATIN1_BYTE_4; + off += 6; // disable auto vector } BH.consume(off); } @@ -719,8 +802,8 @@ public void str5Utf16UnsafePut(Blackhole BH) { public void str5Utf16ArrayCopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_5_BYTES_UTF16, 0, bytes10, off, 10); - off += 10; + System.arraycopy(STR_5_BYTES_UTF16, 0, bytes16, off, 10); + off += 11; // disable auto vector } BH.consume(off); } @@ -746,8 +829,27 @@ public void str5Utf16StringBuilder(Blackhole BH) { public void str7GetBytes(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - STR_7.getBytes(0, 7, bytes8, off); - off += 7; + STR_7.getBytes(0, 7, bytes10, off); + off += 9; // disable auto vector + } + BH.consume(off); + } + + /** + * Test the performance of array set 7 constant byte, used as a benchmark for comparison with other str7 Benchmarks + */ + @Benchmark + public void str7ArraySetConst(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + bytes10[off ] = STR_7_BYTES_LATIN1_BYTE_0; + bytes10[off + 1] = STR_7_BYTES_LATIN1_BYTE_1; + bytes10[off + 2] = STR_7_BYTES_LATIN1_BYTE_2; + bytes10[off + 3] = STR_7_BYTES_LATIN1_BYTE_3; + bytes10[off + 4] = STR_7_BYTES_LATIN1_BYTE_4; + bytes10[off + 5] = STR_7_BYTES_LATIN1_BYTE_5; + bytes10[off + 6] = STR_7_BYTES_LATIN1_BYTE_6; + off += 9; // disable auto vector } BH.consume(off); } @@ -759,8 +861,8 @@ public void str7GetBytes(Blackhole BH) { public void str7Arraycopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_7_BYTES_LATIN1, 0, bytes8, off, 7); - off += 7; + System.arraycopy(STR_7_BYTES_LATIN1, 0, bytes10, off, 7); + off += 9; // disable auto vector } BH.consume(off); } @@ -772,10 +874,10 @@ public void str7Arraycopy(Blackhole BH) { public void str7UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putInt(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_7_BYTES_LATIN1_INT); - UNSAFE.putShort(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 4, STR_7_BYTES_LATIN1_SHORT); - UNSAFE.putByte(bytes8, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 6, STR_7_BYTES_LATIN1_BYTE); - off += 7; + UNSAFE.putInt(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_7_BYTES_LATIN1_INT); + UNSAFE.putShort(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 4, STR_7_BYTES_LATIN1_SHORT); + UNSAFE.putByte(bytes10, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 6, STR_7_BYTES_LATIN1_BYTE); + off += 9; // disable auto vector } BH.consume(off); } @@ -800,8 +902,27 @@ public void str7StringBuilder(Blackhole BH) { public void str7GetChars(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - STR_7.getChars(0, 7, chars7, off); - off += 7; + STR_7.getChars(0, 7, chars10, off); + off += 9; // disable auto vector + } + BH.consume(off); + } + + /** + * Test the performance of array set 7 constant char, used as a benchmark for comparison with other str7 Benchmarks + */ + @Benchmark + public void str7Utf16ArraySetConst(Blackhole BH) { + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + chars10[off ] = (char) STR_7_BYTES_LATIN1_BYTE_0; + chars10[off + 1] = (char) STR_7_BYTES_LATIN1_BYTE_1; + chars10[off + 2] = (char) STR_7_BYTES_LATIN1_BYTE_2; + chars10[off + 3] = (char) STR_7_BYTES_LATIN1_BYTE_3; + chars10[off + 4] = (char) STR_7_BYTES_LATIN1_BYTE_4; + chars10[off + 5] = (char) STR_7_BYTES_LATIN1_BYTE_5; + chars10[off + 6] = (char) STR_7_BYTES_LATIN1_BYTE_6; + off += 9; // disable auto vector } BH.consume(off); } @@ -813,10 +934,10 @@ public void str7GetChars(Blackhole BH) { public void str7Utf16UnsafePut(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - UNSAFE.putLong(bytes14, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_7_BYTES_UTF16_LONG); - UNSAFE.putInt(bytes14, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_7_BYTES_UTF16_INT); - UNSAFE.putShort(bytes14, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 12, STR_7_BYTES_UTF16_SHORT); - off += 14; + UNSAFE.putLong(bytes16, Unsafe.ARRAY_BYTE_BASE_OFFSET + off, STR_7_BYTES_UTF16_LONG); + UNSAFE.putInt(bytes16, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 8, STR_7_BYTES_UTF16_INT); + UNSAFE.putShort(bytes16, Unsafe.ARRAY_BYTE_BASE_OFFSET + off + 12, STR_7_BYTES_UTF16_SHORT); + off += 15; // disable auto vector } BH.consume(off); } @@ -828,8 +949,8 @@ public void str7Utf16UnsafePut(Blackhole BH) { public void str7Utf16ArrayCopy(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - System.arraycopy(STR_7_BYTES_UTF16, 0, bytes14, off, 14); - off += 14; + System.arraycopy(STR_7_BYTES_UTF16, 0, bytes16, off, 14); + off += 15; // disable auto vector } BH.consume(off); } From c4d3ffd2ca1e2e459340196e03f7e28516f337ba Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 13:26:53 +0800 Subject: [PATCH 7/9] bug fix for str5ArraySetConst --- .../org/openjdk/bench/vm/compiler/MergeStoreBench.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index 59a39b930ca14..e726986ea86a9 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -701,11 +701,11 @@ public void str5GetBytes(Blackhole BH) { public void str5ArraySetConst(Blackhole BH) { int off = 0; for (int i = 0; i < NUMBERS; i++) { - bytes8[off ] = STR_7_BYTES_LATIN1_BYTE_0; - bytes8[off + 1] = STR_7_BYTES_LATIN1_BYTE_1; - bytes8[off + 2] = STR_7_BYTES_LATIN1_BYTE_2; - bytes8[off + 3] = STR_7_BYTES_LATIN1_BYTE_3; - bytes8[off + 4] = STR_7_BYTES_LATIN1_BYTE_4; + bytes8[off ] = STR_5_BYTES_LATIN1_BYTE_0; + bytes8[off + 1] = STR_5_BYTES_LATIN1_BYTE_1; + bytes8[off + 2] = STR_5_BYTES_LATIN1_BYTE_2; + bytes8[off + 3] = STR_5_BYTES_LATIN1_BYTE_3; + bytes8[off + 4] = STR_5_BYTES_LATIN1_BYTE_4; off += 6; // disable auto vector } BH.consume(off); From 322624ebd250dfea7921a0f0998dad995aa183a5 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 13:47:21 +0800 Subject: [PATCH 8/9] appendChar --- .../bench/vm/compiler/MergeStoreBench.java | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index e726986ea86a9..5b4a86d9cd868 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -612,6 +612,22 @@ public void str4StringBuilder(Blackhole BH) { BH.consume(sb.length()); } + /** + * Test whether StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str4StringBuilderAppendChar(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb.append((char) STR_4_BYTES_LATIN1_BYTE_0); + sb.append((char) STR_4_BYTES_LATIN1_BYTE_1); + sb.append((char) STR_4_BYTES_LATIN1_BYTE_2); + sb.append((char) STR_4_BYTES_LATIN1_BYTE_3); + } + BH.consume(sb.length()); + } + /** * Test whether the constant String with a length of 4 calls the getChars method to mergestore */ @@ -680,6 +696,22 @@ public void str4Utf16StringBuilder(Blackhole BH) { BH.consume(sb_utf16.length()); } + /** + * Test whether the UTF16 StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str4Utf16StringBuilderAppendChar(Blackhole BH) { + sb_utf16.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_0); + sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_1); + sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_2); + sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_3); + } + BH.consume(sb_utf16.length()); + } + /** * Test whether a constant String of length 5 is MergeStored when calling getBytes */ @@ -751,6 +783,23 @@ public void str5StringBuilder(Blackhole BH) { BH.consume(sb.length()); } + /** + * Test whether StringBuilder is MergeStored when appending 5 constant characters + */ + @Benchmark + public void str5StringBuilderAppendChar(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb.append((char) STR_5_BYTES_LATIN1_BYTE_0); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_1); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_2); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_3); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_4); + } + BH.consume(sb.length()); + } + /** * Test whether the constant String with a length of 5 calls the getChars method to mergestore */ @@ -821,6 +870,23 @@ public void str5Utf16StringBuilder(Blackhole BH) { BH.consume(sb_utf16.length()); } + /** + * Test whether the UTF16 StringBuilder is MergeStored when appending 5 constant characters + */ + @Benchmark + public void str5Utf16StringBuilderAppendChar(Blackhole BH) { + sb_utf16.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_0); + sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_1); + sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_2); + sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_3); + sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_4); + } + BH.consume(sb_utf16.length()); + } + /** * Test whether a constant String of length 5 is MergeStored when calling getBytes */ @@ -895,6 +961,25 @@ public void str7StringBuilder(Blackhole BH) { BH.consume(sb.length()); } + /** + * Test whether StringBuilder is MergeStored when appending 7 constant characters + */ + @Benchmark + public void str7StringBuilderAppendChar(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb.append((char) STR_7_BYTES_LATIN1_BYTE_0); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_1); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_2); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_3); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_4); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_5); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_6); + } + BH.consume(sb.length()); + } + /** * Test whether the constant String with a length of 7 calls the getChars method to mergestore */ @@ -968,6 +1053,25 @@ public void str7Utf16StringBuilder(Blackhole BH) { BH.consume(sb_utf16.length()); } + /** + * Test whether the UTF16 StringBuilder is MergeStored when appending 7 constant characters + */ + @Benchmark + public void str7Utf16StringBuilderAppendChar(Blackhole BH) { + sb_utf16.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_0); + sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_1); + sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_2); + sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_3); + sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_4); + sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_5); + sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_6); + } + BH.consume(sb_utf16.length()); + } + static void setIntB(byte[] array, int offset, int value) { array[offset ] = (byte) (value >> 24); array[offset + 1] = (byte) (value >> 16); From cd1d8fb3b137a741446c894d1893e7180535ce8f Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 29 Mar 2025 15:22:44 +0800 Subject: [PATCH 9/9] add StringBuilderUnsafePut --- .../bench/vm/compiler/MergeStoreBench.java | 279 +++++++++++++++--- 1 file changed, 245 insertions(+), 34 deletions(-) diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java index 5b4a86d9cd868..ddedc7ba5fb9d 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStoreBench.java @@ -52,6 +52,16 @@ public class MergeStoreBench { CHAR_L = MethodHandles.byteArrayViewVarHandle(char[].class, ByteOrder.LITTLE_ENDIAN), CHAR_B = MethodHandles.byteArrayViewVarHandle(char[].class, ByteOrder.BIG_ENDIAN); + final static long FIELD_OFFSET_STR_BUILDER_VALUE; + final static long FIELD_OFFSET_STR_BUILDER_CODER; + final static long FIELD_OFFSET_STR_BUILDER_COUNT; + static { + Class clazz = StringBuilder.class.getSuperclass(); + FIELD_OFFSET_STR_BUILDER_VALUE = UNSAFE.objectFieldOffset(clazz, "value"); + FIELD_OFFSET_STR_BUILDER_CODER = UNSAFE.objectFieldOffset(clazz, "coder"); + FIELD_OFFSET_STR_BUILDER_COUNT = UNSAFE.objectFieldOffset(clazz, "count"); + } + private static final String STR_4 = "null"; private static final byte[] STR_4_BYTES_LATIN1 = STR_4.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); private static final byte[] STR_4_BYTES_UTF16 = STR_4.getBytes( @@ -108,8 +118,8 @@ public class MergeStoreBench { final char[] chars = new char[NUMBERS ]; final char[] chars5 = new char[NUMBERS * 5]; final char[] chars10 = new char[NUMBERS * 10]; - final StringBuilder sb = new StringBuilder(NUMBERS * 7); - final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 14).append('\u4e2d'); + final StringBuilder sb = new StringBuilder(NUMBERS * 10); + final StringBuilder sb_utf16 = new StringBuilder(NUMBERS * 10).append('\u4e2d'); @Setup public void setup() { @@ -628,6 +638,47 @@ public void str4StringBuilderAppendChar(Blackhole BH) { BH.consume(sb.length()); } + private static void str4AppendUnsafePut(StringBuilder sb, char c0, char c1, char c2, char c3) { + byte[] value = (byte[]) UNSAFE.getReference(sb, FIELD_OFFSET_STR_BUILDER_VALUE); + byte coder = UNSAFE.getByte(sb, FIELD_OFFSET_STR_BUILDER_CODER); + int count = UNSAFE.getInt(sb, FIELD_OFFSET_STR_BUILDER_COUNT); + if (count + 4 >= (value.length >> coder)) { + sb.ensureCapacity(count + 4); + value = (byte[]) UNSAFE.getReference(sb, FIELD_OFFSET_STR_BUILDER_VALUE); + } + if (coder == 0) { + value[count ] = (byte) c0; + value[count + 1] = (byte) c1; + value[count + 2] = (byte) c2; + value[count + 3] = (byte) c3; + } else { + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + ((long) count << 1); + UNSAFE.putChar(value, address , c0); + UNSAFE.putChar(value, address + 2, c1); + UNSAFE.putChar(value, address + 4, c2); + UNSAFE.putChar(value, address + 6, c3); + } + UNSAFE.putInt(sb, FIELD_OFFSET_STR_BUILDER_COUNT, count + 5); // disable auto vector + } + + /** + * Test whether StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str4StringBuilderUnsafePut(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + str4AppendUnsafePut( + sb, + (char) STR_4_BYTES_LATIN1_BYTE_0, + (char) STR_4_BYTES_LATIN1_BYTE_1, + (char) STR_4_BYTES_LATIN1_BYTE_2, + (char) STR_4_BYTES_LATIN1_BYTE_3); + } + BH.consume(sb.length()); + } + /** * Test whether the constant String with a length of 4 calls the getChars method to mergestore */ @@ -688,12 +739,13 @@ public void str4Utf16ArrayCopy(Blackhole BH) { */ @Benchmark public void str4Utf16StringBuilder(Blackhole BH) { - sb_utf16.setLength(0); + var sb = sb_utf16; + sb.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb_utf16.append(STR_4); + sb.append(STR_4); } - BH.consume(sb_utf16.length()); + BH.consume(sb.length()); } /** @@ -701,15 +753,35 @@ public void str4Utf16StringBuilder(Blackhole BH) { */ @Benchmark public void str4Utf16StringBuilderAppendChar(Blackhole BH) { - sb_utf16.setLength(0); + var sb = sb_utf16; + sb.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_0); - sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_1); - sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_2); - sb_utf16.append((char) STR_4_BYTES_LATIN1_BYTE_3); + sb.append((char) STR_4_BYTES_LATIN1_BYTE_0); + sb.append((char) STR_4_BYTES_LATIN1_BYTE_1); + sb.append((char) STR_4_BYTES_LATIN1_BYTE_2); + sb.append((char) STR_4_BYTES_LATIN1_BYTE_3); } - BH.consume(sb_utf16.length()); + BH.consume(sb.length()); + } + + /** + * Test whether StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str4Utf16StringBuilderUnsafePut(Blackhole BH) { + StringBuilder sb = sb_utf16; + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + str4AppendUnsafePut( + sb, + (char) STR_4_BYTES_LATIN1_BYTE_0, + (char) STR_4_BYTES_LATIN1_BYTE_1, + (char) STR_4_BYTES_LATIN1_BYTE_2, + (char) STR_4_BYTES_LATIN1_BYTE_3); + } + BH.consume(sb.length()); } /** @@ -800,6 +872,50 @@ public void str5StringBuilderAppendChar(Blackhole BH) { BH.consume(sb.length()); } + private static void str5AppendUnsafePut(StringBuilder sb, char c0, char c1, char c2, char c3, char c4) { + byte[] value = (byte[]) UNSAFE.getReference(sb, FIELD_OFFSET_STR_BUILDER_VALUE); + byte coder = UNSAFE.getByte(sb, FIELD_OFFSET_STR_BUILDER_CODER); + int count = UNSAFE.getInt(sb, FIELD_OFFSET_STR_BUILDER_COUNT); + if (count + 4 >= (value.length >> coder)) { + sb.ensureCapacity(count + 4); + value = (byte[]) UNSAFE.getReference(sb, FIELD_OFFSET_STR_BUILDER_VALUE); + } + if (coder == 0) { + value[count ] = (byte) c0; + value[count + 1] = (byte) c1; + value[count + 2] = (byte) c2; + value[count + 3] = (byte) c3; + value[count + 4] = (byte) c4; + } else { + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + ((long) count << 1); + UNSAFE.putChar(value, address , c0); + UNSAFE.putChar(value, address + 2, c1); + UNSAFE.putChar(value, address + 4, c2); + UNSAFE.putChar(value, address + 6, c3); + UNSAFE.putChar(value, address + 8, c4); + } + UNSAFE.putInt(sb, FIELD_OFFSET_STR_BUILDER_COUNT, count + 6); // disable auto vector + } + + /** + * Test whether StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str5StringBuilderUnsafePut(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + str5AppendUnsafePut( + sb, + (char) STR_5_BYTES_LATIN1_BYTE_0, + (char) STR_5_BYTES_LATIN1_BYTE_1, + (char) STR_5_BYTES_LATIN1_BYTE_2, + (char) STR_5_BYTES_LATIN1_BYTE_3, + (char) STR_5_BYTES_LATIN1_BYTE_4); + } + BH.consume(sb.length()); + } + /** * Test whether the constant String with a length of 5 calls the getChars method to mergestore */ @@ -862,12 +978,13 @@ public void str5Utf16ArrayCopy(Blackhole BH) { */ @Benchmark public void str5Utf16StringBuilder(Blackhole BH) { - sb_utf16.setLength(0); + StringBuilder sb = sb_utf16; + sb.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb_utf16.append(STR_5); + sb.append(STR_5); } - BH.consume(sb_utf16.length()); + BH.consume(sb.length()); } /** @@ -875,16 +992,36 @@ public void str5Utf16StringBuilder(Blackhole BH) { */ @Benchmark public void str5Utf16StringBuilderAppendChar(Blackhole BH) { - sb_utf16.setLength(0); + StringBuilder sb = sb_utf16; + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + sb.append((char) STR_5_BYTES_LATIN1_BYTE_0); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_1); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_2); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_3); + sb.append((char) STR_5_BYTES_LATIN1_BYTE_4); + } + BH.consume(sb.length()); + } + + /** + * Test whether StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str5Utf16StringBuilderUnsafePut(Blackhole BH) { + sb.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_0); - sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_1); - sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_2); - sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_3); - sb_utf16.append((char) STR_5_BYTES_LATIN1_BYTE_4); + str5AppendUnsafePut( + sb, + (char) STR_5_BYTES_LATIN1_BYTE_0, + (char) STR_5_BYTES_LATIN1_BYTE_1, + (char) STR_5_BYTES_LATIN1_BYTE_2, + (char) STR_5_BYTES_LATIN1_BYTE_3, + (char) STR_5_BYTES_LATIN1_BYTE_4); } - BH.consume(sb_utf16.length()); + BH.consume(sb.length()); } /** @@ -980,6 +1117,56 @@ public void str7StringBuilderAppendChar(Blackhole BH) { BH.consume(sb.length()); } + private static void str7AppendUnsafePut(StringBuilder sb, char c0, char c1, char c2, char c3, char c4, char c5, char c6) { + byte[] value = (byte[]) UNSAFE.getReference(sb, FIELD_OFFSET_STR_BUILDER_VALUE); + byte coder = UNSAFE.getByte(sb, FIELD_OFFSET_STR_BUILDER_CODER); + int count = UNSAFE.getInt(sb, FIELD_OFFSET_STR_BUILDER_COUNT); + if (count + 4 >= (value.length >> coder)) { + sb.ensureCapacity(count + 4); + value = (byte[]) UNSAFE.getReference(sb, FIELD_OFFSET_STR_BUILDER_VALUE); + } + if (coder == 0) { + value[count ] = (byte) c0; + value[count + 1] = (byte) c1; + value[count + 2] = (byte) c2; + value[count + 3] = (byte) c3; + value[count + 4] = (byte) c4; + value[count + 5] = (byte) c5; + value[count + 6] = (byte) c6; + } else { + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + ((long) count << 1); + UNSAFE.putChar(value, address , c0); + UNSAFE.putChar(value, address + 2, c1); + UNSAFE.putChar(value, address + 4, c2); + UNSAFE.putChar(value, address + 6, c3); + UNSAFE.putChar(value, address + 8, c4); + UNSAFE.putChar(value, address + 10, c5); + UNSAFE.putChar(value, address + 12, c6); + } + UNSAFE.putInt(sb, FIELD_OFFSET_STR_BUILDER_COUNT, count + 8); // disable auto vector + } + + /** + * Test whether StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str7StringBuilderUnsafePut(Blackhole BH) { + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + str7AppendUnsafePut( + sb, + (char) STR_7_BYTES_LATIN1_BYTE_0, + (char) STR_7_BYTES_LATIN1_BYTE_1, + (char) STR_7_BYTES_LATIN1_BYTE_2, + (char) STR_7_BYTES_LATIN1_BYTE_3, + (char) STR_7_BYTES_LATIN1_BYTE_4, + (char) STR_7_BYTES_LATIN1_BYTE_5, + (char) STR_7_BYTES_LATIN1_BYTE_6); + } + BH.consume(sb.length()); + } + /** * Test whether the constant String with a length of 7 calls the getChars method to mergestore */ @@ -1045,12 +1232,13 @@ public void str7Utf16ArrayCopy(Blackhole BH) { */ @Benchmark public void str7Utf16StringBuilder(Blackhole BH) { - sb_utf16.setLength(0); + var sb = sb_utf16; + sb.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb_utf16.append(STR_7); + sb.append(STR_7); } - BH.consume(sb_utf16.length()); + BH.consume(sb.length()); } /** @@ -1058,18 +1246,41 @@ public void str7Utf16StringBuilder(Blackhole BH) { */ @Benchmark public void str7Utf16StringBuilderAppendChar(Blackhole BH) { - sb_utf16.setLength(0); + var sb = sb_utf16; + sb.setLength(0); int off = 0; for (int i = 0; i < NUMBERS; i++) { - sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_0); - sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_1); - sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_2); - sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_3); - sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_4); - sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_5); - sb_utf16.append((char) STR_7_BYTES_LATIN1_BYTE_6); - } - BH.consume(sb_utf16.length()); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_0); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_1); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_2); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_3); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_4); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_5); + sb.append((char) STR_7_BYTES_LATIN1_BYTE_6); + } + BH.consume(sb.length()); + } + + /** + * Test whether StringBuilder is MergeStored when appending 4 constant characters + */ + @Benchmark + public void str7Utf16StringBuilderUnsafePut(Blackhole BH) { + var sb = sb_utf16; + sb.setLength(0); + int off = 0; + for (int i = 0; i < NUMBERS; i++) { + str7AppendUnsafePut( + sb, + (char) STR_7_BYTES_LATIN1_BYTE_0, + (char) STR_7_BYTES_LATIN1_BYTE_1, + (char) STR_7_BYTES_LATIN1_BYTE_2, + (char) STR_7_BYTES_LATIN1_BYTE_3, + (char) STR_7_BYTES_LATIN1_BYTE_4, + (char) STR_7_BYTES_LATIN1_BYTE_5, + (char) STR_7_BYTES_LATIN1_BYTE_6); + } + BH.consume(sb.length()); } static void setIntB(byte[] array, int offset, int value) {