Ver código fonte

new: RuntimeUtils
change: LoggerUtils # invokedInsideMaven - moved to RuntimeUtils
change: LoggerUtils # invokedInsideSingleTest - moved to RuntimeUtils

new: Cache # hold
new: Cache # holdsize
fix: Cache - constructor check arguments

change: Numeric#format - support long

test: Cache

Ranides Atterwim 11 anos atrás
pai
commit
7f1b8efd04

+ 1 - 1
pom.xml

@@ -5,7 +5,7 @@
 
     <groupId>net.ranides</groupId>
     <artifactId>assira</artifactId>
-    <version>0.71.0</version>
+    <version>0.71.1</version>
     <packaging>jar</packaging>
 
     <name>assira</name>

+ 47 - 8
src/main/java/net/ranides/assira/collection/map/Cache.java

@@ -34,6 +34,9 @@ import java.util.Set;
  * do obiektów: nawet odczyt zmienia wewnętrzną reprezentację. W efekcie, jeśli 
  * podczas iteracji zostanie wywołana jakakolwiek inna metoda, to zostanie rzucone 
  * ConcurentModificationException. 
+ * 
+ * @todo (assira #8) issue: holdlist contains duplicate entries
+ *        if you invoke #get(key) x times, it will put x "key" entries inside list
  * </p>
  * <div class="message-note">thread-safe class</div>
  * @param <K> 
@@ -80,6 +83,9 @@ public class Cache<K,V> extends AbstractMap<K,V> {
      * @param holdsize ilość elementów chronionych przed GC
      */
     public Cache(int cachesize, int holdsize) {
+        if( cachesize < holdsize ) {
+            throw new IllegalArgumentException("cachesize must be greater or equal to holdsize");
+        }
         this.list   = new CacheList<>(Math.max(1,holdsize));
         this.map    = new CacheMap<>(cachesize);
         this.view   = new CacheView<>(map);
@@ -149,6 +155,39 @@ public class Cache<K,V> extends AbstractMap<K,V> {
         return map.size();
     }
     
+    /**
+     * Returns number of holded entries
+     * Please note, that holdlist could contain duplicated entries, 
+     * so returned number could be deceptively greater than size of map. 
+     * @return
+     */
+    public synchronized int holdsize() {
+        release();
+        return list.size();
+    }
+    
+    /**
+     * Holds value specified by key
+     * @param key
+     * @return 
+     */
+    public synchronized boolean hold(K key) {
+        return null != get(key);
+    }
+    
+    /**
+     * Holds as many entries as possible
+     * @return number of holded values
+     */
+    public synchronized int hold() {
+        for(V value : values() ) {
+            if(null != value) {
+                list.hold(value);
+            }
+        }
+        return list.size();
+    }
+    
     @Override
     public Set<Entry<K,V>> entrySet() {
         release();
@@ -183,9 +222,9 @@ public class Cache<K,V> extends AbstractMap<K,V> {
     
     private static class ReferenceEntry<KT,VT> extends SoftReference<VT> {
         
-        final KT key;
+        private final KT key;
 
-        ReferenceEntry(KT key, VT value, ReferenceQueue<VT> queue) {
+        public ReferenceEntry(KT key, VT value, ReferenceQueue<VT> queue) {
             super(value, queue);
             this.key = key;
         }
@@ -193,9 +232,9 @@ public class Cache<K,V> extends AbstractMap<K,V> {
     
     private static class CacheMap<TK,TV> extends LinkedHashMap<TK, Reference<TV>> {
         
-        final int maxsize;
+        private final int maxsize;
 
-        CacheMap(int maxsize) {
+        public CacheMap(int maxsize) {
             super( ic(maxsize), 0.75f, true);
             this.maxsize = maxsize;
         }
@@ -213,13 +252,13 @@ public class Cache<K,V> extends AbstractMap<K,V> {
     
     private static class CacheList<TV> extends LinkedList<TV> {
         
-        final int maxsize;
+        private final int maxsize;
 
-        CacheList(int maxsize) {
+        public CacheList(int maxsize) {
             this.maxsize = maxsize;
         }
         
-        void hold(TV value) {
+        public void hold(TV value) {
             addFirst(value);
             if (size() > maxsize) { removeLast(); }
         }
@@ -228,7 +267,7 @@ public class Cache<K,V> extends AbstractMap<K,V> {
     
     private static class CacheView<TK,TV> extends MapAdapter<TK, Reference<TV>, TV> {
 
-        CacheView(Map<TK, Reference<TV>> content) {
+        public CacheView(Map<TK, Reference<TV>> content) {
             super(content);
         }
 

+ 2 - 2
src/main/java/net/ranides/assira/math/Numeric.java

@@ -144,9 +144,9 @@ public final class Numeric {
         return value;
     }
 
-    public static String format(int value) {
+    public static String format(long value) {
         StringBuilder ret = new StringBuilder();
-        String text = Integer.toString(value, 10);
+        String text = Long.toString(value, 10);
         for(int i=0, n=text.length()-1; i<=n; i++) {
             ret.append(text.charAt(i));
             if( n>i && ((n-i)%3 == 0) ) {

+ 87 - 0
src/main/java/net/ranides/assira/system/RuntimeUtils.java

@@ -0,0 +1,87 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.system;
+
+import java.util.LinkedList;
+import java.util.List;
+import net.ranides.assira.generic.PrivilegedActions;
+import net.ranides.assira.math.MathUtils;
+import net.ranides.assira.math.Numeric;
+import net.ranides.assira.trace.AdvLogger;
+import net.ranides.assira.trace.LoggerUtils;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class RuntimeUtils {
+    
+    private static final AdvLogger LOGGER = LoggerUtils.getLogger();
+    
+    private RuntimeUtils() {
+        // utility class
+    }
+    
+    public static long getMemoryUse() {
+        Runtime runtime = Runtime.getRuntime();
+        return runtime.totalMemory() - runtime.freeMemory();
+    }
+    
+    
+    /**
+     * Runs the garbage collector. 
+     * @return 
+     *      Estimated amount of memory released by GC
+     *      
+     */
+    public static long performGC() {
+        long prev = getMemoryUse();
+        Runtime.getRuntime().gc();
+        return prev - getMemoryUse();
+    }
+    
+    /**
+     * Forces releasing {@code SoftReferences}, by causing OutOfMemoryError in VM.
+     * @return 
+     *      Estimated amount of memory released by GC
+     */
+    public static long forceGC() {
+        long prev = getMemoryUse();
+        try {
+            final List<long[]> memhog = new LinkedList<>();
+            while(true) {
+                memhog.add(new long[102400]);
+            }
+        }
+        catch(final OutOfMemoryError e) {
+            // at this point all SoftReferences have been released - GUARANTEED
+            long alloc = getMemoryUse() - prev;
+            LOGGER.fdebug("Forced OutOfMemoryError by allocation %s bytes", Numeric.format(alloc));
+            Runtime.getRuntime().gc();
+            // at this point we should use minimal amount of memory
+            return prev - getMemoryUse();
+        }
+    }
+    
+    
+    public static boolean invokedInsideMaven() {
+        for(StackTraceElement item : new Exception().getStackTrace()) {
+            if( item.getClassName().contains("org.apache.maven.surefire.junit4.JUnit4TestSet") ) { return true; }
+        }
+        return false;
+    }
+
+    public static boolean invokedInsideSingleTest() {
+        return Li.SINGLE_TEST;
+    }
+    
+    private static final class Li { // lazy init idiom
+        
+        private static final boolean SINGLE_TEST = PrivilegedActions.getProperty("test") != null;
+        
+    }
+}

+ 8 - 0
src/main/java/net/ranides/assira/time/TimeUtils.java

@@ -54,6 +54,14 @@ public class TimeUtils {
         return new SimpleDateFormat(format, Locale.ROOT).format(date);
     }
 
+    /**
+     * Use caliper library instead
+     * @param repeats
+     * @param function
+     * @return
+     * @deprecated
+     */
+    @Deprecated
     public static TimeResult benchmark(int repeats, Runnable function) {
         TimeStack timer = new TimeStack();
         Runnable empty = new Runnable(){ @Override public void run() { /* do nothing */ } };

+ 3 - 15
src/main/java/net/ranides/assira/trace/LoggerUtils.java

@@ -13,6 +13,7 @@ import java.util.Locale;
 import java.util.Map;
 import net.ranides.assira.generic.PrivilegedActions;
 import net.ranides.assira.reflection.AutoConstructor;
+import net.ranides.assira.system.RuntimeUtils;
 
 /**
  *
@@ -20,8 +21,6 @@ import net.ranides.assira.reflection.AutoConstructor;
  */
 public final class LoggerUtils {
 
-    private static final boolean SINGLE_TEST = PrivilegedActions.getProperty("test") != null;
-
     private static final Map<String, AdvLogger> CACHE = new HashMap<>();
 
     private static final org.apache.log4j.Appender APPENDER = new org.apache.log4j.ConsoleAppender(new org.apache.log4j.PatternLayout("%d %p [%c %M] %m%n"), "System.out");
@@ -42,7 +41,7 @@ public final class LoggerUtils {
     }
 
     public static void initTest() {
-        resetLogger4j(SINGLE_TEST);
+        resetLogger4j(RuntimeUtils.invokedInsideSingleTest());
     }
 
     public static java.util.logging.Logger resetJavaLogger(boolean enable) {
@@ -97,17 +96,6 @@ public final class LoggerUtils {
 
     }
 
-    public static boolean invokedInsideMaven() {
-        for(StackTraceElement item : new Exception().getStackTrace()) {
-            if( item.getClassName().contains("org.apache.maven.surefire.junit4.JUnit4TestSet") ) { return true; }
-        }
-        return false;
-    }
-
-    public static boolean invokedInsideSingleTest() {
-        return SINGLE_TEST;
-    }
-
     /**
      * Działa tylko wtedy, jeśli ustawiona jest zmienna systemowa "test".
      * W praktyce oznacza to, że działa wtedy, gdy uruchomiono <b>pojedynczny</b>
@@ -119,7 +107,7 @@ public final class LoggerUtils {
      */
     @SuppressWarnings({"PMD.SystemPrintln", "NP_ALWAYS_NULL"})
     public static void dump(Locale locale, String format, Object... args) {
-        if(SINGLE_TEST) {
+        if(RuntimeUtils.invokedInsideSingleTest()) {
             System.out.print(new Formatter().format(locale, format, args).toString());
         }
     }

+ 106 - 7
src/test/java/net/ranides/assira/collection/map/CacheTest.java

@@ -17,8 +17,11 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import net.ranides.assira.collection.CollectionUtils;
+import net.ranides.assira.math.Randomizer;
+import net.ranides.assira.system.RuntimeUtils;
+import net.ranides.assira.trace.LoggerUtils;
+import org.apache.log4j.Level;
 import static org.junit.Assert.*;
-import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -27,22 +30,23 @@ import org.junit.Test;
  */
 public class CacheTest {
     
-    private Map<Integer, String> cache;
-    
     public CacheTest() {
+        LoggerUtils.resetLogger4j(Level.WARN);
     }
     
-    @Before
-    public void createMap() {
+    public Cache<Integer, String> createPMap() {
         // tworzymy cache, który chroni wszystkie swoje elementy przed GC
-        cache = new Cache<>(32);
+        Cache<Integer, String> cache = new Cache<>(32);
         for(int i=0; i<48; i++) {
             cache.put(i, "BNGV-"+i);
         }
+        return cache;
     }
 
     @Test
     public void testContainsKey() {
+        Cache<Integer, String> cache = createPMap();
+        
         assertFalse( cache.containsKey(5) );
         assertFalse( cache.containsKey(12) );
         assertFalse( cache.containsKey(15) );
@@ -50,11 +54,11 @@ public class CacheTest {
         assertTrue( cache.containsKey(16) );
         assertTrue( cache.containsKey(30) );
         assertTrue( cache.containsKey(47) );
-        
     }
 
     @Test
     public void testGet() {
+        Cache<Integer, String> cache = createPMap();
         assertNull( cache.get(5) );
         assertNull( cache.get(12) );
         assertNull( cache.get(15) );
@@ -66,6 +70,7 @@ public class CacheTest {
 
     @Test
     public void testRemove() {
+        Cache<Integer, String> cache = createPMap();
         assertTrue( cache.containsKey(32) );
         cache.remove(32);
         assertFalse( cache.containsKey(32) );
@@ -77,6 +82,7 @@ public class CacheTest {
 
     @Test
     public void testClear() {
+        Cache<Integer, String> cache = createPMap();
         cache.clear();
         assertEquals(0, cache.size());
         assertFalse( cache.containsKey(16) );
@@ -86,11 +92,14 @@ public class CacheTest {
 
     @Test
     public void testSize() {
+        Cache<Integer, String> cache = createPMap();
         assertEquals(32, cache.size());
     }
 
     @Test
     public void testEntrySet() {
+        Cache<Integer, String> cache = createPMap();
+        
         Set<Entry<Integer,String>> entries = cache.entrySet();
         assertEquals(cache.size(), entries.size());
         
@@ -118,6 +127,8 @@ public class CacheTest {
 
     @Test
     public void testKeySet() {
+        Cache<Integer, String> cache = createPMap();
+        
         Set<Integer> keys = cache.keySet();
         assertEquals(cache.size(), keys.size());
         
@@ -143,6 +154,8 @@ public class CacheTest {
 
     @Test
     public void testValues() {
+        Cache<Integer, String> cache = createPMap();
+        
         Collection<String> values = cache.values();
         assertEquals(cache.size(), values.size());
         
@@ -168,4 +181,90 @@ public class CacheTest {
         assertEquals(copy1.size() / 2, cache.size());
     }
     
+    @Test
+    public void testRelease() {
+        // we created that cache to check as much things as possible in one method
+        // we don't want to run "forceGC" more than once, because its very costly
+        Cache<Integer, String> cache0 = new Cache<>(32);
+        
+        Cache<Integer, String> cache = new Cache<>(128, 16);
+        for(int i=0; i<256; i++) {
+            cache0.put(i, Randomizer.text(32));
+            cache.put(i, Randomizer.text(32));
+        }
+        
+        assertEquals(32, cache0.hold());
+        
+        // we should have only last 128 elements
+        assertEquals(128, cache.size());
+        // we should not hold anything (we didn't make any access till now)
+        assertEquals(0, cache.holdsize());
+        
+        assertFalse( cache.containsKey(12) );
+        assertTrue( cache.containsKey(160) );
+        // we should hold 1 accessed element (i.e. 160)
+        assertEquals(1, cache.holdsize());
+        
+        // we should hold as many as possible
+        assertEquals(16, cache.hold());
+        assertEquals(true, cache.hold(255)); // it will create "duplicate in holdlist"
+        assertEquals(false, cache.hold(17));
+        assertEquals(16, cache.holdsize());
+        assertEquals(128, cache.size());
+        
+        // 512 KB is reasonable minimum of unreachable memory 
+        // all soft references should stay
+        assertTrue( RuntimeUtils.performGC() > 512*1024);
+        
+        assertEquals(128, cache.size());
+        assertEquals(16, cache.holdsize());
+        assertTrue(cache.containsKey(160)); // it will create "duplicate in holdlist"
+        assertTrue(cache.containsKey(252)); // it will create "duplicate in holdlist"
+        assertEquals(16, cache.holdsize());
+        
+        // 512 KB is reasonable minimum of unreachable memory 
+        // all soft references should go away
+        assertTrue( RuntimeUtils.forceGC() > 512*1024 );
+        
+        // test clean-up code in "get". 
+        // we can't invoke almost any method after GC, because it will run 
+        // clean-up code in #relase method
+        // we can't invoke #contains on existing key, because it will create
+        // "duplicate in holdlist"
+        assertFalse(cache.containsKey(161));
+        assertFalse(cache.containsKey(240));
+        
+        // we have 3 duplicates in holdlist
+        assertEquals(13, cache.size());
+        assertEquals(16, cache.holdsize());
+        
+        assertTrue(cache.containsKey(160));
+        assertTrue(cache.containsKey(252));
+        
+        // we dont have any duplicates
+        assertEquals(32, cache0.size());
+        assertEquals(32, cache0.holdsize());
+    }
+    
+    @Test
+    public void testPass() {
+        Cache<Integer, String> cache = new Cache<>();
+        assertSame("A", cache.pass(17, "A"));
+        assertSame("B", cache.pass(17, "B"));
+        assertSame("C", cache.pass(17, "C"));
+        assertEquals(1, cache.size());
+    }
+    
+    @Test
+    public void testConstruct() {
+        try {
+            Cache<Integer, String> cache3 = new Cache<>(32,48);
+            fail("IllegalArgumentException expected");
+        } catch(IllegalArgumentException cause) {
+            assertTrue(true);
+        }
+    }
+    
+    
+    
 }

+ 323 - 0
src/test/java/net/ranides/assira/collection/map/SwitchMapBenchmark.java

@@ -0,0 +1,323 @@
+/*
+ *  @author Ranides Atterwim <ranides@gmail.com>
+ *  @copyright Ranides Atterwim
+ *  @license WTFPL
+ *  @url http://ranides.net/projects/
+ */
+package net.ranides.assira.collection.map;
+
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import net.ranides.assira.math.Randomizer;
+
+/**
+ * Comparison of performance #get methods
+ * 
+ * RESULTS:
+ * 
+ *  Integer:
+ *     SIZE  DOMAIN   1/HIT  NAME    TREE  SWITCH  HASH   RATIO
+ *       32      1K      30   TT       55     55    40     73%
+ *      256      1K       4   SS       79     82    41     50%
+ *      256    100K     400   SM       79     89    39     43%
+ *      256  1 000M      4M   SL       81     84    39     46%
+ *   10 000  1 000M    100K   MM      156    160    49     30%
+ *   10 000     10K       1   ED      139    154    55     35%
+ *  100 000  1 000M     10K   LL      392    361    90     25%
+ * 
+ *   String:
+ *     SIZE  DOMAIN   1/HIT  NAME    TREE  SWITCH  HASH   RATIO
+ *       32      1K      30   TT       95     96    69     71%
+ *      256      1K       4   SS      123    133    72     54%
+ *      256    100K     400   SM      128    135    73     54%
+ *      256  1 000M      4M   SL      146    152    78     51%
+ *   10 000  1 000M    100K   MM      292    316    98     31%
+ *   10 000     10K       1   ED      249    261   113     43%
+ *  100 000  1 000M     10K   LL      753    723   169     23%
+ *     
+ * 
+ * SUMMARY:
+ * 
+ *                 TREE  SWITCH  HASH   RATIO
+ *      Integer     981    980   353     34%
+ *      String     1786   1816   672     36%
+ * 
+ * CONCLUSION:
+ *      it is classical O(logN) performance identical to TreeMap
+ *      it is better in terms of memory usage but slower than HashMap
+ * 
+ *      difference is observable for every N (even for N=32 hash is 30% better)
+ *      its acceptable choice anyway
+ * 
+ * @author ranides
+ */
+public class SwitchMapBenchmark extends SimpleBenchmark {
+
+    private IntMaps intTT;
+    private IntMaps intSS;
+    private IntMaps intSM;
+    private IntMaps intSL;
+    private IntMaps intMM;
+    private IntMaps intLL;
+    private IntMaps intED;
+    
+    private StrMaps strTT;
+    private StrMaps strSS;
+    private StrMaps strSM;
+    private StrMaps strSL;
+    private StrMaps strMM;
+    private StrMaps strLL;
+    private StrMaps strED;
+        
+    @Override
+    public void setUp() {
+        intTT = new IntMaps(     32,         1_000 );
+        intSS = new IntMaps(    256,         1_000 );
+        intSM = new IntMaps(    256,       100_000 );
+        intSL = new IntMaps(    256, 1_000_000_000 );
+        intMM = new IntMaps( 10_000, 1_000_000_000 );
+        intLL = new IntMaps(100_000, 1_000_000_000 );
+        intED = new IntMaps( 10_000,        10_000 );
+        
+        strTT = new StrMaps(     32,         1_000 );
+        strSS = new StrMaps(    256,         1_000 );
+        strSM = new StrMaps(    256,       100_000 );
+        strSL = new StrMaps(    256, 1_000_000_000 );
+        strMM = new StrMaps( 10_000, 1_000_000_000 );
+        strLL = new StrMaps(100_000, 1_000_000_000 );
+        strED = new StrMaps( 10_000,        10_000 );
+    }
+    
+    private static final class IntMaps {
+        
+        public final int domain;
+        public final SortedMap<Integer,Character> tree;
+        public final Map<Integer,Character> smap;
+        public final Map<Integer,Character> hash;
+        
+        public IntMaps(int n, int domain) {
+            this.domain = domain;
+            this.tree = new TreeMap<>();
+            for(int i=0; i<n; i++) {
+                int key = Randomizer.number(domain);
+                char val = Randomizer.character();
+                this.tree.put(key, val);
+            }
+            this.smap = new SwitchMap<>(tree);
+            this.hash = new HashMap<>(tree);
+        }
+    }
+    
+    private static final class StrMaps {
+        
+        public final int domain;
+        public final SortedMap<String,Character> tree;
+        public final Map<String,Character> smap;
+        public final Map<String,Character> hash;
+        
+        public StrMaps(int n, int domain) {
+            this.domain = domain;
+            this.tree = new TreeMap<>();
+            for(int i=0; i<n; i++) {
+                String key = Integer.toHexString(Randomizer.number(domain));
+                char val = Randomizer.character();
+                this.tree.put(key, val);
+            }
+            this.smap = new SwitchMap<>(tree);
+            this.hash = new HashMap<>(tree);
+        }
+    }
+
+    private int itimeIntMap(int reps, int domain, Map<Integer, Character> map) {
+        int c = 0;
+        for(int i=0; i<reps; i++) {
+            int key = Randomizer.number(domain);
+            Character val = map.get(key);
+            c += (null == val) ? 1 : 2;
+        }
+        return c;
+    }
+    
+    private int itimeStrMap(int reps, int domain, Map<String, Character> map) {
+        int c = 0;
+        for(int i=0; i<reps; i++) {
+            String key = Long.toHexString(Randomizer.number(domain));
+            Character val = map.get(key);
+            c += (null == val) ? 1 : 2;
+        }
+        return c;
+    }
+//    
+//    public int timeIntSS_tree(int reps) {
+//        return itimeIntMap(reps, intSS.domain, intSS.tree);
+//    }
+//    
+//    public int timeIntSM_tree(int reps) {
+//        return itimeIntMap(reps, intSM.domain, intSM.tree);
+//    }
+//    
+//    public int timeIntSL_tree(int reps) {
+//        return itimeIntMap(reps, intSL.domain, intSL.tree);
+//    }
+//    
+//    public int timeIntMM_tree(int reps) {
+//        return itimeIntMap(reps, intMM.domain, intMM.tree);
+//    }
+//    
+//    public int timeIntLL_tree(int reps) {
+//        return itimeIntMap(reps, intLL.domain, intLL.tree);
+//    }
+//    
+//    public int timeIntSS_hash(int reps) {
+//        return itimeIntMap(reps, intSS.domain, intSS.hash);
+//    }
+//    
+//    public int timeIntSM_hash(int reps) {
+//        return itimeIntMap(reps, intSM.domain, intSM.hash);
+//    }
+//    
+//    public int timeIntSL_hash(int reps) {
+//        return itimeIntMap(reps, intSL.domain, intSL.hash);
+//    }
+//    
+//    public int timeIntMM_hash(int reps) {
+//        return itimeIntMap(reps, intMM.domain, intMM.hash);
+//    }
+//    
+//    public int timeIntLL_hash(int reps) {
+//        return itimeIntMap(reps, intLL.domain, intLL.hash);
+//    }
+//    
+//    public int timeIntSS_smap(int reps) {
+//        return itimeIntMap(reps, intSS.domain, intSS.smap);
+//    }
+//    
+//    public int timeIntSM_smap(int reps) {
+//        return itimeIntMap(reps, intSM.domain, intSM.smap);
+//    }
+//    
+//    public int timeIntSL_smap(int reps) {
+//        return itimeIntMap(reps, intSL.domain, intSL.smap);
+//    }
+//    
+//    public int timeIntMM_smap(int reps) {
+//        return itimeIntMap(reps, intMM.domain, intMM.smap);
+//    }
+//    
+//    public int timeIntED_smap(int reps) {
+//        return itimeIntMap(reps, intED.domain, intED.smap);
+//    }
+//    
+//    public int timeIntED_tree(int reps) {
+//        return itimeIntMap(reps, intED.domain, intED.tree);
+//    }
+//    
+//    public int timeIntED_hash(int reps) {
+//        return itimeIntMap(reps, intED.domain, intED.hash);
+//    }
+    
+    public int timeIntTT_smap(int reps) {
+        return itimeIntMap(reps, intTT.domain, intTT.smap);
+    }
+    
+    public int timeIntTT_tree(int reps) {
+        return itimeIntMap(reps, intTT.domain, intTT.tree);
+    }
+    
+    public int timeIntTT_hash(int reps) {
+        return itimeIntMap(reps, intTT.domain, intTT.hash);
+    }
+    
+//    
+//    public int timeStrSS_tree(int reps) {
+//        return itimeStrMap(reps, strSS.domain, strSS.tree);
+//    }
+//    
+//    public int timeStrSM_tree(int reps) {
+//        return itimeStrMap(reps, strSM.domain, strSM.tree);
+//    }
+//    
+//    public int timeStrSL_tree(int reps) {
+//        return itimeStrMap(reps, strSL.domain, strSL.tree);
+//    }
+//    
+//    public int timeStrMM_tree(int reps) {
+//        return itimeStrMap(reps, strMM.domain, strMM.tree);
+//    }
+//    
+//    public int timeStrLL_tree(int reps) {
+//        return itimeStrMap(reps, strLL.domain, strLL.tree);
+//    }
+//    
+//    public int timeStrSS_hash(int reps) {
+//        return itimeStrMap(reps, strSS.domain, strSS.hash);
+//    }
+//    
+//    public int timeStrSM_hash(int reps) {
+//        return itimeStrMap(reps, strSM.domain, strSM.hash);
+//    }
+//    
+//    public int timeStrSL_hash(int reps) {
+//        return itimeStrMap(reps, strSL.domain, strSL.hash);
+//    }
+//    
+//    public int timeStrMM_hash(int reps) {
+//        return itimeStrMap(reps, strMM.domain, strMM.hash);
+//    }
+//    
+//    public int timeStrLL_hash(int reps) {
+//        return itimeStrMap(reps, strLL.domain, strLL.hash);
+//    }
+//    
+//    public int timeStrSS_smap(int reps) {
+//        return itimeStrMap(reps, strSS.domain, strSS.smap);
+//    }
+//    
+//    public int timeStrSM_smap(int reps) {
+//        return itimeStrMap(reps, strSM.domain, strSM.smap);
+//    }
+//    
+//    public int timeStrSL_smap(int reps) {
+//        return itimeStrMap(reps, strSL.domain, strSL.smap);
+//    }
+//    
+//    public int timeStrMM_smap(int reps) {
+//        return itimeStrMap(reps, strMM.domain, strMM.smap);
+//    }
+//    
+//    public int timeStrLL_smap(int reps) {
+//        return itimeStrMap(reps, strLL.domain, strLL.smap);
+//    }
+//    
+//    public int timeStrED_smap(int reps) {
+//        return itimeStrMap(reps, strED.domain, strED.smap);
+//    }
+//    
+//    public int timeStrED_tree(int reps) {
+//        return itimeStrMap(reps, strED.domain, strED.tree);
+//    }
+//    
+//    public int timeStrED_hash(int reps) {
+//        return itimeStrMap(reps, strED.domain, strED.hash);
+//    }
+    
+    public int timeStrTT_smap(int reps) {
+        return itimeStrMap(reps, strTT.domain, strTT.smap);
+    }
+    
+    public int timeStrTT_tree(int reps) {
+        return itimeStrMap(reps, strTT.domain, strTT.tree);
+    }
+    
+    public int timeStrTT_hash(int reps) {
+        return itimeStrMap(reps, strTT.domain, strTT.hash);
+    }
+    
+    public static void main(String[] args) {
+        Runner.main(SwitchMapBenchmark.class, args);
+    }
+}

+ 0 - 97
src/test/java/net/ranides/assira/collection/map/SwitchMapTest.java

@@ -9,11 +9,6 @@ package net.ranides.assira.collection.map;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import net.ranides.assira.math.Randomizer;
-import net.ranides.assira.time.TimeUtils;
-import net.ranides.assira.trace.LoggerUtils;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
@@ -90,96 +85,4 @@ public class SwitchMapTest {
 
     }
 
-
-    private static SortedMap<Integer,Character> generateIntMap(int n, long domain) {
-        final SortedMap<Integer, Character> result = new TreeMap<>();
-        for(int i=0; i<n; i++) {
-            result.put( (int)Randomizer.number(domain), (char)Randomizer.number(domain) );
-        }
-        return result;
-    }
-
-    private static SortedMap<String,Character> generateStrMap(int n, long domain) {
-        final SortedMap<String, Character> result = new TreeMap<>();
-        for(int i=0; i<n; i++) {
-            result.put( Long.toHexString(Randomizer.number(domain)), Randomizer.character() );
-        }
-        return result;
-    }
-
-    private static void ptestIntMap(int precision, final int keys, final long domain) {
-        final SortedMap<Integer, Character> intTree = generateIntMap(keys, domain);
-        final Map<Integer, Character> intSMap = new SwitchMap<>(intTree);
-        final Map<Integer, Character> intHash = new HashMap<>(intTree);
-
-        LoggerUtils.dump("hash<int> %8d:%2.0f |    %s\n", keys, Math.log10(domain), TimeUtils.benchmark(precision, new Runnable() {
-            @Override public void run() {
-                for(int i=0; i<5000; i++) { intHash.get( (int)Randomizer.number(domain) ); }
-            }
-        }));
-
-        LoggerUtils.dump("tree<int> %8d:%2.0f |    %s\n", keys, Math.log10(domain), TimeUtils.benchmark(precision, new Runnable() {
-            @Override public void run() {
-                for(int i=0; i<5000; i++) { intTree.get( (int)Randomizer.number(domain) ); }
-            }
-        }));
-
-        LoggerUtils.dump("smap<int> %8d:%2.0f |    %s\n", keys, Math.log10(domain), TimeUtils.benchmark(precision, new Runnable() {
-            @Override public void run() {
-                for(int i=0; i<5000; i++) { intSMap.get( (int)Randomizer.number(domain) ); }
-            }
-        }));
-
-        LoggerUtils.dump("\n");
-    }
-
-    private static void ptestStrMap(int precision, final int keys, final long domain) {
-        final SortedMap<String, Character> strTree = generateStrMap(keys, domain);
-        final Map<String, Character> strSMap = new SwitchMap<>(strTree);
-        final Map<String, Character> strHash = new HashMap<>(strTree);
-
-
-
-        LoggerUtils.dump("hash<str> %8d:%2.0f |    %s\n", keys, Math.log10(domain), TimeUtils.benchmark(precision, new Runnable() {
-            @Override public void run() {
-                for(int i=0; i<5000; i++) { strHash.get( Long.toHexString(Randomizer.number(domain)) ); }
-            }
-        }));
-
-        LoggerUtils.dump("tree<str> %8d:%2.0f |    %s\n", keys, Math.log10(domain), TimeUtils.benchmark(precision, new Runnable() {
-            @Override public void run() {
-                for(int i=0; i<5000; i++) { strTree.get( Long.toHexString(Randomizer.number(domain)) ); }
-            }
-        }));
-
-        LoggerUtils.dump("smap<str> %8d:%2.0f |    %s\n", keys, Math.log10(domain), TimeUtils.benchmark(precision, new Runnable() {
-            @Override public void run() {
-                for(int i=0; i<5000; i++) { strSMap.get( Long.toHexString(Randomizer.number(domain)) ); }
-            }
-        }));
-
-        LoggerUtils.dump("\n");
-    }
-
-    /**
-     * Test wydajnościowy
-     * @param args
-     */
-    public static void main(String[] args) {
-        final int PRECISION = 300;
-
-        ptestIntMap(PRECISION, 256, 1000);
-        ptestIntMap(PRECISION, 256, 100000);
-        ptestIntMap(PRECISION, 256, 1000000000);
-        ptestIntMap(PRECISION, 10000,  1000000000);
-        ptestIntMap(PRECISION, 100000, 1000000000);
-
-        LoggerUtils.dump("\n\n\n");
-
-        ptestStrMap(PRECISION, 256, 1000);
-        ptestStrMap(PRECISION, 256, 100000);
-        ptestStrMap(PRECISION, 256, 1000000000);
-        ptestStrMap(PRECISION, 10000,  1000000000);
-        ptestStrMap(PRECISION, 100000, 1000000000);
-    }
 }

+ 19 - 8
src/test/java/net/ranides/assira/events/ThreadPerfTest.java

@@ -9,24 +9,36 @@ package net.ranides.assira.events;
 import java.util.concurrent.Semaphore;
 import net.ranides.assira.time.TimeStack;
 import net.ranides.assira.time.TimeUtils;
-import org.junit.Test;
-import static org.junit.Assert.*;
 
 /**
- *
+ * Measure overhead of creation and running many threads.
+ * 
+ * CREATE:  4000 threads in 325 ms
+ * EXECUTE: 4000 threads in 840 ms
+ * 
+ * SUMMARY:
+ *      12'000 threads / s
+ *      16'000 threads / s on my old PC (George)
+ * 
+ *       4'750 semaphores / s
+ * 
+ * CONCLUSION:
+ *      threading overhead is overestimated
+ *      if acceptable overhead is ~1% then 
+ *      we should use ThreadPool for more than 100 threads / s
+ * 
  * @author ranides
  */
-public class ThreadPerfTest {
+public class ThreadBenchmark {
     
-    @Test
-    public void testPerf() throws InterruptedException {
+    public static void main(String[] args) throws InterruptedException {
         TimeStack tsm = new TimeStack();
         final Semaphore count = new Semaphore(Integer.MAX_VALUE, true);
 
         tsm.start(2);
         
         for(int i=0; i<4000; i++) {
-            assertTrue( count.tryAcquire() );
+            count.tryAcquire();
             new Thread() {
                 @Override
                 public void run() {
@@ -38,7 +50,6 @@ public class ThreadPerfTest {
         
         // około 16000 wątków / s
         
-        
         System.out.println("\ncreation = " + tsm.stop());
         count.acquire(Integer.MAX_VALUE);
         System.out.println("\nexecution = " + tsm.stop());