diff --git a/pom.xml b/pom.xml index 3503eac4f64..02237af5657 100644 --- a/pom.xml +++ b/pom.xml @@ -230,6 +230,18 @@ file comparators, endian transformation classes, and much more. + + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + org.junit.jupiter junit-jupiter @@ -300,6 +312,7 @@ file comparators, endian transformation classes, and much more. true Gary Gregory 86fdc7e2a11262cb + 1.21 @@ -469,5 +482,44 @@ file comparators, endian transformation classes, and much more. true + + benchmark + + true + org.apache + + + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + + benchmark + test + + exec + + + test + java + + -classpath + + org.openjdk.jmh.Main + -rf + json + -rff + target/jmh-result.${benchmark}.json + ${benchmark} + + + + + + + + diff --git a/src/main/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedInputStream.java b/src/main/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedInputStream.java new file mode 100644 index 00000000000..aafa44a3901 --- /dev/null +++ b/src/main/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedInputStream.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.input.buffer; + +import java.io.IOException; +import java.io.InputStream; +import org.apache.commons.io.IOUtils; +import static org.apache.commons.io.IOUtils.EOF; + +/** + * A BufferedReader class who does not care about thread safety, but very much faster. + * + * Should be able to replace java.io.BufferedReader in nearly every use-cases when you + * need the Reader be buffered, but do not need it have thread safety. + */ +public class UnsynchronizedBufferedInputStream extends InputStream { + private final InputStream inputStream; + private final byte[] byteBuffer; + + private int nowIndex = 0; + private int nowLimit = 0; + + /** + * Creates a new instance, which filters the given input stream, and + * uses the given buffer size. + * + * @param inputStream The original input stream, which is being buffered. + * @param charBufferSize size of the buffer. + */ + public UnsynchronizedBufferedInputStream(InputStream inputStream, int charBufferSize) { + this(inputStream, new byte[charBufferSize]); + } + + /** + * Creates a new instance, which filters the given input stream, and + * uses IOUtils.DEFAULT_BUFFER_SIZE. + * + * @param inputStream The original input stream, which is being buffered. + * @see IOUtils#DEFAULT_BUFFER_SIZE + */ + public UnsynchronizedBufferedInputStream(InputStream inputStream) { + this(inputStream, IOUtils.DEFAULT_BUFFER_SIZE); + } + + /** + * Creates a new instance, which filters the given reader, and + * uses the given buffer. + * + * @param inputStream The original inputStream, which is being buffered. + * @param byteBuffer buffer used. + */ + public UnsynchronizedBufferedInputStream(InputStream inputStream, byte[] byteBuffer) { + this.inputStream = inputStream; + this.byteBuffer = byteBuffer; + } + + /** + * {@inheritDoc} + */ + @Override + public int read(byte[] cbuf, int off, int len) throws IOException { + if (len <= 0) { + return 0; + } + int currentBufferSize = this.nowLimit - this.nowIndex; + if (currentBufferSize == 0) { + int readLength; + do { + readLength = this.inputStream.read(this.byteBuffer, 0, this.byteBuffer.length); + } while (readLength == 0); + if (readLength == EOF) { + return EOF; + } + this.nowLimit = readLength; + this.nowIndex = 0; + currentBufferSize = this.nowLimit - this.nowIndex; + } + if (currentBufferSize <= len) { + System.arraycopy(this.byteBuffer, this.nowIndex, cbuf, off, currentBufferSize); + this.nowLimit = this.nowIndex = 0; + return currentBufferSize; + } else { + System.arraycopy(this.byteBuffer, this.nowIndex, cbuf, off, len); + this.nowIndex += len; + return len; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int read() throws IOException { + int res = this.peek(); + if (res != EOF) { + eat(); + } + return res; + } + + /** + * see the next byte, but not mark it as read. + * + * @return the next byte + * @throws IOException by inputStream.read() + * @see #read() + */ + public int peek() throws IOException { + int currentBufferSize = this.nowLimit - this.nowIndex; + if (currentBufferSize == 0) { + int readLength; + do { + readLength = this.inputStream.read(this.byteBuffer, 0, this.byteBuffer.length); + } while (readLength == 0); + if (readLength == EOF) { + return EOF; + } + this.nowLimit = readLength; + this.nowIndex = 0; + return this.byteBuffer[0]; + } + return this.byteBuffer[this.nowIndex]; + } + + /** + * mark the current char as read. + * must be used after invoke peek. + * + * @see #read() + * @see #peek() + */ + public void eat() { + this.nowIndex++; + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws IOException { + if (this.inputStream != null) { + this.inputStream.close(); + } + } + + /** + * getter for this.inputStream + * @return this.inputStream + */ + public InputStream getInputStream() { + return this.inputStream; + } + + /** + * getter for this.byteBuffer + * @return this.byteBuffer + */ + public byte[] getByteBuffer() { + return this.byteBuffer; + } + + /** + * getter for this.nowIndex + * @return this.nowIndex + */ + public int getNowIndex() { + return this.nowIndex; + } + + /** + * setter for this.nowIndex + * @param nowIndex this.nowIndex + */ + public void setNowIndex(int nowIndex) { + this.nowIndex = nowIndex; + } + + /** + * getter for this.nowLimit + * @return this.nowLimit + */ + public int getNowLimit() { + return this.nowLimit; + } + + /** + * setter for this.nowLimit + * @param nowLimit this.nowLimit + */ + public void setNowLimit(int nowLimit) { + this.nowLimit = nowLimit; + } +} diff --git a/src/main/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedReader.java b/src/main/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedReader.java new file mode 100644 index 00000000000..401b959b250 --- /dev/null +++ b/src/main/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedReader.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.input.buffer; + +import java.io.IOException; +import java.io.Reader; +import org.apache.commons.io.IOUtils; +import static org.apache.commons.io.IOUtils.EOF; + +/** + * A BufferedReader class who does not care about thread safety, but very much faster. + * + * Should be able to replace java.io.BufferedReader in nearly every use-cases when you + * need the Reader be buffered, but do not need it have thread safety. + */ +public class UnsynchronizedBufferedReader extends Reader { + private final Reader reader; + private final char[] charBuffer; + + private int nowIndex = 0; + private int nowLimit = 0; + + /** + * Creates a new instance, which filters the given reader, and + * uses the given buffer size. + * + * @param reader The original reader, which is being buffered. + * @param charBufferSize size of the buffer. + */ + public UnsynchronizedBufferedReader(Reader reader, int charBufferSize) { + this(reader, new char[charBufferSize]); + } + + /** + * Creates a new instance, which filters the given reader, and + * uses IOUtils.DEFAULT_BUFFER_SIZE. + * + * @param reader The original reader, which is being buffered. + * @see IOUtils#DEFAULT_BUFFER_SIZE + */ + public UnsynchronizedBufferedReader(Reader reader) { + this(reader, IOUtils.DEFAULT_BUFFER_SIZE); + } + + /** + * Creates a new instance, which filters the given reader, and + * uses the given buffer. + * + * @param reader The original reader, which is being buffered. + * @param charBuffer buffer used. + */ + public UnsynchronizedBufferedReader(Reader reader, char[] charBuffer) { + this.reader = reader; + this.charBuffer = charBuffer; + } + + /** + * {@inheritDoc} + */ + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + if (len <= 0) { + return 0; + } + int currentBufferSize = this.nowLimit - this.nowIndex; + if (currentBufferSize == 0) { + int readLength; + do { + readLength = this.reader.read(this.charBuffer, 0, this.charBuffer.length); + } while (readLength == 0); + if (readLength == EOF) { + return EOF; + } + this.nowLimit = readLength; + this.nowIndex = 0; + currentBufferSize = this.nowLimit - this.nowIndex; + } + if (currentBufferSize <= len) { + System.arraycopy(this.charBuffer, this.nowIndex, cbuf, off, currentBufferSize); + this.nowLimit = this.nowIndex = 0; + return currentBufferSize; + } else { + System.arraycopy(this.charBuffer, this.nowIndex, cbuf, off, len); + this.nowIndex += len; + return len; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int read() throws IOException { + int res = this.peek(); + if (res != EOF) { + eat(); + } + return res; + } + + /** + * see the next char, but not mark it as read. + * + * @return the next char + * @throws IOException by reader.read() + * @see #read() + */ + public int peek() throws IOException { + int currentBufferSize = this.nowLimit - this.nowIndex; + if (currentBufferSize == 0) { + int readLength; + do { + readLength = this.reader.read(this.charBuffer, 0, this.charBuffer.length); + } while (readLength == 0); + if (readLength == EOF) { + return EOF; + } + this.nowLimit = readLength; + this.nowIndex = 0; + return this.charBuffer[0]; + } + return this.charBuffer[this.nowIndex]; + } + + /** + * mark the current char as read. + * must be used after invoke peek. + * + * @see #read() + * @see #peek() + */ + public void eat() { + this.nowIndex++; + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws IOException { + if (this.reader != null) { + this.reader.close(); + } + } + + /** + * getter for this.reader + * @return this.reader + */ + public Reader getReader() { + return this.reader; + } + + /** + * getter for this.charBuffer + * @return this.charBuffer + */ + public char[] getCharBuffer() { + return this.charBuffer; + } + + /** + * getter for this.nowIndex + * @return this.nowIndex + */ + public int getNowIndex() { + return this.nowIndex; + } + + /** + * setter for this.nowIndex + * @param nowIndex this.nowIndex + */ + public void setNowIndex(int nowIndex) { + this.nowIndex = nowIndex; + } + + /** + * getter for this.nowLimit + * @return this.nowLimit + */ + public int getNowLimit() { + return this.nowLimit; + } + + /** + * setter for this.nowLimit + * @param nowLimit this.nowLimit + */ + public void setNowLimit(int nowLimit) { + this.nowLimit = nowLimit; + } +} diff --git a/src/test/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedInputStreamTest.java b/src/test/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedInputStreamTest.java new file mode 100644 index 00000000000..dc5ccf341eb --- /dev/null +++ b/src/test/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedInputStreamTest.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.input.buffer; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.util.Random; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.ReaderInputStream; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * modified from CircularBufferInputStreamTest + * @see CircularBufferInputStreamTest + */ +public class UnsynchronizedBufferedInputStreamTest { + /** + * Always using the same seed should ensure a reproducable test. + */ + private final Random rnd = new Random(1530960934483L); + + @Test + public void testRandomRead() throws Exception { + final byte[] inputBuffer = newInputBuffer(); + final byte[] bufferCopy = new byte[inputBuffer.length]; + final ByteArrayInputStream bais = new ByteArrayInputStream(inputBuffer); + @SuppressWarnings("resource") final UnsynchronizedBufferedInputStream cbis = + new UnsynchronizedBufferedInputStream(bais, 253); + int offset = 0; + final byte[] readBuffer = new byte[256]; + while (offset < bufferCopy.length) { + switch (rnd.nextInt(2)) { + case 0: { + final int res = cbis.read(); + if (res == IOUtils.EOF) { + throw new IllegalStateException("Unexpected EOF at offset " + offset); + } + if (inputBuffer[offset] != res) { + throw new IllegalStateException("Expected " + inputBuffer[offset] + " at offset " + offset + + ", got " + res); + } + ++offset; + break; + } + case 1: { + final int res = cbis.read(readBuffer, 0, rnd.nextInt(readBuffer.length + 1)); + if (res == IOUtils.EOF) { + throw new IllegalStateException("Unexpected EOF at offset " + offset); + } else if (res == 0) { + throw new IllegalStateException("Unexpected zero-byte-result at offset " + offset); + } else { + for (int i = 0; i < res; i++) { + if (inputBuffer[offset] != readBuffer[i]) { + throw new IllegalStateException("Expected " + inputBuffer[offset] + " at offset " + offset + ", got " + readBuffer[i]); + } + ++offset; + } + } + break; + } + default: + throw new IllegalStateException("Unexpected random choice value"); + } + } + bais.close(); + cbis.close(); + } + + @Test + public void testClose() throws Exception { + UnsynchronizedBufferedInputStream b = new UnsynchronizedBufferedInputStream(null); + closeSeveralTimes(b); + UnsynchronizedBufferedInputStream b2 = + new UnsynchronizedBufferedInputStream(new ReaderInputStream(new StringReader(""))); + closeSeveralTimes(b2); + } + + private void closeSeveralTimes(UnsynchronizedBufferedInputStream b) throws IOException { + b.close(); + b.close(); + b.close(); + b.close(); + b.close(); + } + + @Test + public void testFullRead() throws Exception { + UnsynchronizedBufferedInputStream b = + new UnsynchronizedBufferedInputStream(new ReaderInputStream(new StringReader("aaaaa"))); + while (b.read() != IOUtils.EOF) { + } + } + + @Test + public void testFullReadArray() throws Exception { + UnsynchronizedBufferedInputStream b = + new UnsynchronizedBufferedInputStream(new ReaderInputStream(new StringReader("aaaaa"))); + final byte[] buffer = new byte[5]; + while (true) { + final int res = b.read(buffer, 0, buffer.length); + if (res == IOUtils.EOF) { + break; + } + } + } + + @Test + public void testWeirdReadArray() throws Exception { + UnsynchronizedBufferedInputStream b = + new UnsynchronizedBufferedInputStream(new ReaderInputStream(new StringReader("aaaaa"))); + final byte[] buffer = new byte[5]; + int res; + res = b.read(buffer, 0, 0); + assertEquals(res, 0); + res = b.read(buffer, 0, -20); + assertEquals(res, 0); + } + + /** + * Create a large, but random input buffer. + */ + private byte[] newInputBuffer() { + final byte[] buffer = new byte[16 * 512 + rnd.nextInt(512)]; + rnd.nextBytes(buffer); + return buffer; + } +} diff --git a/src/test/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedReaderTest.java b/src/test/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedReaderTest.java new file mode 100644 index 00000000000..95547cfca3b --- /dev/null +++ b/src/test/java/org/apache/commons/io/input/buffer/UnsynchronizedBufferedReaderTest.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.input.buffer; + +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.Random; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * modified from NonThreadSafeButFastBufferedInputStreamTest + * @see UnsynchronizedBufferedInputStreamTest + */ +public class UnsynchronizedBufferedReaderTest { + /** + * Always using the same seed should ensure a reproducable test. + */ + private final Random rnd = new Random(1530960934483L); + + @Test + public void testRandomRead() throws Exception { + final char[] inputBuffer = newInputBuffer(); + final char[] bufferCopy = new char[inputBuffer.length]; + final CharArrayReader bais = new CharArrayReader(inputBuffer); + @SuppressWarnings("resource") final UnsynchronizedBufferedReader cbis = + new UnsynchronizedBufferedReader(bais, 253); + int offset = 0; + final char[] readBuffer = new char[256]; + while (offset < bufferCopy.length) { + switch (rnd.nextInt(2)) { + case 0: { + final int res = cbis.read(); + if (res == IOUtils.EOF) { + throw new IllegalStateException("Unexpected EOF at offset " + offset); + } + if (inputBuffer[offset] != res) { + throw new IllegalStateException("Expected " + inputBuffer[offset] + " at offset " + offset + + ", got " + res); + } + ++offset; + break; + } + case 1: { + final int res = cbis.read(readBuffer, 0, rnd.nextInt(readBuffer.length + 1)); + if (res == IOUtils.EOF) { + throw new IllegalStateException("Unexpected EOF at offset " + offset); + } else if (res == 0) { + throw new IllegalStateException("Unexpected zero-byte-result at offset " + offset); + } else { + for (int i = 0; i < res; i++) { + if (inputBuffer[offset] != readBuffer[i]) { + throw new IllegalStateException("Expected " + inputBuffer[offset] + " at offset " + offset + ", got " + readBuffer[i]); + } + ++offset; + } + } + break; + } + default: + throw new IllegalStateException("Unexpected random choice value"); + } + } + bais.close(); + cbis.close(); + } + + @Test + public void testClose() throws Exception { + UnsynchronizedBufferedReader b = new UnsynchronizedBufferedReader(null); + closeSeveralTimes(b); + UnsynchronizedBufferedReader b2 = + new UnsynchronizedBufferedReader(new StringReader("")); + closeSeveralTimes(b2); + } + + private void closeSeveralTimes(UnsynchronizedBufferedReader b) throws IOException { + b.close(); + b.close(); + b.close(); + b.close(); + b.close(); + } + + @Test + public void testFullRead() throws Exception { + UnsynchronizedBufferedReader b = + new UnsynchronizedBufferedReader(new StringReader("aaaaa")); + while (b.read() != IOUtils.EOF) { + } + } + + @Test + public void testFullReadArray() throws Exception { + UnsynchronizedBufferedReader b = + new UnsynchronizedBufferedReader(new StringReader("aaaaa")); + final char[] buffer = new char[5]; + while (true) { + final int res = b.read(buffer, 0, buffer.length); + if (res == IOUtils.EOF) { + break; + } + } + } + + @Test + public void testWeirdReadArray() throws Exception { + UnsynchronizedBufferedReader b = + new UnsynchronizedBufferedReader(new StringReader("aaaaa")); + final char[] buffer = new char[5]; + int res; + res = b.read(buffer, 0, 0); + assertEquals(res, 0); + res = b.read(buffer, 0, -20); + assertEquals(res, 0); + } + + /** + * Create a large, but random input buffer. + */ + private char[] newInputBuffer() { + final char[] buffer = new char[16 * 512 + rnd.nextInt(512)]; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = (char) rnd.nextInt(); + } + return buffer; + } +} diff --git a/src/test/java/org/apache/commons/io/performance/IOUtilsContentEqualsPerformanceTest.java b/src/test/java/org/apache/commons/io/performance/IOUtilsContentEqualsPerformanceTest.java new file mode 100644 index 00000000000..0874854f0b4 --- /dev/null +++ b/src/test/java/org/apache/commons/io/performance/IOUtilsContentEqualsPerformanceTest.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.performance; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.concurrent.TimeUnit; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.buffer.UnsynchronizedBufferedInputStream; +import org.apache.commons.io.input.buffer.UnsynchronizedBufferedReader; +import org.apache.commons.lang3.StringUtils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * Test to show whether using BitSet for removeAll() methods is faster than using HashSet. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 1, time = 10, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 1, time = 10, timeUnit = TimeUnit.SECONDS) +@Fork(value = 1, jvmArgs = {"-server"}) +public class IOUtilsContentEqualsPerformanceTest { + static String[] STRINGS = new String[1]; + + static { + STRINGS[0] = StringUtils.repeat("ab", 1 << 24); + } + + @Benchmark + public void testBufferedInputStream(Blackhole blackhole) throws IOException { + try ( + InputStream inputStream = IOUtils.toInputStream(STRINGS[0]); + BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream) + ) { + while (true) { + int nowI = bufferedInputStream.read(); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + + @Benchmark + public void testUnsynchronizedBufferedInputStream(Blackhole blackhole) throws IOException { + try ( + InputStream inputStream = IOUtils.toInputStream(STRINGS[0]); + UnsynchronizedBufferedInputStream bufferedInputStream = new UnsynchronizedBufferedInputStream(inputStream) + ) { + while (true) { + int nowI = bufferedInputStream.read(); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + + @Benchmark + public void testBufferedReader(Blackhole blackhole) throws IOException { + try ( + StringReader inputReader = new StringReader(STRINGS[0]); + BufferedReader bufferedReader = new BufferedReader(inputReader) + ) { + while (true) { + int nowI = bufferedReader.read(); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + + @Benchmark + public void testUnsynchronizedBufferedReader(Blackhole blackhole) throws IOException { + try ( + StringReader inputReader = new StringReader(STRINGS[0]); + UnsynchronizedBufferedReader bufferedReader = new UnsynchronizedBufferedReader(inputReader) + ) { + while (true) { + int nowI = bufferedReader.read(); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + + + + + + + + + + + + + + + + + @Benchmark + public void testBufferedInputStream2(Blackhole blackhole) throws IOException { + try ( + InputStream inputStream = IOUtils.toInputStream(STRINGS[0]); + BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream) + ) { + byte[] bytes = new byte[1]; + while (true) { + int nowI = bufferedInputStream.read(bytes , 0, 1); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + + @Benchmark + public void testUnsynchronizedBufferedInputStream2(Blackhole blackhole) throws IOException { + try ( + InputStream inputStream = IOUtils.toInputStream(STRINGS[0]); + UnsynchronizedBufferedInputStream bufferedInputStream = new UnsynchronizedBufferedInputStream(inputStream) + ) { + byte[] bytes = new byte[1]; + while (true) { + int nowI = bufferedInputStream.read(bytes , 0, 1); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + + @Benchmark + public void testBufferedReader2(Blackhole blackhole) throws IOException { + try ( + StringReader inputReader = new StringReader(STRINGS[0]); + BufferedReader bufferedReader = new BufferedReader(inputReader) + ) { + char[] bytes = new char[1]; + while (true) { + int nowI = bufferedReader.read(bytes , 0, 1); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + + @Benchmark + public void testUnsynchronizedBufferedReader2(Blackhole blackhole) throws IOException { + try ( + StringReader inputReader = new StringReader(STRINGS[0]); + UnsynchronizedBufferedReader bufferedReader = new UnsynchronizedBufferedReader(inputReader) + ) { + char[] bytes = new char[1]; + while (true) { + int nowI = bufferedReader.read(bytes , 0, 1); + // do nothing + blackhole.consume(nowI); + if (nowI != -1) { + break; + } + } + } + } + +} \ No newline at end of file