Copies from read-only heap ByteBuffer to direct ByteBuf can avoid stealth ByteBuf allocation and additional copies
Motivation: Read-only heap ByteBuffer doesn't expose array: the existent method to perform copies to direct ByteBuf involves the creation of a (maybe pooled) additional heap ByteBuf instance and copy Modifications: To avoid stressing the allocator with additional (and stealth) heap ByteBuf allocations is provided a method to perform copies using the (pooled) internal NIO buffer Result: Copies from read-only heap ByteBuffer to direct ByteBuf won't create any intermediate ByteBuf
This commit is contained in:
parent
a53f716ca1
commit
ed46c4ed00
|
@ -538,34 +538,48 @@ final class UnsafeByteBufUtil {
|
|||
}
|
||||
|
||||
static void setBytes(AbstractByteBuf buf, long addr, int index, ByteBuffer src) {
|
||||
buf.checkIndex(index, src.remaining());
|
||||
|
||||
int length = src.remaining();
|
||||
final int length = src.remaining();
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src.isDirect()) {
|
||||
buf.checkIndex(index, length);
|
||||
// Copy from direct memory
|
||||
long srcAddress = PlatformDependent.directBufferAddress(src);
|
||||
PlatformDependent.copyMemory(srcAddress + src.position(), addr, src.remaining());
|
||||
PlatformDependent.copyMemory(srcAddress + src.position(), addr, length);
|
||||
src.position(src.position() + length);
|
||||
} else if (src.hasArray()) {
|
||||
buf.checkIndex(index, length);
|
||||
// Copy from array
|
||||
PlatformDependent.copyMemory(src.array(), src.arrayOffset() + src.position(), addr, length);
|
||||
src.position(src.position() + length);
|
||||
} else {
|
||||
ByteBuf tmpBuf = buf.alloc().heapBuffer(length);
|
||||
try {
|
||||
byte[] tmp = tmpBuf.array();
|
||||
src.get(tmp, tmpBuf.arrayOffset(), length); // moves the src position too
|
||||
PlatformDependent.copyMemory(tmp, tmpBuf.arrayOffset(), addr, length);
|
||||
} finally {
|
||||
tmpBuf.release();
|
||||
if (length < 8) {
|
||||
setSingleBytes(buf, addr, index, src, length);
|
||||
} else {
|
||||
//no need to checkIndex: internalNioBuffer is already taking care of it
|
||||
assert buf.nioBufferCount() == 1;
|
||||
final ByteBuffer internalBuffer = buf.internalNioBuffer(index, length);
|
||||
internalBuffer.put(src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setSingleBytes(final AbstractByteBuf buf, final long addr, final int index,
|
||||
final ByteBuffer src, final int length) {
|
||||
buf.checkIndex(index, length);
|
||||
final int srcPosition = src.position();
|
||||
final int srcLimit = src.limit();
|
||||
long dstAddr = addr;
|
||||
for (int srcIndex = srcPosition; srcIndex < srcLimit; srcIndex++) {
|
||||
final byte value = src.get(srcIndex);
|
||||
PlatformDependent.putByte(dstAddr, value);
|
||||
dstAddr++;
|
||||
}
|
||||
src.position(srcLimit);
|
||||
}
|
||||
|
||||
static void getBytes(AbstractByteBuf buf, long addr, int index, OutputStream out, int length) throws IOException {
|
||||
buf.checkIndex(index, length);
|
||||
if (length != 0) {
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2018 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.PooledByteBufAllocator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.microbench.util.AbstractMicrobenchmark;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.TearDown;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class ByteBufCopyBenchmark extends AbstractMicrobenchmark {
|
||||
static {
|
||||
System.setProperty("io.netty.buffer.bytebuf.checkAccessible", "false");
|
||||
}
|
||||
|
||||
@Param({"7", "36", "128", "512" })
|
||||
private int size;
|
||||
@Param({"true", "false" })
|
||||
private boolean directByteBuff;
|
||||
@Param({"true", "false" })
|
||||
private boolean directByteBuffer;
|
||||
@Param({"false", "true" })
|
||||
private boolean readonlyByteBuffer;
|
||||
@Param({"true", "false" })
|
||||
private boolean pooledByteBuf;
|
||||
@Param({"true", "false" })
|
||||
private boolean alignedCopyByteBuffer;
|
||||
@Param({"true", "false" })
|
||||
private boolean alignedCopyByteBuf;
|
||||
@Param({"true", "false" })
|
||||
private boolean nativeOrderByteBuffer;
|
||||
|
||||
private ByteBuffer byteBuffer;
|
||||
private ByteBuf buffer;
|
||||
private int index;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
final int requiredByteBufSize = alignedCopyByteBuf ? size : size + 1;
|
||||
final int requiredByteBufferSize = alignedCopyByteBuffer ? size : size + 1;
|
||||
byteBuffer = directByteBuffer ?
|
||||
ByteBuffer.allocateDirect(requiredByteBufferSize) :
|
||||
ByteBuffer.allocate(requiredByteBufferSize);
|
||||
if (pooledByteBuf) {
|
||||
buffer = directByteBuff ?
|
||||
PooledByteBufAllocator.DEFAULT.directBuffer(requiredByteBufSize, requiredByteBufSize) :
|
||||
PooledByteBufAllocator.DEFAULT.heapBuffer(requiredByteBufSize, requiredByteBufSize);
|
||||
} else {
|
||||
buffer = directByteBuff ?
|
||||
Unpooled.directBuffer(requiredByteBufSize, requiredByteBufSize) :
|
||||
Unpooled.buffer(requiredByteBufSize, requiredByteBufSize);
|
||||
}
|
||||
if (!alignedCopyByteBuffer) {
|
||||
byteBuffer.position(1);
|
||||
byteBuffer = byteBuffer.slice();
|
||||
}
|
||||
if (readonlyByteBuffer) {
|
||||
byteBuffer = byteBuffer.asReadOnlyBuffer();
|
||||
}
|
||||
final ByteOrder byteBufferOrder;
|
||||
if (!nativeOrderByteBuffer) {
|
||||
byteBufferOrder = ByteOrder.LITTLE_ENDIAN == ByteOrder.nativeOrder() ?
|
||||
ByteOrder.BIG_ENDIAN :
|
||||
ByteOrder.LITTLE_ENDIAN;
|
||||
} else {
|
||||
byteBufferOrder = ByteOrder.nativeOrder();
|
||||
}
|
||||
byteBuffer.order(byteBufferOrder);
|
||||
index = alignedCopyByteBuf ? 0 : 1;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public ByteBuf setBytes() {
|
||||
byteBuffer.clear();
|
||||
return buffer.setBytes(index, byteBuffer);
|
||||
}
|
||||
|
||||
@TearDown
|
||||
public void tearDown() {
|
||||
buffer.release();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user