From 836ab600a1e83169d7da018489d99f0c435d7618 Mon Sep 17 00:00:00 2001 From: pyb1993 <634077956@qq.com> Date: Tue, 15 Jun 2021 00:06:33 +0800 Subject: [PATCH 1/2] optimize unnecessary require operation in write_ascii_slow --- .../benchmarks/io/HugeStringBenchmark.java | 52 +++++++++++++++++++ .../kryo/io/ByteBufferOutput.java | 2 +- src/com/esotericsoftware/kryo/io/Output.java | 22 +++++--- 3 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java diff --git a/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java new file mode 100644 index 000000000..1008c95d7 --- /dev/null +++ b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java @@ -0,0 +1,52 @@ +/* Copyright (c) 2008-2020, Nathan Sweet + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +package com.esotericsoftware.kryo.benchmarks.io; + +import com.esotericsoftware.kryo.io.Output; +import org.openjdk.jmh.annotations.*; + + + + +/* + * this benchmark is used to test serialize huge string when not reuse the buffer + * */ +@BenchmarkMode(Mode.SingleShotTime) +@Measurement(batchSize = 120000) +public class HugeStringBenchmark { + static String hugeString = ""; + static { + for(int i = 0; i < 256; i++){ + hugeString += "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789"; + } + } + + /** + * 1. not reuse the output + * 2. the initial bufferSize will be smaller than hugeString size + * ***/ + @Benchmark + public void writeAsciiHuge (InputOutputState state) { + Output output = new Output(1024, 1024 * 512); + output.writeAscii(hugeString); + } + +} +￿ \ No newline at end of file diff --git a/src/com/esotericsoftware/kryo/io/ByteBufferOutput.java b/src/com/esotericsoftware/kryo/io/ByteBufferOutput.java index c3cb14769..d2efc4ba5 100644 --- a/src/com/esotericsoftware/kryo/io/ByteBufferOutput.java +++ b/src/com/esotericsoftware/kryo/io/ByteBufferOutput.java @@ -649,7 +649,7 @@ private void writeAscii_slow (String value, int charCount) throws KryoException buffer.put(tmp, 0, charsToWrite); charIndex += charsToWrite; position += charsToWrite; - charsToWrite = Math.min(charCount - charIndex, capacity); + charsToWrite = Math.min(charCount - charIndex, maxAvailableRequired()); if (require(charsToWrite)) buffer = this.byteBuffer; } } diff --git a/src/com/esotericsoftware/kryo/io/Output.java b/src/com/esotericsoftware/kryo/io/Output.java index 6a8aa1289..11b0c67be 100644 --- a/src/com/esotericsoftware/kryo/io/Output.java +++ b/src/com/esotericsoftware/kryo/io/Output.java @@ -173,7 +173,13 @@ public void reset () { position = 0; total = 0; } - + + /**how much space can be allocated when call require **/ + public int maxAvailableRequired(){ + if(outputStream != null){return maxCapacity;} + else{return maxCapacity - position;} + } + /** Ensures the buffer is large enough to read the specified number of bytes. * @return true if the buffer has been resized. */ protected boolean require (int required) throws KryoException { @@ -637,7 +643,7 @@ public void writeBoolean (boolean value) throws KryoException { } // String: - + /** Writes the length and string, or null. Short strings are checked and if ASCII they are written more efficiently, else they * are written as UTF8. If a string is known to be ASCII, {@link #writeAscii(String)} may be used. The string can be read using * {@link Input#readString()} or {@link Input#readStringBuilder()}. @@ -657,6 +663,8 @@ public void writeString (String value) throws KryoException { if (charCount > 1 && charCount <= 32) { for (int i = 0; i < charCount; i++) if (value.charAt(i) > 127) break outer; + + // todo can combine if (capacity - position < charCount) writeAscii_slow(value, charCount); else { @@ -686,7 +694,7 @@ public void writeString (String value) throws KryoException { } if (charIndex < charCount) writeUtf8_slow(value, charCount, charIndex); } - + /** Writes a string that is known to contain only ASCII characters. Non-ASCII strings passed to this method will be corrupted. * Each byte is a 7 bit character with the remaining byte denoting if another character is available. This is slightly more * efficient than {@link #writeString(String)}. The string can be read using {@link Input#readString()} or @@ -735,7 +743,7 @@ else if (c > 0x07FF) { } } } - + private void writeAscii_slow (String value, int charCount) throws KryoException { if (charCount == 0) return; if (position == capacity) require(1); // Must be able to write at least one character. @@ -746,13 +754,11 @@ private void writeAscii_slow (String value, int charCount) throws KryoException value.getBytes(charIndex, charIndex + charsToWrite, buffer, position); charIndex += charsToWrite; position += charsToWrite; - charsToWrite = Math.min(charCount - charIndex, capacity); + charsToWrite = Math.min(charCount - charIndex, maxAvailableRequired()); if (require(charsToWrite)) buffer = this.buffer; } } - - // Primitive arrays: - + /** Writes an int array in bulk. This may be more efficient than writing them individually. */ public void writeInts (int[] array, int offset, int count) throws KryoException { if (capacity >= count << 2) { From a8bc0252dc3430cc57bed5bbdc58b7a959a59b1a Mon Sep 17 00:00:00 2001 From: pyb1993 <634077956@qq.com> Date: Tue, 15 Jun 2021 00:35:24 +0800 Subject: [PATCH 2/2] remove some typo and blank --- .../kryo/benchmarks/io/HugeStringBenchmark.java | 4 +--- src/com/esotericsoftware/kryo/io/Output.java | 12 ++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java index 1008c95d7..bcf7aaf17 100644 --- a/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java +++ b/benchmarks/src/main/java/com/esotericsoftware/kryo/benchmarks/io/HugeStringBenchmark.java @@ -47,6 +47,4 @@ public void writeAsciiHuge (InputOutputState state) { Output output = new Output(1024, 1024 * 512); output.writeAscii(hugeString); } - -} -￿ \ No newline at end of file +} \ No newline at end of file diff --git a/src/com/esotericsoftware/kryo/io/Output.java b/src/com/esotericsoftware/kryo/io/Output.java index 11b0c67be..fc78f5cd8 100644 --- a/src/com/esotericsoftware/kryo/io/Output.java +++ b/src/com/esotericsoftware/kryo/io/Output.java @@ -643,7 +643,7 @@ public void writeBoolean (boolean value) throws KryoException { } // String: - + /** Writes the length and string, or null. Short strings are checked and if ASCII they are written more efficiently, else they * are written as UTF8. If a string is known to be ASCII, {@link #writeAscii(String)} may be used. The string can be read using * {@link Input#readString()} or {@link Input#readStringBuilder()}. @@ -663,8 +663,6 @@ public void writeString (String value) throws KryoException { if (charCount > 1 && charCount <= 32) { for (int i = 0; i < charCount; i++) if (value.charAt(i) > 127) break outer; - - // todo can combine if (capacity - position < charCount) writeAscii_slow(value, charCount); else { @@ -694,7 +692,7 @@ public void writeString (String value) throws KryoException { } if (charIndex < charCount) writeUtf8_slow(value, charCount, charIndex); } - + /** Writes a string that is known to contain only ASCII characters. Non-ASCII strings passed to this method will be corrupted. * Each byte is a 7 bit character with the remaining byte denoting if another character is available. This is slightly more * efficient than {@link #writeString(String)}. The string can be read using {@link Input#readString()} or @@ -743,7 +741,7 @@ else if (c > 0x07FF) { } } } - + private void writeAscii_slow (String value, int charCount) throws KryoException { if (charCount == 0) return; if (position == capacity) require(1); // Must be able to write at least one character. @@ -758,7 +756,9 @@ private void writeAscii_slow (String value, int charCount) throws KryoException if (require(charsToWrite)) buffer = this.buffer; } } - + + // Primitive arrays: + /** Writes an int array in bulk. This may be more efficient than writing them individually. */ public void writeInts (int[] array, int offset, int count) throws KryoException { if (capacity >= count << 2) {