/* * Copyright 2015 Goldman Sachs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.impl.memory.map; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import com.carrotsearch.hppc.Containers; import com.carrotsearch.hppc.ObjectObjectHashMap; import com.carrotsearch.hppc.ObjectObjectMap; import com.gs.collections.api.block.function.Function0; import com.gs.collections.api.block.procedure.Procedure; import com.gs.collections.api.list.ImmutableList; import com.gs.collections.impl.map.mutable.UnifiedMap; import com.gs.collections.impl.memory.MemoryTestBench; import com.gs.collections.impl.memory.TestDataFactory; import gnu.trove.impl.Constants; import gnu.trove.map.hash.THashMap; import net.openhft.koloboke.collect.map.hash.HashObjObjMap; import net.openhft.koloboke.collect.map.hash.HashObjObjMaps; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import scala.collection.mutable.AnyRefMap; import scala.collection.mutable.HashTable; public class MapMemoryTest { private static final Logger LOGGER = LoggerFactory.getLogger(MapMemoryTest.class); @Test public void memoryForScaledMaps() { LOGGER.info( "Comparing Items: Scala {}, JDK {}, Trove {}, Trove Presized {}, GSC {}, JDK {}, HPPC {}, Koloboke {}, Scala {}", scala.collection.mutable.HashMap.class.getSimpleName(), HashMap.class.getSimpleName(), THashMap.class.getSimpleName(), THashMap.class.getSimpleName(), UnifiedMap.class.getSimpleName(), Hashtable.class.getSimpleName(), ObjectObjectMap.class.getSimpleName(), HashObjObjMap.class.getSimpleName(), AnyRefMap.class.getSimpleName() ); for (int size = 0; size < 1000001; size += 25000) { this.memoryForScaledMaps(size); } LOGGER.info("Ending test: {}", this.getClass().getName()); } public void memoryForScaledMaps(int size) { Float[] chainingLoadFactors = {0.70f, 0.75f, 0.80f}; for (Float loadFactor : chainingLoadFactors) { String suffix = "_loadFactor=" + loadFactor; MemoryTestBench.on(scala.collection.mutable.HashMap.class, suffix) .printContainerMemoryUsage("Map", size, new ScalaHashMapFactory(size, loadFactor)); MemoryTestBench.on(HashMap.class, suffix) .printContainerMemoryUsage("Map", size, new HashMapFactory(size, loadFactor)); MemoryTestBench.on(UnifiedMap.class, suffix) .printContainerMemoryUsage("Map", size, new UnifiedMapFactory(size, loadFactor)); MemoryTestBench.on(Hashtable.class, suffix) .printContainerMemoryUsage("Map", size, new HashtableFactory(size, loadFactor)); MemoryTestBench.on(ObjectObjectHashMap.class, suffix) .printContainerMemoryUsage("Map", size, new HppcMapFactory(size, loadFactor)); } Float[] openAddressingLoadFactors = {0.45f, 0.50f, 0.55f}; for (Float loadFactor : openAddressingLoadFactors) { String suffix = "_loadFactor=" + loadFactor; MemoryTestBench.on(THashMap.class, suffix) .printContainerMemoryUsage("Map", size, new THashMapFactory(size, loadFactor)); MemoryTestBench.on(THashMap.class, suffix + "_presized") .printContainerMemoryUsage("Map", size, new PresizedTHashMapFactory(size, loadFactor)); } MemoryTestBench.on(HashObjObjMap.class) .printContainerMemoryUsage("Map", size, new KolobokeMapFactory(size)); MemoryTestBench.on(AnyRefMap.class) .printContainerMemoryUsage("Map", size, new ScalaAnyRefMapFactory(size)); } public abstract static class SizedMapFactory { protected final int size; protected final float loadFactor; protected final ImmutableList<Integer> data; protected SizedMapFactory(int size, float loadFactor) { this.size = size; this.loadFactor = loadFactor; this.data = TestDataFactory.createRandomImmutableList(this.size); } protected <R extends Map<Integer, String>> R fill(final R map) { this.data.forEach(new Procedure<Integer>() { public void value(Integer each) { map.put(each, "dummy"); } }); return map; } } private static final class ScalaHashMapFactory extends SizedMapFactory implements Function0<scala.collection.mutable.HashMap<Integer, String>> { private ScalaHashMapFactory(int size, float loadFactor) { super(size, loadFactor); } @Override public scala.collection.mutable.HashMap<Integer, String> value() { /** * @see HashTable#initialSize() */ int defaultInitialSize = 16; final scala.collection.mutable.HashMap<Integer, String> map = new PresizableHashMap<>(defaultInitialSize, (int) (this.loadFactor * 1000)); this.data.forEach(new Procedure<Integer>() { public void value(Integer each) { map.put(each, "dummy"); } }); return map; } } private static final class HashMapFactory extends SizedMapFactory implements Function0<HashMap<Integer, String>> { private HashMapFactory(int size, float loadFactor) { super(size, loadFactor); } @Override public HashMap<Integer, String> value() { /** * @see HashMap#DEFAULT_INITIAL_CAPACITY */ int defaultInitialCapacity = 16; HashMap<Integer, String> map = new HashMap<>(defaultInitialCapacity, this.loadFactor); return this.fill(map); } } private static final class THashMapFactory extends SizedMapFactory implements Function0<THashMap<Integer, String>> { private THashMapFactory(int size, float loadFactor) { super(size, loadFactor); } @Override public THashMap<Integer, String> value() { return this.fill(new THashMap<Integer, String>(Constants.DEFAULT_CAPACITY, this.loadFactor)); } } private static final class PresizedTHashMapFactory extends SizedMapFactory implements Function0<THashMap<Integer, String>> { private PresizedTHashMapFactory(int size, float loadFactor) { super(size, loadFactor); } @Override public THashMap<Integer, String> value() { return this.fill(new THashMap<Integer, String>(this.size, this.loadFactor)); } } private static final class HashtableFactory extends SizedMapFactory implements Function0<Hashtable<Integer, String>> { private HashtableFactory(int size, float loadFactor) { super(size, loadFactor); } @Override @SuppressWarnings("UseOfObsoleteCollectionType") public Hashtable<Integer, String> value() { /** * @see Hashtable#Hashtable() */ int defaultSize = 11; Hashtable<Integer, String> map = new Hashtable<>(defaultSize, this.loadFactor); return this.fill(map); } } private static final class UnifiedMapFactory extends SizedMapFactory implements Function0<UnifiedMap<Integer, String>> { private UnifiedMapFactory(int size, float loadFactor) { super(size, loadFactor); } @Override public UnifiedMap<Integer, String> value() { /** * @see UnifiedMap#DEFAULT_INITIAL_CAPACITY */ int defaultSize = 8; UnifiedMap<Integer, String> map = new UnifiedMap<Integer, String>(defaultSize, this.loadFactor); return this.fill(map); } } private static final class HppcMapFactory extends SizedMapFactory implements Function0<ObjectObjectMap<Integer, String>> { private HppcMapFactory(int size, float loadFactor) { super(size, loadFactor); } @Override public ObjectObjectMap<Integer, String> value() { final ObjectObjectMap<Integer, String> map = new ObjectObjectHashMap<>(Containers.DEFAULT_EXPECTED_ELEMENTS, this.loadFactor); this.data.forEach(new Procedure<Integer>() { public void value(Integer each) { map.put(each, "dummy"); } }); return map; } } private static final class KolobokeMapFactory extends SizedMapFactory implements Function0<HashObjObjMap<Integer, String>> { private KolobokeMapFactory(int size) { super(size, 0.0f); } @Override public HashObjObjMap<Integer, String> value() { return this.fill(HashObjObjMaps.<Integer, String>newMutableMap()); } } private static final class ScalaAnyRefMapFactory extends SizedMapFactory implements Function0<AnyRefMap<Integer, String>> { private ScalaAnyRefMapFactory(int size) { super(size, 0.0f); } @Override public AnyRefMap<Integer, String> value() { final AnyRefMap<Integer, String> map = new AnyRefMap<>(); this.data.forEach(new Procedure<Integer>() { public void value(Integer each) { map.put(each, "dummy"); } }); return map; } } }