Optimize and minimize bound checks

Motivation:

We should minimize and optimize bound checks as much as possible to get the most out of performance.

Modifications:

- Use bitwise operations to remove branching
- Remove branches when possible

Result:

Better performance for various operations.
This commit is contained in:
Norman Maurer 2015-10-09 23:28:14 +02:00
parent 4403b1a7ea
commit af9dc2c6a6

View File

@ -232,11 +232,15 @@ public abstract class AbstractByteBuf extends ByteBuf {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"minWritableBytes: %d (expected: >= 0)", minWritableBytes)); "minWritableBytes: %d (expected: >= 0)", minWritableBytes));
} }
ensureWritable0(minWritableBytes);
if (minWritableBytes <= writableBytes()) {
return this; return this;
} }
private void ensureWritable0(int minWritableBytes) {
if (minWritableBytes <= writableBytes()) {
return;
}
if (minWritableBytes > maxCapacity - writerIndex) { if (minWritableBytes > maxCapacity - writerIndex) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s", "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
@ -248,7 +252,6 @@ public abstract class AbstractByteBuf extends ByteBuf {
// Adjust to the new capacity. // Adjust to the new capacity.
capacity(newCapacity); capacity(newCapacity);
return this;
} }
@Override @Override
@ -543,21 +546,22 @@ public abstract class AbstractByteBuf extends ByteBuf {
int nLong = length >>> 3; int nLong = length >>> 3;
int nBytes = length & 7; int nBytes = length & 7;
for (int i = nLong; i > 0; i --) { for (int i = nLong; i > 0; i --) {
setLong(index, 0); _setLong(index, 0);
index += 8; index += 8;
} }
if (nBytes == 4) { if (nBytes == 4) {
setInt(index, 0); _setInt(index, 0);
// Not need to update the index as we not will use it after this.
} else if (nBytes < 4) { } else if (nBytes < 4) {
for (int i = nBytes; i > 0; i --) { for (int i = nBytes; i > 0; i --) {
setByte(index, (byte) 0); _setByte(index, (byte) 0);
index ++; index ++;
} }
} else { } else {
setInt(index, 0); _setInt(index, 0);
index += 4; index += 4;
for (int i = nBytes - 4; i > 0; i --) { for (int i = nBytes - 4; i > 0; i --) {
setByte(index, (byte) 0); _setByte(index, (byte) 0);
index ++; index ++;
} }
} }
@ -566,9 +570,9 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public byte readByte() { public byte readByte() {
checkReadableBytes(1); checkReadableBytes0(1);
int i = readerIndex; int i = readerIndex;
byte b = getByte(i); byte b = _getByte(i);
readerIndex = i + 1; readerIndex = i + 1;
return b; return b;
} }
@ -585,7 +589,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public short readShort() { public short readShort() {
checkReadableBytes(2); checkReadableBytes0(2);
short v = _getShort(readerIndex); short v = _getShort(readerIndex);
readerIndex += 2; readerIndex += 2;
return v; return v;
@ -607,7 +611,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public int readUnsignedMedium() { public int readUnsignedMedium() {
checkReadableBytes(3); checkReadableBytes0(3);
int v = _getUnsignedMedium(readerIndex); int v = _getUnsignedMedium(readerIndex);
readerIndex += 3; readerIndex += 3;
return v; return v;
@ -615,7 +619,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public int readInt() { public int readInt() {
checkReadableBytes(4); checkReadableBytes0(4);
int v = _getInt(readerIndex); int v = _getInt(readerIndex);
readerIndex += 4; readerIndex += 4;
return v; return v;
@ -628,7 +632,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public long readLong() { public long readLong() {
checkReadableBytes(8); checkReadableBytes0(8);
long v = _getLong(readerIndex); long v = _getLong(readerIndex);
readerIndex += 8; readerIndex += 8;
return v; return v;
@ -751,7 +755,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public ByteBuf writeByte(int value) { public ByteBuf writeByte(int value) {
ensureAccessible(); ensureAccessible();
ensureWritable(1); ensureWritable0(1);
_setByte(writerIndex++, value); _setByte(writerIndex++, value);
return this; return this;
} }
@ -759,7 +763,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public ByteBuf writeShort(int value) { public ByteBuf writeShort(int value) {
ensureAccessible(); ensureAccessible();
ensureWritable(2); ensureWritable0(2);
_setShort(writerIndex, value); _setShort(writerIndex, value);
writerIndex += 2; writerIndex += 2;
return this; return this;
@ -768,7 +772,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public ByteBuf writeMedium(int value) { public ByteBuf writeMedium(int value) {
ensureAccessible(); ensureAccessible();
ensureWritable(3); ensureWritable0(3);
_setMedium(writerIndex, value); _setMedium(writerIndex, value);
writerIndex += 3; writerIndex += 3;
return this; return this;
@ -777,7 +781,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public ByteBuf writeInt(int value) { public ByteBuf writeInt(int value) {
ensureAccessible(); ensureAccessible();
ensureWritable(4); ensureWritable0(4);
_setInt(writerIndex, value); _setInt(writerIndex, value);
writerIndex += 4; writerIndex += 4;
return this; return this;
@ -786,7 +790,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override @Override
public ByteBuf writeLong(long value) { public ByteBuf writeLong(long value) {
ensureAccessible(); ensureAccessible();
ensureWritable(8); ensureWritable0(8);
_setLong(writerIndex, value); _setLong(writerIndex, value);
writerIndex += 8; writerIndex += 8;
return this; return this;
@ -891,25 +895,32 @@ public abstract class AbstractByteBuf extends ByteBuf {
} }
ensureWritable(length); ensureWritable(length);
checkIndex(writerIndex, length); int wIndex = writerIndex;
checkIndex(wIndex, length);
int nLong = length >>> 3; int nLong = length >>> 3;
int nBytes = length & 7; int nBytes = length & 7;
for (int i = nLong; i > 0; i --) { for (int i = nLong; i > 0; i --) {
writeLong(0); _setLong(wIndex, 0);
wIndex += 8;
} }
if (nBytes == 4) { if (nBytes == 4) {
writeInt(0); _setInt(wIndex, 0);
wIndex += 4;
} else if (nBytes < 4) { } else if (nBytes < 4) {
for (int i = nBytes; i > 0; i --) { for (int i = nBytes; i > 0; i --) {
writeByte((byte) 0); _setByte(wIndex, (byte) 0);
wIndex++;
} }
} else { } else {
writeInt(0); _setInt(wIndex, 0);
wIndex += 4;
for (int i = nBytes - 4; i > 0; i --) { for (int i = nBytes - 4; i > 0; i --) {
writeByte((byte) 0); _setByte(wIndex, (byte) 0);
wIndex++;
} }
} }
writerIndex = wIndex;
return this; return this;
} }
@ -1117,19 +1128,12 @@ public abstract class AbstractByteBuf extends ByteBuf {
} }
protected final void checkIndex(int index) { protected final void checkIndex(int index) {
ensureAccessible(); checkIndex(index, 1);
if (index < 0 || index >= capacity()) {
throw new IndexOutOfBoundsException(String.format(
"index: %d (expected: range(0, %d))", index, capacity()));
}
} }
protected final void checkIndex(int index, int fieldLength) { protected final void checkIndex(int index, int fieldLength) {
ensureAccessible(); ensureAccessible();
if (fieldLength < 0) { if (isInvalid(index, fieldLength, capacity())) {
throw new IllegalArgumentException("length: " + fieldLength + " (expected: >= 0)");
}
if (index < 0 || index > capacity() - fieldLength) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"index: %d, length: %d (expected: range(0, %d))", index, fieldLength, capacity())); "index: %d, length: %d (expected: range(0, %d))", index, fieldLength, capacity()));
} }
@ -1137,7 +1141,7 @@ public abstract class AbstractByteBuf extends ByteBuf {
protected final void checkSrcIndex(int index, int length, int srcIndex, int srcCapacity) { protected final void checkSrcIndex(int index, int length, int srcIndex, int srcCapacity) {
checkIndex(index, length); checkIndex(index, length);
if (srcIndex < 0 || srcIndex > srcCapacity - length) { if (isInvalid(srcIndex, length, srcCapacity)) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"srcIndex: %d, length: %d (expected: range(0, %d))", srcIndex, length, srcCapacity)); "srcIndex: %d, length: %d (expected: range(0, %d))", srcIndex, length, srcCapacity));
} }
@ -1145,22 +1149,30 @@ public abstract class AbstractByteBuf extends ByteBuf {
protected final void checkDstIndex(int index, int length, int dstIndex, int dstCapacity) { protected final void checkDstIndex(int index, int length, int dstIndex, int dstCapacity) {
checkIndex(index, length); checkIndex(index, length);
if (dstIndex < 0 || dstIndex > dstCapacity - length) { if (isInvalid(dstIndex, length, dstCapacity)) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"dstIndex: %d, length: %d (expected: range(0, %d))", dstIndex, length, dstCapacity)); "dstIndex: %d, length: %d (expected: range(0, %d))", dstIndex, length, dstCapacity));
} }
} }
private static boolean isInvalid(int index, int length, int capacity) {
return (index | length | (index + length) | (capacity - (index + length))) < 0;
}
/** /**
* Throws an {@link IndexOutOfBoundsException} if the current * Throws an {@link IndexOutOfBoundsException} if the current
* {@linkplain #readableBytes() readable bytes} of this buffer is less * {@linkplain #readableBytes() readable bytes} of this buffer is less
* than the specified value. * than the specified value.
*/ */
protected final void checkReadableBytes(int minimumReadableBytes) { protected final void checkReadableBytes(int minimumReadableBytes) {
ensureAccessible();
if (minimumReadableBytes < 0) { if (minimumReadableBytes < 0) {
throw new IllegalArgumentException("minimumReadableBytes: " + minimumReadableBytes + " (expected: >= 0)"); throw new IllegalArgumentException("minimumReadableBytes: " + minimumReadableBytes + " (expected: >= 0)");
} }
checkReadableBytes0(minimumReadableBytes);
}
private void checkReadableBytes0(int minimumReadableBytes) {
ensureAccessible();
if (readerIndex > writerIndex - minimumReadableBytes) { if (readerIndex > writerIndex - minimumReadableBytes) {
throw new IndexOutOfBoundsException(String.format( throw new IndexOutOfBoundsException(String.format(
"readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s", "readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s",