/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.store;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import org.h2.mvstore.MVStore;
import org.h2.test.TestBase;
import org.h2.util.New;
/**
* Tests the performance and memory usage claims in the documentation.
*/
public class TestMVStoreBenchmark extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase test = TestBase.createCaller().init();
test.config.traceTest = true;
test.config.big = true;
test.test();
}
@Override
public void test() throws Exception {
if (!config.big) {
return;
}
if (config.coverage || config.codeCoverage) {
// run only when _not_ using a code coverage tool,
// because the tool might instrument our code but not
// java.util.*
return;
}
testPerformanceComparison();
testMemoryUsageComparison();
}
private void testMemoryUsageComparison() {
long[] mem;
long hash, tree, mv;
String msg;
mem = getMemoryUsed(10000, 10);
hash = mem[0];
tree = mem[1];
mv = mem[2];
msg = Arrays.toString(mem);
assertTrue(msg, hash < mv);
assertTrue(msg, tree < mv);
mem = getMemoryUsed(10000, 30);
hash = mem[0];
tree = mem[1];
mv = mem[2];
msg = Arrays.toString(mem);
assertTrue(msg, mv < hash);
assertTrue(msg, mv < tree);
}
private long[] getMemoryUsed(int count, int size) {
long hash, tree, mv;
ArrayList<Map<Integer, String>> mapList;
long mem;
mapList = New.arrayList();
mem = getMemory();
for (int i = 0; i < count; i++) {
mapList.add(new HashMap<Integer, String>(size));
}
addEntries(mapList, size);
hash = getMemory() - mem;
mapList.size();
mapList = New.arrayList();
mem = getMemory();
for (int i = 0; i < count; i++) {
mapList.add(new TreeMap<Integer, String>());
}
addEntries(mapList, size);
tree = getMemory() - mem;
mapList.size();
mapList = New.arrayList();
mem = getMemory();
MVStore store = MVStore.open(null);
for (int i = 0; i < count; i++) {
Map<Integer, String> map = store.openMap("t" + i);
mapList.add(map);
}
addEntries(mapList, size);
mv = getMemory() - mem;
mapList.size();
trace("hash: " + hash / 1024 / 1024 + " mb");
trace("tree: " + tree / 1024 / 1024 + " mb");
trace("mv: " + mv / 1024 / 1024 + " mb");
return new long[]{hash, tree, mv};
}
private static void addEntries(List<Map<Integer, String>> mapList, int size) {
for (Map<Integer, String> map : mapList) {
for (int i = 0; i < size; i++) {
map.put(i, "Hello World");
}
}
}
static long getMemory() {
try {
LinkedList<byte[]> list = new LinkedList<byte[]>();
while (true) {
list.add(new byte[1024]);
}
} catch (OutOfMemoryError e) {
// ok
}
for (int i = 0; i < 16; i++) {
System.gc();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// ignore
}
}
return getMemoryUsedBytes();
}
private void testPerformanceComparison() {
if (!config.big) {
return;
}
// -mx12g -agentlib:hprof=heap=sites,depth=8
// int size = 1000;
int size = 1000000;
long hash = 0, tree = 0, mv = 0;
for (int i = 0; i < 5; i++) {
Map<Integer, String> map;
MVStore store = MVStore.open(null);
map = store.openMap("test");
mv = testPerformance(map, size);
map = new HashMap<Integer, String>(size);
// map = new ConcurrentHashMap<Integer, String>(size);
hash = testPerformance(map, size);
map = new TreeMap<Integer, String>();
// map = new ConcurrentSkipListMap<Integer, String>();
tree = testPerformance(map, size);
if (hash < tree && mv < tree * 1.5) {
break;
}
}
String msg = "mv " + mv + " tree " + tree + " hash " + hash;
assertTrue(msg, hash < tree);
// assertTrue(msg, hash < mv);
assertTrue(msg, mv < tree * 2);
}
private long testPerformance(Map<Integer, String> map, int size) {
System.gc();
long time = 0;
for (int t = 0; t < 3; t++) {
time = System.nanoTime();
for (int b = 0; b < 3; b++) {
for (int i = 0; i < size; i++) {
map.put(i, "Hello World");
}
for (int a = 0; a < 5; a++) {
for (int i = 0; i < size; i++) {
String x = map.get(i);
assertTrue(x != null);
}
}
for (int i = 0; i < size; i++) {
map.remove(i);
}
assertEquals(0, map.size());
}
time = System.nanoTime() - time;
}
trace(map.getClass().getName() + ": " + TimeUnit.NANOSECONDS.toMillis(time));
return time;
}
}