Improve predictability of writeUtf8/writeAscii performance (#10368)
Motivation: writeUtf8 can suffer from inlining issues and/or megamorphic call-sites on the hot path due to ByteBuf hierarchy Modifications: Duplicate and specialize the code paths to reduce the need of polymorphic calls Result: Performance are more stable in user code
This commit is contained in:
parent
5631f1b2b7
commit
162e59848a
@ -705,7 +705,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
|
|||||||
} else {
|
} else {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
}
|
}
|
||||||
return ByteBufUtil.writeUtf8(this, index, sequence, sequence.length());
|
return ByteBufUtil.writeUtf8(this, index, length, sequence, sequence.length());
|
||||||
}
|
}
|
||||||
if (charset.equals(CharsetUtil.US_ASCII) || charset.equals(CharsetUtil.ISO_8859_1)) {
|
if (charset.equals(CharsetUtil.US_ASCII) || charset.equals(CharsetUtil.ISO_8859_1)) {
|
||||||
int length = sequence.length();
|
int length = sequence.length();
|
||||||
|
@ -570,7 +570,7 @@ public final class ByteBufUtil {
|
|||||||
} else if (buf instanceof AbstractByteBuf) {
|
} else if (buf instanceof AbstractByteBuf) {
|
||||||
AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
|
AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
|
||||||
byteBuf.ensureWritable0(reserveBytes);
|
byteBuf.ensureWritable0(reserveBytes);
|
||||||
int written = writeUtf8(byteBuf, byteBuf.writerIndex, seq, start, end);
|
int written = writeUtf8(byteBuf, byteBuf.writerIndex, reserveBytes, seq, start, end);
|
||||||
byteBuf.writerIndex += written;
|
byteBuf.writerIndex += written;
|
||||||
return written;
|
return written;
|
||||||
} else if (buf instanceof WrappedByteBuf) {
|
} else if (buf instanceof WrappedByteBuf) {
|
||||||
@ -584,12 +584,111 @@ public final class ByteBufUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int writeUtf8(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
|
static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes, CharSequence seq, int len) {
|
||||||
return writeUtf8(buffer, writerIndex, seq, 0, len);
|
return writeUtf8(buffer, writerIndex, reservedBytes, seq, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-Path implementation
|
// Fast-Path implementation
|
||||||
static int writeUtf8(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int start, int end) {
|
static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes,
|
||||||
|
CharSequence seq, int start, int end) {
|
||||||
|
if (seq instanceof AsciiString) {
|
||||||
|
writeAsciiString(buffer, writerIndex, (AsciiString) seq, start, end);
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
if (PlatformDependent.hasUnsafe()) {
|
||||||
|
if (buffer.hasArray()) {
|
||||||
|
return unsafeWriteUtf8(buffer.array(), PlatformDependent.byteArrayBaseOffset(),
|
||||||
|
buffer.arrayOffset() + writerIndex, seq, start, end);
|
||||||
|
}
|
||||||
|
if (buffer.hasMemoryAddress()) {
|
||||||
|
return unsafeWriteUtf8(null, buffer.memoryAddress(), writerIndex, seq, start, end);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (buffer.hasArray()) {
|
||||||
|
return safeArrayWriteUtf8(buffer.array(), buffer.arrayOffset() + writerIndex, seq, start, end);
|
||||||
|
}
|
||||||
|
if (buffer.isDirect()) {
|
||||||
|
assert buffer.nioBufferCount() == 1;
|
||||||
|
final ByteBuffer internalDirectBuffer = buffer.internalNioBuffer(writerIndex, reservedBytes);
|
||||||
|
final int bufferPosition = internalDirectBuffer.position();
|
||||||
|
return safeDirectWriteUtf8(internalDirectBuffer, bufferPosition, seq, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return safeWriteUtf8(buffer, writerIndex, seq, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsciiString Fast-Path implementation - no explicit bound-checks
|
||||||
|
static void writeAsciiString(AbstractByteBuf buffer, int writerIndex, AsciiString seq, int start, int end) {
|
||||||
|
final int begin = seq.arrayOffset() + start;
|
||||||
|
final int length = end - start;
|
||||||
|
if (PlatformDependent.hasUnsafe()) {
|
||||||
|
if (buffer.hasArray()) {
|
||||||
|
PlatformDependent.copyMemory(seq.array(), begin,
|
||||||
|
buffer.array(), buffer.arrayOffset() + writerIndex, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buffer.hasMemoryAddress()) {
|
||||||
|
PlatformDependent.copyMemory(seq.array(), begin, buffer.memoryAddress() + writerIndex, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffer.hasArray()) {
|
||||||
|
System.arraycopy(seq.array(), begin, buffer.array(), buffer.arrayOffset() + writerIndex, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buffer.setBytes(writerIndex, seq.array(), begin, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe off-heap Fast-Path implementation
|
||||||
|
private static int safeDirectWriteUtf8(ByteBuffer buffer, int writerIndex, CharSequence seq, int start, int end) {
|
||||||
|
assert !(seq instanceof AsciiString);
|
||||||
|
int oldWriterIndex = writerIndex;
|
||||||
|
|
||||||
|
// We can use the _set methods as these not need to do any index checks and reference checks.
|
||||||
|
// This is possible as we called ensureWritable(...) before.
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
char c = seq.charAt(i);
|
||||||
|
if (c < 0x80) {
|
||||||
|
buffer.put(writerIndex++, (byte) c);
|
||||||
|
} else if (c < 0x800) {
|
||||||
|
buffer.put(writerIndex++, (byte) (0xc0 | (c >> 6)));
|
||||||
|
buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (isSurrogate(c)) {
|
||||||
|
if (!Character.isHighSurrogate(c)) {
|
||||||
|
buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Surrogate Pair consumes 2 characters.
|
||||||
|
if (++i == end) {
|
||||||
|
buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Extra method is copied here to NOT allow inlining of writeUtf8
|
||||||
|
// and increase the chance to inline CharSequence::charAt instead
|
||||||
|
char c2 = seq.charAt(i);
|
||||||
|
if (!Character.isLowSurrogate(c2)) {
|
||||||
|
buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
|
||||||
|
buffer.put(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : (byte) c2);
|
||||||
|
} else {
|
||||||
|
int codePoint = Character.toCodePoint(c, c2);
|
||||||
|
// See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
|
||||||
|
buffer.put(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
|
||||||
|
buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
|
||||||
|
buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
|
||||||
|
buffer.put(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer.put(writerIndex++, (byte) (0xe0 | (c >> 12)));
|
||||||
|
buffer.put(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
|
buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return writerIndex - oldWriterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe off-heap Fast-Path implementation
|
||||||
|
private static int safeWriteUtf8(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int start, int end) {
|
||||||
|
assert !(seq instanceof AsciiString);
|
||||||
int oldWriterIndex = writerIndex;
|
int oldWriterIndex = writerIndex;
|
||||||
|
|
||||||
// We can use the _set methods as these not need to do any index checks and reference checks.
|
// We can use the _set methods as these not need to do any index checks and reference checks.
|
||||||
@ -611,8 +710,20 @@ public final class ByteBufUtil {
|
|||||||
buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
|
buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Extra method to allow inlining the rest of writeUtf8 which is the most likely code path.
|
// Extra method is copied here to NOT allow inlining of writeUtf8
|
||||||
writerIndex = writeUtf8Surrogate(buffer, writerIndex, c, seq.charAt(i));
|
// and increase the chance to inline CharSequence::charAt instead
|
||||||
|
char c2 = seq.charAt(i);
|
||||||
|
if (!Character.isLowSurrogate(c2)) {
|
||||||
|
buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
|
||||||
|
buffer._setByte(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
|
||||||
|
} else {
|
||||||
|
int codePoint = Character.toCodePoint(c, c2);
|
||||||
|
// See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
|
||||||
|
buffer._setByte(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
|
||||||
|
buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
|
||||||
|
buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
|
||||||
|
buffer._setByte(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer._setByte(writerIndex++, (byte) (0xe0 | (c >> 12)));
|
buffer._setByte(writerIndex++, (byte) (0xe0 | (c >> 12)));
|
||||||
buffer._setByte(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
|
buffer._setByte(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
@ -622,19 +733,94 @@ public final class ByteBufUtil {
|
|||||||
return writerIndex - oldWriterIndex;
|
return writerIndex - oldWriterIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int writeUtf8Surrogate(AbstractByteBuf buffer, int writerIndex, char c, char c2) {
|
// safe byte[] Fast-Path implementation
|
||||||
if (!Character.isLowSurrogate(c2)) {
|
private static int safeArrayWriteUtf8(byte[] buffer, int writerIndex, CharSequence seq, int start, int end) {
|
||||||
buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
|
int oldWriterIndex = writerIndex;
|
||||||
buffer._setByte(writerIndex++, Character.isHighSurrogate(c2) ? WRITE_UTF_UNKNOWN : c2);
|
for (int i = start; i < end; i++) {
|
||||||
return writerIndex;
|
char c = seq.charAt(i);
|
||||||
|
if (c < 0x80) {
|
||||||
|
buffer[writerIndex++] = (byte) c;
|
||||||
|
} else if (c < 0x800) {
|
||||||
|
buffer[writerIndex++] = (byte) (0xc0 | (c >> 6));
|
||||||
|
buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
|
||||||
|
} else if (isSurrogate(c)) {
|
||||||
|
if (!Character.isHighSurrogate(c)) {
|
||||||
|
buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Surrogate Pair consumes 2 characters.
|
||||||
|
if (++i == end) {
|
||||||
|
buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char c2 = seq.charAt(i);
|
||||||
|
// Extra method is copied here to NOT allow inlining of writeUtf8
|
||||||
|
// and increase the chance to inline CharSequence::charAt instead
|
||||||
|
if (!Character.isLowSurrogate(c2)) {
|
||||||
|
buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
|
||||||
|
buffer[writerIndex++] = (byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
|
||||||
|
} else {
|
||||||
|
int codePoint = Character.toCodePoint(c, c2);
|
||||||
|
// See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
|
||||||
|
buffer[writerIndex++] = (byte) (0xf0 | (codePoint >> 18));
|
||||||
|
buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 12) & 0x3f));
|
||||||
|
buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 6) & 0x3f));
|
||||||
|
buffer[writerIndex++] = (byte) (0x80 | (codePoint & 0x3f));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer[writerIndex++] = (byte) (0xe0 | (c >> 12));
|
||||||
|
buffer[writerIndex++] = (byte) (0x80 | ((c >> 6) & 0x3f));
|
||||||
|
buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int codePoint = Character.toCodePoint(c, c2);
|
return writerIndex - oldWriterIndex;
|
||||||
// See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
|
}
|
||||||
buffer._setByte(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
|
|
||||||
buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
|
// unsafe Fast-Path implementation
|
||||||
buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
|
private static int unsafeWriteUtf8(byte[] buffer, long memoryOffset, int writerIndex,
|
||||||
buffer._setByte(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
|
CharSequence seq, int start, int end) {
|
||||||
return writerIndex;
|
assert !(seq instanceof AsciiString);
|
||||||
|
long writerOffset = memoryOffset + writerIndex;
|
||||||
|
final long oldWriterOffset = writerOffset;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
char c = seq.charAt(i);
|
||||||
|
if (c < 0x80) {
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) c);
|
||||||
|
} else if (c < 0x800) {
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xc0 | (c >> 6)));
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (isSurrogate(c)) {
|
||||||
|
if (!Character.isHighSurrogate(c)) {
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Surrogate Pair consumes 2 characters.
|
||||||
|
if (++i == end) {
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char c2 = seq.charAt(i);
|
||||||
|
// Extra method is copied here to NOT allow inlining of writeUtf8
|
||||||
|
// and increase the chance to inline CharSequence::charAt instead
|
||||||
|
if (!Character.isLowSurrogate(c2)) {
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++,
|
||||||
|
(byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2));
|
||||||
|
} else {
|
||||||
|
int codePoint = Character.toCodePoint(c, c2);
|
||||||
|
// See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xf0 | (codePoint >> 18)));
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (codePoint & 0x3f)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xe0 | (c >> 12)));
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
|
PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (int) (writerOffset - oldWriterOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -742,32 +928,31 @@ public final class ByteBufUtil {
|
|||||||
*/
|
*/
|
||||||
public static int writeAscii(ByteBuf buf, CharSequence seq) {
|
public static int writeAscii(ByteBuf buf, CharSequence seq) {
|
||||||
// ASCII uses 1 byte per char
|
// ASCII uses 1 byte per char
|
||||||
final int len = seq.length();
|
for (;;) {
|
||||||
if (seq instanceof AsciiString) {
|
if (buf instanceof WrappedCompositeByteBuf) {
|
||||||
AsciiString asciiString = (AsciiString) seq;
|
// WrappedCompositeByteBuf is a sub-class of AbstractByteBuf so it needs special handling.
|
||||||
buf.writeBytes(asciiString.array(), asciiString.arrayOffset(), len);
|
buf = buf.unwrap();
|
||||||
} else {
|
} else if (buf instanceof AbstractByteBuf) {
|
||||||
for (;;) {
|
final int len = seq.length();
|
||||||
if (buf instanceof WrappedCompositeByteBuf) {
|
AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
|
||||||
// WrappedCompositeByteBuf is a sub-class of AbstractByteBuf so it needs special handling.
|
byteBuf.ensureWritable0(len);
|
||||||
buf = buf.unwrap();
|
if (seq instanceof AsciiString) {
|
||||||
} else if (buf instanceof AbstractByteBuf) {
|
writeAsciiString(byteBuf, byteBuf.writerIndex, (AsciiString) seq, 0, len);
|
||||||
AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
|
|
||||||
byteBuf.ensureWritable0(len);
|
|
||||||
int written = writeAscii(byteBuf, byteBuf.writerIndex, seq, len);
|
|
||||||
byteBuf.writerIndex += written;
|
|
||||||
return written;
|
|
||||||
} else if (buf instanceof WrappedByteBuf) {
|
|
||||||
// Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
|
|
||||||
buf = buf.unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
byte[] bytes = seq.toString().getBytes(CharsetUtil.US_ASCII);
|
final int written = writeAscii(byteBuf, byteBuf.writerIndex, seq, len);
|
||||||
buf.writeBytes(bytes);
|
assert written == len;
|
||||||
return bytes.length;
|
|
||||||
}
|
}
|
||||||
|
byteBuf.writerIndex += len;
|
||||||
|
return len;
|
||||||
|
} else if (buf instanceof WrappedByteBuf) {
|
||||||
|
// Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
|
||||||
|
buf = buf.unwrap();
|
||||||
|
} else {
|
||||||
|
byte[] bytes = seq.toString().getBytes(CharsetUtil.US_ASCII);
|
||||||
|
buf.writeBytes(bytes);
|
||||||
|
return bytes.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-Path implementation
|
// Fast-Path implementation
|
||||||
|
@ -18,11 +18,14 @@ package io.netty.buffer;
|
|||||||
import io.netty.util.AsciiString;
|
import io.netty.util.AsciiString;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@ -31,16 +34,48 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
import static io.netty.buffer.Unpooled.unreleasableBuffer;
|
import static io.netty.buffer.Unpooled.unreleasableBuffer;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import static org.junit.Assume.assumeFalse;
|
|
||||||
import static org.junit.Assume.assumeThat;
|
import static org.junit.Assume.assumeThat;
|
||||||
import static org.junit.Assume.assumeTrue;
|
|
||||||
|
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
public class ByteBufUtilTest {
|
public class ByteBufUtilTest {
|
||||||
|
|
||||||
|
private enum BufferType {
|
||||||
|
DIRECT_UNPOOLED, DIRECT_POOLED, HEAP_POOLED, HEAP_UNPOOLED
|
||||||
|
}
|
||||||
|
|
||||||
|
private final BufferType bufferType;
|
||||||
|
|
||||||
|
public ByteBufUtilTest(BufferType bufferType) {
|
||||||
|
this.bufferType = bufferType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteBuf buffer(int capacity) {
|
||||||
|
switch (bufferType) {
|
||||||
|
|
||||||
|
case DIRECT_UNPOOLED:
|
||||||
|
return Unpooled.directBuffer(capacity);
|
||||||
|
case HEAP_UNPOOLED:
|
||||||
|
return Unpooled.buffer(capacity);
|
||||||
|
case DIRECT_POOLED:
|
||||||
|
return PooledByteBufAllocator.DEFAULT.directBuffer(capacity);
|
||||||
|
case HEAP_POOLED:
|
||||||
|
return PooledByteBufAllocator.DEFAULT.buffer(capacity);
|
||||||
|
default:
|
||||||
|
throw new AssertionError("unexpected buffer type: " + bufferType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameterized.Parameters(name = "bufferType = {0}")
|
||||||
|
public static Collection<Object[]> noUnsafe() {
|
||||||
|
return Arrays.asList(new Object[][] {
|
||||||
|
{ BufferType.DIRECT_POOLED },
|
||||||
|
{ BufferType.DIRECT_UNPOOLED },
|
||||||
|
{ BufferType.HEAP_POOLED },
|
||||||
|
{ BufferType.HEAP_UNPOOLED }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void decodeRandomHexBytesWithEvenLength() {
|
public void decodeRandomHexBytesWithEvenLength() {
|
||||||
decodeRandomHexBytes(256);
|
decodeRandomHexBytes(256);
|
||||||
@ -144,14 +179,14 @@ public class ByteBufUtilTest {
|
|||||||
public void writeShortBE() {
|
public void writeShortBE() {
|
||||||
int expected = 0x1234;
|
int expected = 0x1234;
|
||||||
|
|
||||||
ByteBuf buf = Unpooled.buffer(2).order(ByteOrder.BIG_ENDIAN);
|
ByteBuf buf = buffer(2).order(ByteOrder.BIG_ENDIAN);
|
||||||
ByteBufUtil.writeShortBE(buf, expected);
|
ByteBufUtil.writeShortBE(buf, expected);
|
||||||
assertEquals(expected, buf.readShort());
|
assertEquals(expected, buf.readShort());
|
||||||
buf.resetReaderIndex();
|
buf.resetReaderIndex();
|
||||||
assertEquals(ByteBufUtil.swapShort((short) expected), buf.readShortLE());
|
assertEquals(ByteBufUtil.swapShort((short) expected), buf.readShortLE());
|
||||||
buf.release();
|
buf.release();
|
||||||
|
|
||||||
buf = Unpooled.buffer(2).order(ByteOrder.LITTLE_ENDIAN);
|
buf = buffer(2).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
ByteBufUtil.writeShortBE(buf, expected);
|
ByteBufUtil.writeShortBE(buf, expected);
|
||||||
assertEquals((short) expected, buf.readShortLE());
|
assertEquals((short) expected, buf.readShortLE());
|
||||||
buf.resetReaderIndex();
|
buf.resetReaderIndex();
|
||||||
@ -184,14 +219,14 @@ public class ByteBufUtilTest {
|
|||||||
public void writeMediumBE() {
|
public void writeMediumBE() {
|
||||||
int mediumValue = 0x123456;
|
int mediumValue = 0x123456;
|
||||||
|
|
||||||
ByteBuf buf = Unpooled.buffer(4).order(ByteOrder.BIG_ENDIAN);
|
ByteBuf buf = buffer(4).order(ByteOrder.BIG_ENDIAN);
|
||||||
ByteBufUtil.writeMediumBE(buf, mediumValue);
|
ByteBufUtil.writeMediumBE(buf, mediumValue);
|
||||||
assertEquals(mediumValue, buf.readMedium());
|
assertEquals(mediumValue, buf.readMedium());
|
||||||
buf.resetReaderIndex();
|
buf.resetReaderIndex();
|
||||||
assertEquals(ByteBufUtil.swapMedium(mediumValue), buf.readMediumLE());
|
assertEquals(ByteBufUtil.swapMedium(mediumValue), buf.readMediumLE());
|
||||||
buf.release();
|
buf.release();
|
||||||
|
|
||||||
buf = Unpooled.buffer(4).order(ByteOrder.LITTLE_ENDIAN);
|
buf = buffer(4).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
ByteBufUtil.writeMediumBE(buf, mediumValue);
|
ByteBufUtil.writeMediumBE(buf, mediumValue);
|
||||||
assertEquals(mediumValue, buf.readMediumLE());
|
assertEquals(mediumValue, buf.readMediumLE());
|
||||||
buf.resetReaderIndex();
|
buf.resetReaderIndex();
|
||||||
@ -202,9 +237,9 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUsAscii() {
|
public void testWriteUsAscii() {
|
||||||
String usAscii = "NettyRocks";
|
String usAscii = "NettyRocks";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeAscii(buf2, usAscii);
|
ByteBufUtil.writeAscii(buf2, usAscii);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -216,9 +251,9 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUsAsciiSwapped() {
|
public void testWriteUsAsciiSwapped() {
|
||||||
String usAscii = "NettyRocks";
|
String usAscii = "NettyRocks";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
||||||
SwappedByteBuf buf2 = new SwappedByteBuf(Unpooled.buffer(16));
|
SwappedByteBuf buf2 = new SwappedByteBuf(buffer(16));
|
||||||
ByteBufUtil.writeAscii(buf2, usAscii);
|
ByteBufUtil.writeAscii(buf2, usAscii);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -230,10 +265,10 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUsAsciiWrapped() {
|
public void testWriteUsAsciiWrapped() {
|
||||||
String usAscii = "NettyRocks";
|
String usAscii = "NettyRocks";
|
||||||
ByteBuf buf = unreleasableBuffer(Unpooled.buffer(16));
|
ByteBuf buf = unreleasableBuffer(buffer(16));
|
||||||
assertWrapped(buf);
|
assertWrapped(buf);
|
||||||
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
||||||
ByteBuf buf2 = unreleasableBuffer(Unpooled.buffer(16));
|
ByteBuf buf2 = unreleasableBuffer(buffer(16));
|
||||||
assertWrapped(buf2);
|
assertWrapped(buf2);
|
||||||
ByteBufUtil.writeAscii(buf2, usAscii);
|
ByteBufUtil.writeAscii(buf2, usAscii);
|
||||||
|
|
||||||
@ -246,10 +281,10 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUsAsciiComposite() {
|
public void testWriteUsAsciiComposite() {
|
||||||
String usAscii = "NettyRocks";
|
String usAscii = "NettyRocks";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
||||||
ByteBuf buf2 = Unpooled.compositeBuffer().addComponent(
|
ByteBuf buf2 = Unpooled.compositeBuffer().addComponent(
|
||||||
Unpooled.buffer(8)).addComponent(Unpooled.buffer(24));
|
buffer(8)).addComponent(buffer(24));
|
||||||
// write some byte so we start writing with an offset.
|
// write some byte so we start writing with an offset.
|
||||||
buf2.writeByte(1);
|
buf2.writeByte(1);
|
||||||
ByteBufUtil.writeAscii(buf2, usAscii);
|
ByteBufUtil.writeAscii(buf2, usAscii);
|
||||||
@ -264,10 +299,10 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUsAsciiCompositeWrapped() {
|
public void testWriteUsAsciiCompositeWrapped() {
|
||||||
String usAscii = "NettyRocks";
|
String usAscii = "NettyRocks";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
buf.writeBytes(usAscii.getBytes(CharsetUtil.US_ASCII));
|
||||||
ByteBuf buf2 = new WrappedCompositeByteBuf(Unpooled.compositeBuffer().addComponent(
|
ByteBuf buf2 = new WrappedCompositeByteBuf(Unpooled.compositeBuffer().addComponent(
|
||||||
Unpooled.buffer(8)).addComponent(Unpooled.buffer(24)));
|
buffer(8)).addComponent(buffer(24)));
|
||||||
// write some byte so we start writing with an offset.
|
// write some byte so we start writing with an offset.
|
||||||
buf2.writeByte(1);
|
buf2.writeByte(1);
|
||||||
ByteBufUtil.writeAscii(buf2, usAscii);
|
ByteBufUtil.writeAscii(buf2, usAscii);
|
||||||
@ -282,9 +317,9 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUtf8() {
|
public void testWriteUtf8() {
|
||||||
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(usAscii.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, usAscii);
|
ByteBufUtil.writeUtf8(buf2, usAscii);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -296,10 +331,10 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUtf8Composite() {
|
public void testWriteUtf8Composite() {
|
||||||
String utf8 = "Some UTF-8 like äÄ∏ŒŒ";
|
String utf8 = "Some UTF-8 like äÄ∏ŒŒ";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(utf8.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(utf8.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.compositeBuffer().addComponent(
|
ByteBuf buf2 = Unpooled.compositeBuffer().addComponent(
|
||||||
Unpooled.buffer(8)).addComponent(Unpooled.buffer(24));
|
buffer(8)).addComponent(buffer(24));
|
||||||
// write some byte so we start writing with an offset.
|
// write some byte so we start writing with an offset.
|
||||||
buf2.writeByte(1);
|
buf2.writeByte(1);
|
||||||
ByteBufUtil.writeUtf8(buf2, utf8);
|
ByteBufUtil.writeUtf8(buf2, utf8);
|
||||||
@ -314,10 +349,10 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUtf8CompositeWrapped() {
|
public void testWriteUtf8CompositeWrapped() {
|
||||||
String utf8 = "Some UTF-8 like äÄ∏ŒŒ";
|
String utf8 = "Some UTF-8 like äÄ∏ŒŒ";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(utf8.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(utf8.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = new WrappedCompositeByteBuf(Unpooled.compositeBuffer().addComponent(
|
ByteBuf buf2 = new WrappedCompositeByteBuf(Unpooled.compositeBuffer().addComponent(
|
||||||
Unpooled.buffer(8)).addComponent(Unpooled.buffer(24)));
|
buffer(8)).addComponent(buffer(24)));
|
||||||
// write some byte so we start writing with an offset.
|
// write some byte so we start writing with an offset.
|
||||||
buf2.writeByte(1);
|
buf2.writeByte(1);
|
||||||
ByteBufUtil.writeUtf8(buf2, utf8);
|
ByteBufUtil.writeUtf8(buf2, utf8);
|
||||||
@ -338,9 +373,9 @@ public class ByteBufUtilTest {
|
|||||||
.append('\uDC00')
|
.append('\uDC00')
|
||||||
.append('b')
|
.append('b')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -357,9 +392,9 @@ public class ByteBufUtilTest {
|
|||||||
.append('\uDC00')
|
.append('\uDC00')
|
||||||
.append('b')
|
.append('b')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -376,9 +411,9 @@ public class ByteBufUtilTest {
|
|||||||
.append('\uD800')
|
.append('\uD800')
|
||||||
.append('b')
|
.append('b')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -396,9 +431,9 @@ public class ByteBufUtilTest {
|
|||||||
.append('\uD800')
|
.append('\uD800')
|
||||||
.append('b')
|
.append('b')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -416,9 +451,9 @@ public class ByteBufUtilTest {
|
|||||||
.append('\uD800')
|
.append('\uD800')
|
||||||
.append('b')
|
.append('b')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -435,9 +470,9 @@ public class ByteBufUtilTest {
|
|||||||
.append('\uDC00')
|
.append('\uDC00')
|
||||||
.append('b')
|
.append('b')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -452,9 +487,9 @@ public class ByteBufUtilTest {
|
|||||||
String surrogateString = new StringBuilder(2)
|
String surrogateString = new StringBuilder(2)
|
||||||
.append('\uD800')
|
.append('\uD800')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -469,9 +504,9 @@ public class ByteBufUtilTest {
|
|||||||
String surrogateString = new StringBuilder(2)
|
String surrogateString = new StringBuilder(2)
|
||||||
.append('\uDC00')
|
.append('\uDC00')
|
||||||
.toString();
|
.toString();
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(surrogateString.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
ByteBufUtil.writeUtf8(buf2, surrogateString);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -484,9 +519,10 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUsAsciiString() {
|
public void testWriteUsAsciiString() {
|
||||||
AsciiString usAscii = new AsciiString("NettyRocks");
|
AsciiString usAscii = new AsciiString("NettyRocks");
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
int expectedCapacity = usAscii.length();
|
||||||
|
ByteBuf buf = buffer(expectedCapacity);
|
||||||
buf.writeBytes(usAscii.toString().getBytes(CharsetUtil.US_ASCII));
|
buf.writeBytes(usAscii.toString().getBytes(CharsetUtil.US_ASCII));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(expectedCapacity);
|
||||||
ByteBufUtil.writeAscii(buf2, usAscii);
|
ByteBufUtil.writeAscii(buf2, usAscii);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -498,17 +534,17 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUtf8Wrapped() {
|
public void testWriteUtf8Wrapped() {
|
||||||
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
||||||
ByteBuf buf = unreleasableBuffer(Unpooled.buffer(16));
|
ByteBuf buf = unreleasableBuffer(buffer(16));
|
||||||
assertWrapped(buf);
|
assertWrapped(buf);
|
||||||
buf.writeBytes(usAscii.getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(usAscii.getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = unreleasableBuffer(Unpooled.buffer(16));
|
ByteBuf buf2 = unreleasableBuffer(buffer(16));
|
||||||
assertWrapped(buf2);
|
assertWrapped(buf2);
|
||||||
ByteBufUtil.writeUtf8(buf2, usAscii);
|
ByteBufUtil.writeUtf8(buf2, usAscii);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
|
|
||||||
buf.release();
|
buf.unwrap().release();
|
||||||
buf2.release();
|
buf2.unwrap().release();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertWrapped(ByteBuf buf) {
|
private static void assertWrapped(ByteBuf buf) {
|
||||||
@ -518,9 +554,9 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUtf8Subsequence() {
|
public void testWriteUtf8Subsequence() {
|
||||||
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.substring(5, 18).getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(usAscii.substring(5, 18).getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, usAscii, 5, 18);
|
ByteBufUtil.writeUtf8(buf2, usAscii, 5, 18);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -532,9 +568,9 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteUtf8SubsequenceSplitSurrogate() {
|
public void testWriteUtf8SubsequenceSplitSurrogate() {
|
||||||
String usAscii = "\uD800\uDC00"; // surrogate pair: one code point, two chars
|
String usAscii = "\uD800\uDC00"; // surrogate pair: one code point, two chars
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.substring(0, 1).getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(usAscii.substring(0, 1).getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
ByteBufUtil.writeUtf8(buf2, usAscii, 0, 1);
|
ByteBufUtil.writeUtf8(buf2, usAscii, 0, 1);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -546,9 +582,9 @@ public class ByteBufUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testReserveAndWriteUtf8Subsequence() {
|
public void testReserveAndWriteUtf8Subsequence() {
|
||||||
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
String usAscii = "Some UTF-8 like äÄ∏ŒŒ";
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
buf.writeBytes(usAscii.substring(5, 18).getBytes(CharsetUtil.UTF_8));
|
buf.writeBytes(usAscii.substring(5, 18).getBytes(CharsetUtil.UTF_8));
|
||||||
ByteBuf buf2 = Unpooled.buffer(16);
|
ByteBuf buf2 = buffer(16);
|
||||||
int count = ByteBufUtil.reserveAndWriteUtf8(buf2, usAscii, 5, 18, 16);
|
int count = ByteBufUtil.reserveAndWriteUtf8(buf2, usAscii, 5, 18, 16);
|
||||||
|
|
||||||
assertEquals(buf, buf2);
|
assertEquals(buf, buf2);
|
||||||
@ -575,7 +611,7 @@ public class ByteBufUtilTest {
|
|||||||
|
|
||||||
private void testInvalidSubsequences(TestMethod method) {
|
private void testInvalidSubsequences(TestMethod method) {
|
||||||
for (int [] range : INVALID_RANGES) {
|
for (int [] range : INVALID_RANGES) {
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = buffer(16);
|
||||||
try {
|
try {
|
||||||
method.invoke(buf, "Some UTF-8 like äÄ∏ŒŒ", range[0], range[1]);
|
method.invoke(buf, "Some UTF-8 like äÄ∏ŒŒ", range[0], range[1]);
|
||||||
fail("Did not throw IndexOutOfBoundsException for range (" + range[0] + ", " + range[1] + ")");
|
fail("Did not throw IndexOutOfBoundsException for range (" + range[0] + ", " + range[1] + ")");
|
||||||
@ -641,8 +677,8 @@ public class ByteBufUtilTest {
|
|||||||
CompositeByteBuf buffer = Unpooled.compositeBuffer();
|
CompositeByteBuf buffer = Unpooled.compositeBuffer();
|
||||||
try {
|
try {
|
||||||
byte[] bytes = "1234".getBytes(CharsetUtil.UTF_8);
|
byte[] bytes = "1234".getBytes(CharsetUtil.UTF_8);
|
||||||
buffer.addComponent(Unpooled.buffer(bytes.length).writeBytes(bytes));
|
buffer.addComponent(buffer(bytes.length).writeBytes(bytes));
|
||||||
buffer.addComponent(Unpooled.buffer(bytes.length).writeBytes(bytes));
|
buffer.addComponent(buffer(bytes.length).writeBytes(bytes));
|
||||||
assertEquals("1234", buffer.toString(bytes.length, bytes.length, CharsetUtil.UTF_8));
|
assertEquals("1234", buffer.toString(bytes.length, bytes.length, CharsetUtil.UTF_8));
|
||||||
} finally {
|
} finally {
|
||||||
buffer.release();
|
buffer.release();
|
||||||
@ -703,7 +739,7 @@ public class ByteBufUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsTextWithInvalidIndexAndLength() {
|
public void testIsTextWithInvalidIndexAndLength() {
|
||||||
ByteBuf buffer = Unpooled.buffer();
|
ByteBuf buffer = buffer(4);
|
||||||
try {
|
try {
|
||||||
buffer.writeBytes(new byte[4]);
|
buffer.writeBytes(new byte[4]);
|
||||||
int[][] validIndexLengthPairs = {
|
int[][] validIndexLengthPairs = {
|
||||||
@ -760,8 +796,8 @@ public class ByteBufUtilTest {
|
|||||||
checkUtf8Bytes(s);
|
checkUtf8Bytes(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkUtf8Bytes(final CharSequence charSequence) {
|
private void checkUtf8Bytes(final CharSequence charSequence) {
|
||||||
final ByteBuf buf = Unpooled.buffer(ByteBufUtil.utf8MaxBytes(charSequence));
|
final ByteBuf buf = buffer(ByteBufUtil.utf8MaxBytes(charSequence));
|
||||||
try {
|
try {
|
||||||
final int writtenBytes = ByteBufUtil.writeUtf8(buf, charSequence);
|
final int writtenBytes = ByteBufUtil.writeUtf8(buf, charSequence);
|
||||||
final int utf8Bytes = ByteBufUtil.utf8Bytes(charSequence);
|
final int utf8Bytes = ByteBufUtil.utf8Bytes(charSequence);
|
||||||
@ -771,8 +807,8 @@ public class ByteBufUtilTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertIsText(byte[] bytes, boolean expected, Charset charset) {
|
private void assertIsText(byte[] bytes, boolean expected, Charset charset) {
|
||||||
ByteBuf buffer = Unpooled.buffer();
|
ByteBuf buffer = buffer(bytes.length);
|
||||||
try {
|
try {
|
||||||
buffer.writeBytes(bytes);
|
buffer.writeBytes(bytes);
|
||||||
assertEquals(expected, ByteBufUtil.isText(buffer, charset));
|
assertEquals(expected, ByteBufUtil.isText(buffer, charset));
|
||||||
@ -783,6 +819,7 @@ public class ByteBufUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsTextMultiThreaded() throws Throwable {
|
public void testIsTextMultiThreaded() throws Throwable {
|
||||||
|
assumeThat(bufferType, is(BufferType.HEAP_UNPOOLED));
|
||||||
final ByteBuf buffer = Unpooled.copiedBuffer("Hello, World!", CharsetUtil.ISO_8859_1);
|
final ByteBuf buffer = Unpooled.copiedBuffer("Hello, World!", CharsetUtil.ISO_8859_1);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -822,21 +859,9 @@ public class ByteBufUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetBytesHeap() {
|
public void testGetBytes() {
|
||||||
final ByteBuf buf = Unpooled.buffer(4);
|
final ByteBuf buf = buffer(4);
|
||||||
try {
|
try {
|
||||||
assumeTrue(buf.hasArray());
|
|
||||||
checkGetBytes(buf);
|
|
||||||
} finally {
|
|
||||||
buf.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetBytesDirect() {
|
|
||||||
final ByteBuf buf = Unpooled.directBuffer(4);
|
|
||||||
try {
|
|
||||||
assumeFalse(buf.hasArray());
|
|
||||||
checkGetBytes(buf);
|
checkGetBytes(buf);
|
||||||
} finally {
|
} finally {
|
||||||
buf.release();
|
buf.release();
|
||||||
@ -845,16 +870,17 @@ public class ByteBufUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetBytesHeapWithNonZeroArrayOffset() {
|
public void testGetBytesHeapWithNonZeroArrayOffset() {
|
||||||
final ByteBuf buf = Unpooled.buffer(5);
|
assumeThat(bufferType, is(BufferType.HEAP_UNPOOLED));
|
||||||
|
final ByteBuf buf = buffer(5);
|
||||||
try {
|
try {
|
||||||
buf.setByte(0, 0x05);
|
buf.setByte(0, 0x05);
|
||||||
|
|
||||||
final ByteBuf slice = buf.slice(1, 4);
|
final ByteBuf slice = buf.slice(1, 4);
|
||||||
slice.writerIndex(0);
|
slice.writerIndex(0);
|
||||||
|
|
||||||
assumeTrue(slice.hasArray());
|
assertTrue(slice.hasArray());
|
||||||
assumeThat(slice.arrayOffset(), is(1));
|
assertThat(slice.arrayOffset(), is(1));
|
||||||
assumeThat(slice.array().length, is(buf.capacity()));
|
assertThat(slice.array().length, is(buf.capacity()));
|
||||||
|
|
||||||
checkGetBytes(slice);
|
checkGetBytes(slice);
|
||||||
} finally {
|
} finally {
|
||||||
@ -864,16 +890,17 @@ public class ByteBufUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetBytesHeapWithArrayLengthGreaterThanCapacity() {
|
public void testGetBytesHeapWithArrayLengthGreaterThanCapacity() {
|
||||||
final ByteBuf buf = Unpooled.buffer(5);
|
assumeThat(bufferType, is(BufferType.HEAP_UNPOOLED));
|
||||||
|
final ByteBuf buf = buffer(5);
|
||||||
try {
|
try {
|
||||||
buf.setByte(4, 0x05);
|
buf.setByte(4, 0x05);
|
||||||
|
|
||||||
final ByteBuf slice = buf.slice(0, 4);
|
final ByteBuf slice = buf.slice(0, 4);
|
||||||
slice.writerIndex(0);
|
slice.writerIndex(0);
|
||||||
|
|
||||||
assumeTrue(slice.hasArray());
|
assertTrue(slice.hasArray());
|
||||||
assumeThat(slice.arrayOffset(), is(0));
|
assertThat(slice.arrayOffset(), is(0));
|
||||||
assumeThat(slice.array().length, greaterThan(slice.capacity()));
|
assertThat(slice.array().length, greaterThan(slice.capacity()));
|
||||||
|
|
||||||
checkGetBytes(slice);
|
checkGetBytes(slice);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -273,6 +273,10 @@ public final class PlatformDependent {
|
|||||||
LINUX_OS_CLASSIFIERS = Collections.unmodifiableSet(availableClassifiers);
|
LINUX_OS_CLASSIFIERS = Collections.unmodifiableSet(availableClassifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long byteArrayBaseOffset() {
|
||||||
|
return BYTE_ARRAY_BASE_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean hasDirectBufferNoCleanerConstructor() {
|
public static boolean hasDirectBufferNoCleanerConstructor() {
|
||||||
return PlatformDependent0.hasDirectBufferNoCleanerConstructor();
|
return PlatformDependent0.hasDirectBufferNoCleanerConstructor();
|
||||||
}
|
}
|
||||||
@ -659,6 +663,10 @@ public final class PlatformDependent {
|
|||||||
PlatformDependent0.putByte(data, index, value);
|
PlatformDependent0.putByte(data, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void putByte(Object data, long offset, byte value) {
|
||||||
|
PlatformDependent0.putByte(data, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static void putShort(byte[] data, int index, short value) {
|
public static void putShort(byte[] data, int index, short value) {
|
||||||
PlatformDependent0.putShort(data, index, value);
|
PlatformDependent0.putShort(data, index, value);
|
||||||
}
|
}
|
||||||
@ -687,6 +695,11 @@ public final class PlatformDependent {
|
|||||||
PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
|
PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void copyMemory(byte[] src, int srcIndex, byte[] dst, int dstIndex, long length) {
|
||||||
|
PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex,
|
||||||
|
dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
|
||||||
|
}
|
||||||
|
|
||||||
public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) {
|
public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) {
|
||||||
PlatformDependent0.copyMemory(null, srcAddr, dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
|
PlatformDependent0.copyMemory(null, srcAddr, dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
|
||||||
}
|
}
|
||||||
|
@ -590,6 +590,10 @@ final class PlatformDependent0 {
|
|||||||
UNSAFE.putByte(data, BYTE_ARRAY_BASE_OFFSET + index, value);
|
UNSAFE.putByte(data, BYTE_ARRAY_BASE_OFFSET + index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void putByte(Object data, long offset, byte value) {
|
||||||
|
UNSAFE.putByte(data, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
static void putShort(byte[] data, int index, short value) {
|
static void putShort(byte[] data, int index, short value) {
|
||||||
UNSAFE.putShort(data, BYTE_ARRAY_BASE_OFFSET + index, value);
|
UNSAFE.putShort(data, BYTE_ARRAY_BASE_OFFSET + index, value);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import io.netty.microbench.util.AbstractMicrobenchmark;
|
|||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.Measurement;
|
import org.openjdk.jmh.annotations.Measurement;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
import org.openjdk.jmh.annotations.Scope;
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
import org.openjdk.jmh.annotations.Setup;
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
import org.openjdk.jmh.annotations.State;
|
import org.openjdk.jmh.annotations.State;
|
||||||
@ -34,6 +35,11 @@ import org.openjdk.jmh.annotations.Warmup;
|
|||||||
@Measurement(iterations = 10)
|
@Measurement(iterations = 10)
|
||||||
public class
|
public class
|
||||||
ByteBufUtilBenchmark extends AbstractMicrobenchmark {
|
ByteBufUtilBenchmark extends AbstractMicrobenchmark {
|
||||||
|
|
||||||
|
@Param({ "true", "false" })
|
||||||
|
private boolean direct;
|
||||||
|
@Param({ "8", "16", "64", "128" })
|
||||||
|
private int length;
|
||||||
private ByteBuf buffer;
|
private ByteBuf buffer;
|
||||||
private ByteBuf wrapped;
|
private ByteBuf wrapped;
|
||||||
private ByteBuf asciiBuffer;
|
private ByteBuf asciiBuffer;
|
||||||
@ -48,18 +54,19 @@ public class
|
|||||||
@Setup
|
@Setup
|
||||||
public void setup() {
|
public void setup() {
|
||||||
// Use buffer sizes that will also allow to write UTF-8 without grow the buffer
|
// Use buffer sizes that will also allow to write UTF-8 without grow the buffer
|
||||||
buffer = Unpooled.directBuffer(512);
|
final int maxBytes = ByteBufUtil.utf8MaxBytes(length);
|
||||||
wrapped = Unpooled.unreleasableBuffer(Unpooled.directBuffer(512));
|
buffer = direct? Unpooled.directBuffer(maxBytes) : Unpooled.buffer(maxBytes);
|
||||||
asciiSequence = new StringBuilder(128);
|
wrapped = Unpooled.unreleasableBuffer(direct? Unpooled.directBuffer(maxBytes) : Unpooled.buffer(maxBytes));
|
||||||
for (int i = 0; i < 128; i++) {
|
asciiSequence = new StringBuilder(length);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
asciiSequence.append('a');
|
asciiSequence.append('a');
|
||||||
}
|
}
|
||||||
ascii = asciiSequence.toString();
|
ascii = asciiSequence.toString();
|
||||||
|
|
||||||
// Generate some mixed UTF-8 String for benchmark
|
// Generate some mixed UTF-8 String for benchmark
|
||||||
utf8Sequence = new StringBuilder(128);
|
utf8Sequence = new StringBuilder(length);
|
||||||
char[] chars = "Some UTF-8 like äÄ∏ŒŒ".toCharArray();
|
char[] chars = "Some UTF-8 like äÄ∏ŒŒ".toCharArray();
|
||||||
for (int i = 0; i < 128; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
utf8Sequence.append(chars[i % chars.length]);
|
utf8Sequence.append(chars[i % chars.length]);
|
||||||
}
|
}
|
||||||
utf8 = utf8Sequence.toString();
|
utf8 = utf8Sequence.toString();
|
||||||
|
@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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 io.netty.microbench.buffer;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.microbench.util.AbstractMicrobenchmark;
|
||||||
|
import io.netty.util.AsciiString;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.CompilerControl;
|
||||||
|
import org.openjdk.jmh.annotations.CompilerControl.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.Fork;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Fork(value = 2, jvmArgsAppend = "-XX:MaxInlineLevel=9")
|
||||||
|
public class Utf8EncodingBenchmark extends AbstractMicrobenchmark {
|
||||||
|
private static class AnotherCharSequence implements CharSequence {
|
||||||
|
private final char[] chars;
|
||||||
|
|
||||||
|
AnotherCharSequence(String chars) {
|
||||||
|
this.chars = new char[chars.length()];
|
||||||
|
chars.getChars(0, chars.length(), this.chars, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int length() {
|
||||||
|
return chars.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char charAt(int i) {
|
||||||
|
return chars[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence subSequence(int start, int end) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// experiment test input
|
||||||
|
private String[] strings;
|
||||||
|
private StringBuilder[] stringBuilders;
|
||||||
|
private AnotherCharSequence[] anotherCharSequences;
|
||||||
|
private AsciiString[] asciiStrings;
|
||||||
|
@Param({ "false", "true" })
|
||||||
|
private boolean direct;
|
||||||
|
private ByteBuf buffer;
|
||||||
|
@Param({ "false", "true" })
|
||||||
|
private boolean noUnsafe;
|
||||||
|
private int dataSetLength;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void init() {
|
||||||
|
System.setProperty("io.netty.noUnsafe", Boolean.valueOf(noUnsafe).toString());
|
||||||
|
InputStream testTextStream = null;
|
||||||
|
InputStreamReader inStreamReader = null;
|
||||||
|
BufferedReader buffReader = null;
|
||||||
|
int maxExpectedSize = 0;
|
||||||
|
List<String> strings = new ArrayList<String>();
|
||||||
|
List<StringBuilder> stringBuilders = new ArrayList<StringBuilder>();
|
||||||
|
List<AnotherCharSequence> anotherCharSequenceList = new ArrayList<AnotherCharSequence>();
|
||||||
|
List<AsciiString> asciiStrings = new ArrayList<AsciiString>();
|
||||||
|
try {
|
||||||
|
testTextStream = getClass().getResourceAsStream("/Utf8Samples.txt");
|
||||||
|
inStreamReader = new InputStreamReader(testTextStream, "UTF-8");
|
||||||
|
buffReader = new BufferedReader(inStreamReader);
|
||||||
|
String line;
|
||||||
|
while ((line = buffReader.readLine()) != null) {
|
||||||
|
strings.add(line);
|
||||||
|
stringBuilders.add(new StringBuilder(line));
|
||||||
|
anotherCharSequenceList.add(new AnotherCharSequence(line));
|
||||||
|
asciiStrings.add(new AsciiString(line));
|
||||||
|
maxExpectedSize = Math.max(maxExpectedSize, ByteBufUtil.utf8MaxBytes(line.length()));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
closeStream(testTextStream);
|
||||||
|
closeReader(inStreamReader);
|
||||||
|
closeReader(buffReader);
|
||||||
|
}
|
||||||
|
buffer = direct? Unpooled.directBuffer(maxExpectedSize, maxExpectedSize) :
|
||||||
|
Unpooled.buffer(maxExpectedSize, maxExpectedSize);
|
||||||
|
buffer.setByte(maxExpectedSize - 1, 0);
|
||||||
|
this.strings = strings.toArray(new String[strings.size()]);
|
||||||
|
this.stringBuilders = stringBuilders.toArray(new StringBuilder[stringBuilders.size()]);
|
||||||
|
this.anotherCharSequences =
|
||||||
|
anotherCharSequenceList.toArray(new AnotherCharSequence[anotherCharSequenceList.size()]);
|
||||||
|
this.asciiStrings = asciiStrings.toArray(new AsciiString[asciiStrings.size()]);
|
||||||
|
this.dataSetLength = this.strings.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void closeStream(InputStream inStream) {
|
||||||
|
if (inStream != null) {
|
||||||
|
try {
|
||||||
|
inStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void closeReader(Reader buffReader) {
|
||||||
|
if (buffReader != null) {
|
||||||
|
try {
|
||||||
|
buffReader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@CompilerControl(Mode.DONT_INLINE)
|
||||||
|
public int nestedByteBufUtilWriteUtf8String() {
|
||||||
|
int countBytes = 0;
|
||||||
|
for (String string : strings) {
|
||||||
|
countBytes += nestedByteBufUtilWriteUtf8String1(string);
|
||||||
|
}
|
||||||
|
return countBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nestedByteBufUtilWriteUtf8String1(String string) {
|
||||||
|
return nestedByteBufUtilWriteUtf8String2(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nestedByteBufUtilWriteUtf8String2(String string) {
|
||||||
|
return nestedByteBufUtilWriteUtf8String3(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nestedByteBufUtilWriteUtf8String3(String string) {
|
||||||
|
return nestedByteBufUtilWriteUtf8String4(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nestedByteBufUtilWriteUtf8String4(String string) {
|
||||||
|
return nestedByteBufUtilWriteUtf8String5(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nestedByteBufUtilWriteUtf8String5(String string) {
|
||||||
|
return nestedByteBufUtilWriteUtf8String6(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nestedByteBufUtilWriteUtf8String6(String string) {
|
||||||
|
// this calls should be inlined but...what happen to the subsequent calls > MaxInlineLevel?
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, string, 0, string.length());
|
||||||
|
return buffer.writerIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@CompilerControl(Mode.DONT_INLINE)
|
||||||
|
public int byteBufUtilWriteUtf8String() {
|
||||||
|
int countBytes = 0;
|
||||||
|
for (String string : strings) {
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, string, 0, string.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
}
|
||||||
|
return countBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@CompilerControl(Mode.DONT_INLINE)
|
||||||
|
public int byteBufUtilWriteUtf8Bimorphic() {
|
||||||
|
int countBytes = 0;
|
||||||
|
for (int i = 0, size = dataSetLength; i < size; i++) {
|
||||||
|
final StringBuilder stringBuilder = stringBuilders[i];
|
||||||
|
final String string = strings[i];
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, stringBuilder, 0, stringBuilder.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, string, 0, string.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
}
|
||||||
|
return countBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@CompilerControl(Mode.DONT_INLINE)
|
||||||
|
public int byteBufUtilWriteUtf8Megamorphic() {
|
||||||
|
int countBytes = 0;
|
||||||
|
for (int i = 0, size = dataSetLength; i < size; i++) {
|
||||||
|
final StringBuilder stringBuilder = stringBuilders[i];
|
||||||
|
final String string = strings[i];
|
||||||
|
final AnotherCharSequence anotherCharSequence = anotherCharSequences[i];
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, stringBuilder, 0, stringBuilder.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, string, 0, string.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, anotherCharSequence, 0, anotherCharSequence.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
}
|
||||||
|
return countBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@CompilerControl(Mode.DONT_INLINE)
|
||||||
|
public int byteBufUtilWriteUtf8CommonCharSequences() {
|
||||||
|
int countBytes = 0;
|
||||||
|
for (int i = 0, size = dataSetLength; i < size; i++) {
|
||||||
|
final StringBuilder stringBuilder = stringBuilders[i];
|
||||||
|
final String string = strings[i];
|
||||||
|
final AsciiString asciiString = asciiStrings[i];
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, stringBuilder, 0, stringBuilder.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, string, 0, string.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, asciiString, 0, asciiString.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
}
|
||||||
|
return countBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@CompilerControl(Mode.DONT_INLINE)
|
||||||
|
public int byteBufUtilWriteUtf8AsciiString() {
|
||||||
|
int countBytes = 0;
|
||||||
|
for (int i = 0, size = dataSetLength; i < size; i++) {
|
||||||
|
final AsciiString asciiString = asciiStrings[i];
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
ByteBufUtil.writeUtf8(buffer, asciiString, 0, asciiString.length());
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
}
|
||||||
|
return countBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@CompilerControl(Mode.DONT_INLINE)
|
||||||
|
public int writeGetBytes() throws UnsupportedEncodingException {
|
||||||
|
int countBytes = 0;
|
||||||
|
for (String string : strings) {
|
||||||
|
buffer.resetWriterIndex();
|
||||||
|
final byte[] bytes = string.getBytes("UTF-8");
|
||||||
|
buffer.writeBytes(bytes);
|
||||||
|
countBytes += buffer.writerIndex();
|
||||||
|
}
|
||||||
|
return countBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1399
microbench/src/main/resources/Utf8Samples.txt
Normal file
1399
microbench/src/main/resources/Utf8Samples.txt
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user