Converting a byte array to long - a performance test
WARNING: Micro benchmarks are mostly deceiving, if you aren't careful about how to interpret the results. I leave it up to you to interpret these results.
Recently I came across a problem when I had to convert an array of bytes into a long value. The obvious choice was for me to write a bytesToLong method that takes a byte array as an argument and returns a long value. When I dug around a little bit, I found that I could also make use of the ByteBuffer to wrap the bytes and make use of the getLong() method to get the long value.
I was curious to know if there is any performance benefits of going one way or the other. So I wrote a small micro benchmark, and here is the source code and the results:
The results are given below:
The columns are: number of iterations, time taken by the shift version, time taken by the ByteBuffer version, the ratio between the two times.
As you can see, the ByteBuffer version is four times slower than the hand coded version. For my case, this slowness doesn't make any difference. But depending on your application, it may be significant.
Recently I came across a problem when I had to convert an array of bytes into a long value. The obvious choice was for me to write a bytesToLong method that takes a byte array as an argument and returns a long value. When I dug around a little bit, I found that I could also make use of the ByteBuffer to wrap the bytes and make use of the getLong() method to get the long value.
I was curious to know if there is any performance benefits of going one way or the other. So I wrote a small micro benchmark, and here is the source code and the results:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main; | |
import java.nio.ByteBuffer; | |
import java.nio.ByteOrder; | |
/** | |
* The objective is to compute the value of long represented as a sequence of | |
* bytes using ByteBuffer and by shifting, and compare the performance. | |
* | |
*/ | |
public class ByteBufferVersusShifting { | |
public static long usingByteBuffer(ByteBuffer byteBuffer) { | |
return byteBuffer.getLong(0); | |
} | |
public static long usingShifting(byte[] bytes, int offset) { | |
long retVal = 0; | |
retVal |= ((long) bytes[offset + 7] & 0xFF); | |
retVal <<= 8; | |
retVal |= ((long) bytes[offset + 6] & 0xFF); | |
retVal <<= 8; | |
retVal |= ((long) bytes[offset + 5] & 0xFF); | |
retVal <<= 8; | |
retVal |= ((long) bytes[offset + 4] & 0xFF); | |
retVal <<= 8; | |
retVal |= ((long) bytes[offset + 3] & 0xFF); | |
retVal <<= 8; | |
retVal |= ((long) bytes[offset + 2] & 0xFF); | |
retVal <<= 8; | |
retVal |= ((long) bytes[offset + 1] & 0xFF); | |
retVal <<= 8; | |
retVal |= ((long) bytes[offset] & 0xFF); | |
return retVal; | |
} | |
public static long timeIt(Runnable r) throws Exception { | |
long start = System.nanoTime(); | |
r.run(); | |
long end = System.nanoTime(); | |
return (end - start); | |
} | |
public static void main(String[] args) throws Exception { | |
final byte[] bytes = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00 }; | |
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); | |
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); | |
final long niterIncrement = 10000000; | |
// Warm up | |
for (long i = 0; i < 100000; i++) { | |
usingShifting(bytes, 0); | |
} | |
for (long i = 0; i < 100000; i++) { | |
usingByteBuffer(byteBuffer); | |
} | |
for (int j = 1; j <= 20; j++) { | |
final long niter = niterIncrement*j; | |
long shiftingTime = timeIt(new Runnable() { | |
@Override | |
public void run() { | |
for (long i = 0; i < niter; i++) { | |
usingShifting(bytes, 0); | |
} | |
} | |
}); | |
long byteBufferTime = timeIt(new Runnable() { | |
@Override | |
public void run() { | |
for (long i = 0; i < niter; i++) { | |
usingByteBuffer(byteBuffer); | |
} | |
} | |
}); | |
System.out.printf("%12d, %12d, %12d, %.2f\n", niter, shiftingTime, byteBufferTime, (double)byteBufferTime/(double)shiftingTime); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10000000, 19366534, 58864372, 3.04 | |
20000000, 29383997, 95479759, 3.25 | |
30000000, 45976039, 175275721, 3.81 | |
40000000, 57853499, 234138642, 4.05 | |
50000000, 73506767, 291500083, 3.97 | |
60000000, 87584072, 349426518, 3.99 | |
70000000, 103897341, 429060055, 4.13 | |
80000000, 122580223, 526850899, 4.30 | |
90000000, 130561644, 563535489, 4.32 | |
100000000, 149137528, 640108388, 4.29 | |
110000000, 175070814, 749132181, 4.28 | |
120000000, 174716289, 815580080, 4.67 | |
130000000, 213843512, 801949714, 3.75 | |
140000000, 213317584, 848496774, 3.98 | |
150000000, 242967126, 908547475, 3.74 | |
160000000, 267995385, 954222483, 3.56 | |
170000000, 264381898, 1044492618, 3.95 | |
180000000, 274936731, 1137397940, 4.14 | |
190000000, 287273431, 1168334479, 4.07 | |
200000000, 305623557, 1224665920, 4.01 |
Comments