package com.googlecode.totallylazy.collections; import com.googlecode.totallylazy.functions.Function1; import com.googlecode.totallylazy.functions.Function0; import com.googlecode.totallylazy.Maps; import com.googlecode.totallylazy.Sequence; import com.googlecode.totallylazy.functions.Time0; import com.googlecode.totallylazy.functions.TimeReport; import org.junit.Ignore; import org.junit.Test; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import static com.googlecode.totallylazy.Pair.pair; import static com.googlecode.totallylazy.Sequences.repeat; import static com.googlecode.totallylazy.Sequences.sequence; import static com.googlecode.totallylazy.collections.PersistentSortedMapTest.asPair; import static com.googlecode.totallylazy.matchers.IterableMatcher.startsWith; import static com.googlecode.totallylazy.matchers.Matchers.is; import static com.googlecode.totallylazy.numbers.Numbers.range; import static org.hamcrest.MatcherAssert.assertThat; @Ignore("Manual Performance Tests") public class MapPerformanceTest { public static final int SIZE = 100000; public static final int NUMBER_OF_CALLS = 1000; public static final Sequence<Integer> range = range(1, SIZE).safeCast(Integer.class).realise(); public static final Sequence<Integer> keys_ = range.shuffle().cycle().memorise(); @Test public void iterateWorksOnLargeData() throws Exception { assertThat(createPersistent(range), startsWith(sequence(pair(1, 1), pair(2, 2), pair(3, 3)))); } @Test public void getIsPrettyQuick() throws Exception { for (int i = 0; i < 10; i++) { System.out.println(TimeReport.time(NUMBER_OF_CALLS, persistentGet(createPersistent(range)))); System.out.println(TimeReport.time(NUMBER_OF_CALLS, persistentGet(createHash(range)))); System.out.println(TimeReport.time(NUMBER_OF_CALLS, mutableGet(createMutable(range, new HashMap<Integer, Integer>())))); System.out.println(TimeReport.time(NUMBER_OF_CALLS, mutableGet(createMutable(range, new java.util.TreeMap<Integer, Integer>())))); System.out.println(TimeReport.time(NUMBER_OF_CALLS, mutableGet(createMutable(range, new ConcurrentSkipListMap<Integer, Integer>(), "CSLMap ")))); System.out.println(TimeReport.time(NUMBER_OF_CALLS, mutableGet(createMutable(range, new ConcurrentHashMap<Integer, Integer>(), "CHMap ")))); System.out.println(""); } } @Test public void removeIsQuick() throws Exception { System.out.println("SIZE = " + SIZE); TimeReport hashMapReport = new TimeReport(); TimeReport treeMapReport = new TimeReport(); TimeReport cslMapReport = new TimeReport(); TimeReport avlTreeReport = new TimeReport(); TimeReport hashTreeReport = new TimeReport(); Map<Integer, Integer> hashMap = createMutable(range, new HashMap<Integer, Integer>()); Map<Integer, Integer> treeMap = createMutable(range, new java.util.TreeMap<Integer, Integer>()); Map<Integer, Integer> cslMap = createMutable(range, new ConcurrentSkipListMap<Integer, Integer>(), "CSLMap "); PersistentMap<Integer, Integer> avlTree = createPersistent(range); PersistentMap<Integer, Integer> hashTreeMap = createHash(range); for (int i = 0; i < 100; i++) { timeRemove(NUMBER_OF_CALLS, hashMap, hashMapReport); timeRemove(NUMBER_OF_CALLS, treeMap, treeMapReport); timeRemove(NUMBER_OF_CALLS, cslMap, cslMapReport); time(NUMBER_OF_CALLS, removePersistent(avlTree), avlTreeReport); time(NUMBER_OF_CALLS, removePersistent(hashTreeMap), hashTreeReport); } assertThat(hashMap.size(), is(SIZE)); assertThat(treeMap.size(), is(SIZE)); assertThat(cslMap.size(), is(SIZE)); assertThat(avlTree.size(), is(SIZE)); assertThat(hashTreeMap.size(), is(SIZE)); System.out.println(); System.out.println("HashMap: " + hashMapReport); System.out.println("TreeMap: " + treeMapReport); System.out.println("CSLMap: " + cslMapReport); System.out.println("AvlTree: " + avlTreeReport); System.out.println("HashTree: " + hashTreeReport); } @Test public void putIsQuick() throws Exception { System.out.println("SIZE = " + SIZE); TimeReport hashMapReport = new TimeReport(); TimeReport treeMapReport = new TimeReport(); TimeReport cslMapReport = new TimeReport(); TimeReport avlTreeReport = new TimeReport(); TimeReport hashTreeReport = new TimeReport(); Map<Integer, Integer> hashMap = createMutable(range, new HashMap<Integer, Integer>()); Map<Integer, Integer> treeMap = createMutable(range, new java.util.TreeMap<Integer, Integer>()); Map<Integer, Integer> cslMap = createMutable(range, new ConcurrentSkipListMap<Integer, Integer>(), "CSLMap "); PersistentMap<Integer, Integer> avlTree = createHash(range); PersistentMap<Integer, Integer> hashTreeMap = createHash(range); for (int i = 0; i < 100; i++) { timePut(NUMBER_OF_CALLS, hashMap, hashMapReport); timePut(NUMBER_OF_CALLS, treeMap, treeMapReport); timePut(NUMBER_OF_CALLS, cslMap, cslMapReport); time(NUMBER_OF_CALLS, persistentPut(avlTree), avlTreeReport); time(NUMBER_OF_CALLS, persistentPut(hashTreeMap), hashTreeReport); } assertThat(hashMap.size(), is(SIZE)); assertThat(treeMap.size(), is(SIZE)); assertThat(cslMap.size(), is(SIZE)); assertThat(avlTree.size(), is(SIZE)); assertThat(hashTreeMap.size(), is(SIZE)); System.out.println(); System.out.println("HashMap: " + hashMapReport); System.out.println("TreeMap: " + treeMapReport); System.out.println("CSLMap: " + cslMapReport); System.out.println("AvlTree: " + avlTreeReport); System.out.println("HashTree: " + hashTreeReport); } @SuppressWarnings("unchecked") private Callable<Object> persistentGet(final PersistentMap<Integer, Integer> map) { return () -> map.lookup(keys().head()); } private Sequence<Integer> keys() { return keys_.forwardOnly(); } @SuppressWarnings("unchecked") private Callable<Object> mutableGet(final Map<Integer, Integer> mutable) { return () -> Maps.get(mutable, keys().head()); } private Map<Integer, Integer> createMutable(final Sequence<Integer> range, final Map<Integer, Integer> emptyMap) throws Exception { return createMutable(range, emptyMap, emptyMap.getClass().getSimpleName()); } private Map<Integer, Integer> createMutable(Sequence<Integer> range, Map<Integer, Integer> emptyMap, String name) { System.out.print(name + ":\t"); return range.fold(emptyMap, (map, integer) -> { map.put(integer, integer); return map; }); } private Callable<PersistentMap<Integer, Integer>> removePersistent(final PersistentMap<Integer, Integer> persistent) { return () -> persistent.delete(keys().head()); } public static TimeReport time(int numberOfCalls, Callable<?> callable, final TimeReport report) { repeat(Time0.time(callable, report)).take(numberOfCalls).realise(); return report; } private TimeReport timeRemove(int count, final Map<Integer, Integer> map, final TimeReport report) { repeat(mutableRemove(map).time(report).then(putValueBack(map))).take(count).realise(); return report; } private TimeReport timePut(int count, final Map<Integer, Integer> map, final TimeReport report) { repeat(mutablePut(map).time(report).then(remove(map))).take(count).realise(); return report; } private Function1<Integer, Integer> remove(final Map<Integer, Integer> map) { return map::remove; } private Function1<Integer, Integer> putValueBack(final Map<Integer, Integer> map) { return key -> map.put(key, key); } private Function0<Integer> mutableRemove(final Map<Integer, Integer> map) { return () -> map.remove(keys().head()); } private Callable<PersistentMap<Integer, Integer>> persistentPut(final PersistentMap<Integer, Integer> avlTree) { return () -> { Integer head = keys().head(); return avlTree.insert(head, head); }; } private Function0<Integer> mutablePut(final Map<Integer, Integer> map) { return () -> { Integer head = SIZE + 1; map.put(head, head); return head; }; } public static PersistentSortedMap<Integer, Integer> createPersistent(final Sequence<Integer> range) throws Exception { PersistentSortedMap<Integer, Integer> map = PersistentSortedMap.constructors.sortedMap(range.map(asPair())); System.out.print("AVLTree:\t"); return map; } public static PersistentMap<Integer, Integer> createHash(final Sequence<Integer> range) throws Exception { HashTreeMap<Integer, Integer> map = HashTreeMap.hashTreeMap(range.map(asPair())); System.out.print("HashTreeMap:\t"); return map; } }