diff options
author | Nico Kruber <[email protected]> | 2011-11-25 11:48:40 +0100 |
---|---|---|
committer | Henrik Nord <[email protected]> | 2011-12-09 12:38:43 +0100 |
commit | 864faca823631cfd46da432b4e405d94d7104429 (patch) | |
tree | b764c458861be6741adae0c6240b7c1760b3b24f /lib/jinterface/java_src | |
parent | 7bd353a976a0bf4d93b962376daa0d38958335d0 (diff) | |
download | otp-864faca823631cfd46da432b4e405d94d7104429.tar.gz otp-864faca823631cfd46da432b4e405d94d7104429.tar.bz2 otp-864faca823631cfd46da432b4e405d94d7104429.zip |
JInterface: improve OtpOutputStream buffer allocation
Previously, the buffer was increased linearly by 2048 bytes.
I now propose to use an exponential increase function
(similar to Javas ArrayList, e.g. always at least +50%).
This significantly increases performance of e.g. doRPC for
large parameters as the following comparison illustrates
(shown is the buffer size after each time, the buffer has reached its limit):
n n*2048 (n*3)/2+1 (n*3)/2+1 (at least +2048)
1 2,048 2,048 2,048
2 4,096 3,073 4,096
3 6,144 4,610 6,145
4 8,192 6,916 9,218
5 10,240 10,375 13,828
6 12,288 15,563 20,743
7 14,336 23,345 31,115
8 16,384 35,018 46,673
9 18,432 52,528 70,010
10 20,480 78,793 105,016
11 22,528 118,190 157,525
12 24,576 177,286 236,288
13 26,624 265,930 354,433
14 28,672 398,896 531,650
15 30,720 598,345 797,476
16 32,768 897,518 1,196,215
17 34,816 1,346,278 1,794,323
18 36,864 2,019,418 2,691,485
19 38,912 3,029,128 4,037,228
20 40,960 4,543,693 6,055,843
21 43,008 6,815,540 9,083,765
22 45,056 10,223,311 13,625,648
23 47,104 15,334,967 20,438,473
24 49,152 23,002,451 30,657,710
25 51,200 34,503,677 45,986,566
26 53,248 51,755,516 68,979,850
27 55,296 77,633,275 103,469,776
28 57,344 116,449,913 155,204,665
29 59,392 174,674,870 232,806,998
30 61,440 262,012,306 349,210,498
Actually, ArrayList uses the (n*3)/2+1 strategy. In order not to
decrease performance for messages <10k, we could keep the (public)
OtpOutputStream#defaultIncrement constant and let the buffer always
increase by at least this much (third column).
In order to create a buffer of 1MB, now only 16 array copies are
needed vs. (1024*1024/2048)=512 array copies for the linear increase
function. If a user sends a message of 10MB size, this is 22 vs.
5120 copies.
NOTE: the meaning of the "public static final int defaultIncrement"
member has changed a bit with this implementation (API compatibility?)
- why was this public in the first place?
Diffstat (limited to 'lib/jinterface/java_src')
-rw-r--r-- | lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java index 181350100f..2febd5ce0a 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java @@ -25,6 +25,7 @@ import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.BigInteger; import java.text.DecimalFormat; +import java.util.Arrays; /** * Provides a stream for encoding Erlang terms to external format, for @@ -39,7 +40,7 @@ public class OtpOutputStream extends ByteArrayOutputStream { /** The default initial size of the stream. * */ public static final int defaultInitialSize = 2048; - /** The default increment used when growing the stream. * */ + /** The default increment used when growing the stream (increment at least this much). * */ public static final int defaultIncrement = 2048; // static formats, used to encode floats and doubles @@ -95,6 +96,39 @@ public class OtpOutputStream extends ByteArrayOutputStream { } /** + * Trims the capacity of this <tt>OtpOutputStream</tt> instance to be the + * buffer's current size. An application can use this operation to minimize + * the storage of an <tt>OtpOutputStream</tt> instance. + */ + public void trimToSize() { + if (super.count < super.buf.length) { + super.buf = Arrays.copyOf(super.buf, super.count); + } + } + + /** + * Increases the capacity of this <tt>OtpOutputStream</tt> instance, if + * necessary, to ensure that it can hold at least the number of elements + * specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + public void ensureCapacity(int minCapacity) { + int oldCapacity = super.buf.length; + if (minCapacity > oldCapacity) { + int newCapacity = (oldCapacity * 3)/2 + 1; + if (newCapacity < oldCapacity + defaultIncrement) + newCapacity = oldCapacity + defaultIncrement; + if (newCapacity < minCapacity) + newCapacity = minCapacity; + // minCapacity is usually close to size, so this is a win: + final byte[] tmp = new byte[newCapacity]; + System.arraycopy(super.buf, 0, tmp, 0, super.count); + super.buf = tmp; + } + } + + /** * Write one byte to the stream. * * @param b @@ -102,13 +136,7 @@ public class OtpOutputStream extends ByteArrayOutputStream { * */ public void write(final byte b) { - if (super.count >= super.buf.length) { - // System.err.println("Expanding buffer from " + this.buf.length - // + " to " + (this.buf.length+defaultIncrement)); - final byte[] tmp = new byte[super.buf.length + defaultIncrement]; - System.arraycopy(super.buf, 0, tmp, 0, super.count); - super.buf = tmp; - } + ensureCapacity(super.count + 1); super.buf[super.count++] = b; } @@ -122,14 +150,7 @@ public class OtpOutputStream extends ByteArrayOutputStream { @Override public void write(final byte[] buf) { - if (super.count + buf.length > super.buf.length) { - // System.err.println("Expanding buffer from " + super.buf.length - // + " to " + (buf.length + super.buf.lengt + defaultIncrement)); - final byte[] tmp = new byte[super.buf.length + buf.length - + defaultIncrement]; - System.arraycopy(super.buf, 0, tmp, 0, super.count); - super.buf = tmp; - } + ensureCapacity(super.count + buf.length); System.arraycopy(buf, 0, super.buf, super.count, buf.length); super.count += buf.length; } |