Created
October 6, 2011 02:25
-
-
Save vvuk/1266342 to your computer and use it in GitHub Desktop.
two NIO/Java array benchmarks
This file contains hidden or 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
/* javac ArrayBenchmark.java | |
* java -Xbootclasspath/a:. ArrayBenchmark | |
*/ | |
import java.nio.ByteBuffer; | |
import java.nio.ByteOrder; | |
import java.nio.IntBuffer; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.List; | |
import sun.misc.Cleaner; | |
import sun.misc.Unsafe; | |
class RawBuffer { | |
public static final Unsafe unsafe = Unsafe.getUnsafe(); | |
// order is important | |
final long address; | |
final int sizeBytes; | |
final int size; | |
private static class Deallocator | |
implements Runnable | |
{ | |
private long address; | |
private Deallocator(long address) { | |
this.address = address; | |
} | |
public void run() { | |
if (address == 0) | |
return; | |
unsafe.freeMemory(address); | |
address = 0; | |
} | |
} | |
protected RawBuffer(int sizeBytes, int size) { | |
this.address = unsafe.allocateMemory(sizeBytes); | |
this.sizeBytes = sizeBytes; | |
this.size = size; | |
// use a phantom reference and cleaner to deallocate | |
// the underlying memory, similar to DirectByteBuffer | |
Cleaner.create(this, new Deallocator(address)); | |
} | |
public int size() { | |
return size; | |
} | |
} | |
final class CustomIntBuffer | |
extends RawBuffer | |
{ | |
public static int BYTES_PER_ELEMENT = 4; | |
public CustomIntBuffer(int capacity) { | |
super(capacity * 4, capacity); | |
} | |
public int get(int index) { | |
if (index < 0 || index >= size) | |
throw new IndexOutOfBoundsException(); | |
return unsafe.getInt(address + index*BYTES_PER_ELEMENT); | |
} | |
public int getUnchecked(int index) { | |
return unsafe.getInt(address + index*BYTES_PER_ELEMENT); | |
} | |
public void put(int index, int value) { | |
if (index < 0 || index >= size) | |
throw new IndexOutOfBoundsException(); | |
unsafe.putInt(address + index*BYTES_PER_ELEMENT, value); | |
} | |
public void putUnchecked(int index, int value) { | |
unsafe.putInt(address + index*BYTES_PER_ELEMENT, value); | |
} | |
public void getInto(int[] dest, int origin, int count) { | |
if (origin < 0 || (origin+count) > size) | |
throw new IndexOutOfBoundsException(); | |
long ptr = address + origin * BYTES_PER_ELEMENT; | |
for (int i = 0; i < count; ++i) { | |
dest[i] = unsafe.getInt(ptr); | |
ptr += 4; | |
} | |
} | |
public void getIntoUsingCopyMemory(int[] dest, int origin, int count) { | |
if (origin < 0 || (origin+count) > size) | |
throw new IndexOutOfBoundsException(); | |
long ptr = address + origin * BYTES_PER_ELEMENT; | |
assert Unsafe.ARRAY_INT_INDEX_SCALE == BYTES_PER_ELEMENT; | |
unsafe.copyMemory(null, ptr, | |
dest, Unsafe.ARRAY_INT_BASE_OFFSET, | |
count * BYTES_PER_ELEMENT); | |
} | |
} | |
public class ArrayBenchmark { | |
static int numIterations = 5; | |
public static void main(String[] args) { | |
String test = args.length > 0 ? args[0] : null; | |
final int size = 10 * 1000 * 1000; | |
int check = 0; | |
int[] tempbuf = new int[size]; | |
if (test == null || test.equals("array")) { | |
startTest("native java int[] array"); | |
int[] buf = new int[size]; | |
for (int iteration = 0; iteration < numIterations; ++iteration) { | |
start("put"); | |
for (int i = 0; i < size; ++i) { | |
buf[i] = i; | |
} | |
stop(); | |
start("get"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf[i]; | |
} | |
stop(); | |
start("copy into"); | |
System.arraycopy(buf, 0, tempbuf, 0, size); | |
stop(); | |
} | |
endTest(); | |
} | |
if (test == null || test.equals("heap")) { | |
startTest("nio heap buffers (native byte order, int buffers)"); | |
IntBuffer buf = ByteBuffer.allocate(size * 4).order(ByteOrder.nativeOrder()).asIntBuffer(); | |
for (int iteration = 0; iteration < numIterations; ++iteration) { | |
start("put"); | |
for (int i = 0; i < size; ++i) { | |
buf.put(i, i); | |
} | |
stop(); | |
buf.clear(); | |
start("put (relative)"); | |
for (int i = 0; i < size; ++i) { | |
buf.put(i); | |
} | |
stop(); | |
buf.rewind(); | |
start("get"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf.get(i); | |
} | |
stop(); | |
buf.rewind(); | |
start("get (relative)"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf.get(); | |
} | |
stop(); | |
buf.rewind(); | |
start("copy into"); | |
buf.get(tempbuf); | |
stop(); | |
} | |
endTest(); | |
} | |
if (test == null || test.equals("direct")) { | |
startTest("nio direct buffers (native byte order, int buffers)"); | |
IntBuffer buf = ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder()).asIntBuffer(); | |
for (int iteration = 0; iteration < numIterations; ++iteration) { | |
start("put"); | |
for (int i = 0; i < size; ++i) { | |
buf.put(i, i); | |
} | |
stop(); | |
buf.clear(); | |
start("put (relative)"); | |
for (int i = 0; i < size; ++i) { | |
buf.put(i); | |
} | |
stop(); | |
buf.rewind(); | |
start("get"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf.get(i); | |
} | |
stop(); | |
buf.rewind(); | |
start("get (relative)"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf.get(); | |
} | |
stop(); | |
buf.rewind(); | |
start("copy into"); | |
buf.get(tempbuf); | |
stop(); | |
} | |
endTest(); | |
} | |
if (test == null || test.equals("fast")) { | |
startTest("custom buffers"); | |
CustomIntBuffer buf = new CustomIntBuffer(size); | |
for (int iteration = 0; iteration < numIterations; ++iteration) { | |
start("put"); | |
for (int i = 0; i < size; ++i) { | |
buf.put(i, i); | |
} | |
stop(); | |
start("put unchecked"); | |
for (int i = 0; i < size; ++i) { | |
buf.putUnchecked(i, i); | |
} | |
stop(); | |
start("get"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf.get(i); | |
} | |
stop(); | |
start("get unchecked"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf.getUnchecked(i); | |
} | |
stop(); | |
start("copy into"); | |
buf.getInto(tempbuf, 0, size); | |
stop(); | |
start("copy into (copyMemory)"); | |
buf.getIntoUsingCopyMemory(tempbuf, 0, size); | |
stop(); | |
} | |
endTest(); | |
} | |
if (test == null || test.equals("mixed")) { | |
startTest("mixed int[] and direct"); | |
int[] buf = new int[size]; | |
IntBuffer dbuf = ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder()).asIntBuffer(); | |
for (int iteration = 0; iteration < numIterations; ++iteration) { | |
start("put-[]"); | |
for (int i = 0; i < size; ++i) { | |
buf[i] = i; | |
} | |
stop(); | |
start("put-direct"); | |
for (int i = 0; i < size; ++i) { | |
dbuf.put(i, i); | |
} | |
stop(); | |
dbuf.clear(); | |
start("put-direct (relative)"); | |
for (int i = 0; i < size; ++i) { | |
dbuf.put(i); | |
} | |
stop(); | |
dbuf.rewind(); | |
start("get-[]"); | |
for (int i = 0; i < size; ++i) { | |
check |= buf[i]; | |
} | |
stop(); | |
start("get-direct"); | |
for (int i = 0; i < size; ++i) { | |
check |= dbuf.get(i); | |
} | |
stop(); | |
dbuf.rewind(); | |
start("get-direct (relative)"); | |
for (int i = 0; i < size; ++i) { | |
check |= dbuf.get(); | |
} | |
stop(); | |
} | |
endTest(); | |
} | |
System.out.printf("check = %d\n", check); // to ensure hotspot doesn't optimize out inner read loops | |
} | |
static long timeStart; | |
static String timeDesc; | |
static HashMap<String, Long> resultMap; | |
public static void startTest(String testName) { | |
System.out.printf("===== %s\n", testName); | |
resultMap = new HashMap<String, Long>(); | |
} | |
public static void start(String desc) { | |
timeDesc = desc; | |
timeStart = System.nanoTime(); | |
} | |
public static void stop() { | |
long elapsed = System.nanoTime() - timeStart; | |
Long current = resultMap.get(timeDesc); | |
if (current == null) { | |
// throw away first result, to give the jit a chance to compile | |
resultMap.put(timeDesc, 0L); | |
} else { | |
resultMap.put(timeDesc, current + elapsed); | |
} | |
// System.out.printf("%30s: %f ms\n", timeDesc, elapsed / 1000000.0); | |
} | |
public static void endTest() { | |
List<String> keys = new ArrayList(resultMap.keySet()); | |
Collections.sort(keys); | |
for (String key : keys) { | |
Long value = resultMap.get(key); | |
System.out.printf("%30s: %f ms\n", key, value / ((numIterations - 1) * 1000000.0)); | |
} | |
} | |
} |
This file contains hidden or 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
import java.nio.*; | |
public class niotest | |
{ | |
public static void main(String[] asArg) | |
{ | |
final int MB = 1000 * 1000; | |
IntBuffer buf = ByteBuffer.allocateDirect(4 * 10 * MB).order(ByteOrder.nativeOrder()).asIntBuffer(); | |
int cbMax = buf.capacity(); | |
int[] ab = new int[cbMax]; | |
int x = 0; | |
// how many times to run the test (to allow hotspot to optimize) | |
int cIters = 10; | |
for (int i = 1; i <= cIters; ++i) | |
{ | |
System.out.println("*** iteration " + i); | |
start("array[]: populating"); | |
for (int of = 0; of < cbMax; ++of) | |
{ | |
ab[of] = of; | |
} | |
stop(); | |
buf.rewind(); | |
start("direct buffer: absolute populating"); | |
for (int of = 0; of < cbMax; ++of) | |
{ | |
buf.put(of, of); | |
} | |
stop(); | |
buf.rewind(); | |
start("direct buffer: relative populating"); | |
for (int of = 0; of < cbMax; ++of) | |
{ | |
buf.put(of, of); | |
} | |
stop(); | |
start("array[]: accessing"); | |
for (int of = 0; of < cbMax; ++of) | |
{ | |
x |= ab[of]; | |
} | |
stop(); | |
buf.rewind(); | |
start("direct buffer: absolute accessing"); | |
for (int of = 0; of < cbMax; ++of) | |
{ | |
x |= buf.get(of); | |
} | |
stop(); | |
buf.rewind(); | |
start("direct buffer: relative accessing"); | |
for (int of = 0; of < cbMax; ++of) | |
{ | |
x |= buf.get(); | |
} | |
stop(); | |
} | |
// to avoid hotspot completely discarding some of the loops, | |
// by using the variable "x" it can't optimize out the access | |
// inside the loop | |
System.out.println("*** Test completed (x=" + x + ")"); | |
} | |
/** | |
* Start a test. | |
* | |
* @param sDesc the test description | |
*/ | |
public static void start(String sDesc) | |
{ | |
s_sDesc = sDesc; | |
s_lStart = System.currentTimeMillis(); | |
} | |
/** | |
* Finish a test and print the elapsed time. | |
*/ | |
public static void stop() | |
{ | |
long lStop = System.currentTimeMillis(); | |
System.out.println(s_sDesc + "=" + (lStop - s_lStart) + "ms"); | |
} | |
/** | |
* Time at which the current test started. | |
*/ | |
static long s_lStart; | |
/** | |
* Description of the current test. | |
*/ | |
static String s_sDesc; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment