Skip to content

Commit 65f5dd1

Browse files
committed
#129: Improved the performance of newMessageBuffer
1 parent f02fcdd commit 65f5dd1

File tree

3 files changed

+49
-15
lines changed

3 files changed

+49
-15
lines changed

msgpack-core/src/main/java/org/msgpack/core/buffer/ArrayBufferInput.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ public class ArrayBufferInput implements MessageBufferInput {
1111
private MessageBuffer buffer;
1212
private boolean isRead = false;
1313

14+
public ArrayBufferInput(MessageBuffer buf) {
15+
this.buffer = checkNotNull(buf, "input buffer is null");
16+
}
17+
1418
public ArrayBufferInput(byte[] arr) {
1519
this(arr, 0, arr.length);
1620
}

msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBuffer.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import sun.misc.Unsafe;
55
import sun.nio.ch.DirectBuffer;
66

7+
//import java.lang.invoke.MethodHandle;
8+
//import java.lang.invoke.MethodHandles;
9+
//import java.lang.invoke.MethodType;
710
import java.lang.reflect.Constructor;
811
import java.lang.reflect.Field;
912
import java.nio.BufferOverflowException;
@@ -90,7 +93,21 @@ public class MessageBuffer {
9093
}
9194

9295
String bufferClsName = isLittleEndian ? "org.msgpack.core.buffer.MessageBuffer" : "org.msgpack.core.buffer.MessageBufferBE";
93-
msgBufferClass = Class.forName(bufferClsName);
96+
Class<?> bufferCls = Class.forName(bufferClsName);
97+
msgBufferClass = bufferCls;
98+
99+
Constructor<?> mbArrCstr = bufferCls.getDeclaredConstructor(byte[].class);
100+
mbArrCstr.setAccessible(true);
101+
mbArrConstructor = mbArrCstr;
102+
103+
Constructor<?> mbBBCstr = bufferCls.getDeclaredConstructor(ByteBuffer.class);
104+
mbBBCstr.setAccessible(true);
105+
mbBBConstructor = mbBBCstr;
106+
107+
// Requires Java7
108+
//newMsgBuffer = MethodHandles.lookup().unreflectConstructor(mbArrCstr).asType(
109+
// MethodType.methodType(bufferCls, byte[].class)
110+
//);
94111
}
95112
catch (Exception e) {
96113
e.printStackTrace(System.err);
@@ -104,6 +121,13 @@ public class MessageBuffer {
104121
*/
105122
private final static Class<?> msgBufferClass;
106123

124+
private final static Constructor<?> mbArrConstructor;
125+
private final static Constructor<?> mbBBConstructor;
126+
127+
128+
// Requires Java7
129+
//private final static MethodHandle newMsgBuffer;
130+
107131
/**
108132
* Base object for resolving the relative address of the raw byte array.
109133
* If base == null, the address value is a raw memory address
@@ -163,11 +187,7 @@ private static MessageBuffer newMessageBuffer(ByteBuffer bb) {
163187
try {
164188
// We need to use reflection to create MessageBuffer instances in order to prevent TypeProfile generation for getInt method. TypeProfile will be
165189
// generated to resolve one of the method references when two or more classes overrides the method.
166-
Constructor<?> constructor = msgBufferClass.getDeclaredConstructor(ByteBuffer.class);
167-
return (MessageBuffer) constructor.newInstance(bb);
168-
}
169-
catch(NoSuchMethodException e) {
170-
throw new IllegalStateException(e);
190+
return (MessageBuffer) mbBBConstructor.newInstance(bb);
171191
}
172192
catch(Exception e) {
173193
throw new RuntimeException(e);
@@ -182,12 +202,9 @@ private static MessageBuffer newMessageBuffer(ByteBuffer bb) {
182202
private static MessageBuffer newMessageBuffer(byte[] arr) {
183203
checkNotNull(arr);
184204
try {
185-
Constructor<?> constructor = msgBufferClass.getDeclaredConstructor(byte[].class);
186-
return (MessageBuffer) constructor.newInstance(arr);
205+
return (MessageBuffer) mbArrConstructor.newInstance(arr);
187206
}
188-
catch(NoSuchMethodException e) {
189-
throw new IllegalStateException(e);
190-
} catch(Exception e) {
207+
catch(Throwable e) {
191208
throw new RuntimeException(e);
192209
}
193210
}

msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,6 @@ class MessageUnpackerTest extends MessagePackSpec {
530530

531531
}
532532

533-
// TODO: change tag 'ignore' to 'in'
534533
"improve the performance via reset method" taggedAs("reset-arr") in {
535534

536535
val out = new ByteArrayOutputStream
@@ -541,7 +540,7 @@ class MessageUnpackerTest extends MessagePackSpec {
541540
val mb = MessageBuffer.wrap(arr)
542541

543542
val N = 1000
544-
val t = time("unpacker", repeat = 10) {
543+
val t = time("unpacker", repeat = 500) {
545544
block("no-buffer-reset") {
546545
IOUtil.withResource(MessagePackFactory.newDefaultUnpacker(arr)) { unpacker =>
547546
for (i <- 0 until N) {
@@ -553,7 +552,7 @@ class MessageUnpackerTest extends MessagePackSpec {
553552
}
554553
}
555554

556-
block("buffer-reset") {
555+
block("reuse-message-buffer") {
557556
IOUtil.withResource(MessagePackFactory.newDefaultUnpacker(arr)) { unpacker =>
558557
val buf = new ArrayBufferInput(arr)
559558
for (i <- 0 until N) {
@@ -564,9 +563,23 @@ class MessageUnpackerTest extends MessagePackSpec {
564563
}
565564
}
566565
}
566+
567+
block("reuse-array-input") {
568+
IOUtil.withResource(MessagePackFactory.newDefaultUnpacker(arr)) { unpacker =>
569+
val buf = new ArrayBufferInput(arr)
570+
for (i <- 0 until N) {
571+
buf.reset(arr)
572+
unpacker.reset(buf)
573+
unpacker.unpackInt
574+
unpacker.close
575+
}
576+
}
577+
}
578+
567579
}
568580

569-
t("buffer-reset").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax
581+
t("reuse-message-buffer").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax
582+
t("reuse-array-input").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax
570583
}
571584
}
572585
}

0 commit comments

Comments
 (0)