memoizeit

added caching simulation, instancereference on trace, parametrized

10/28/2018 1:29:10 AM

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/TraceReader.java b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/TraceReader.java
index 8c9ba22..99bb6bd 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/TraceReader.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/TraceReader.java
@@ -15,8 +15,10 @@ import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -47,6 +49,7 @@ public class TraceReader {
 
     public static List<Method> groupByMethods(List<Trace> traces) {
         Map<String, List<Occurrence>> methodNameHasOccurrences = new HashMap<>();
+        Set<String> staticMethods = new HashSet<>();
         while (!traces.isEmpty()) {
             Trace trace = traces.remove(0);
             try {
@@ -54,13 +57,16 @@ public class TraceReader {
                 trace.getParameters().forEach((parameter) -> {
                     parameters.add(parameter.getData());
                 });
-                Occurrence occurrence = new Occurrence(trace.getReturn().getData(), parameters, trace.getStartTime(), trace.getEndTime());
+                Occurrence occurrence = new Occurrence(trace.getInstance(), trace.getReturn().getData(), parameters, trace.getStartTime(), trace.getEndTime());
                 try {
                     methodNameHasOccurrences.get(trace.getName()).add(occurrence);
                 } catch (Exception ex) {
                     List<Occurrence> occurrences = new ArrayList<>();
                     occurrences.add(occurrence);
                     methodNameHasOccurrences.put(trace.getName(), occurrences);
+                    if (trace.getModifiers().contains("static")) {
+                        staticMethods.add(trace.getName());
+                    }
                 }
             } catch (Exception e) {
                 System.err.println("Trace discarted: " + trace);
@@ -68,7 +74,8 @@ public class TraceReader {
         }
         List<Method> methods = new ArrayList<>();
         methodNameHasOccurrences.entrySet().forEach((entry) -> {
-            methods.add(new Method(entry.getKey(), entry.getValue()));
+            boolean isStatic = staticMethods.contains(entry.getKey());
+            methods.add(new Method(entry.getKey(), isStatic, entry.getValue()));
         });
         return methods;
     }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/Cache.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/Cache.java
new file mode 100644
index 0000000..0d9cef6
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/Cache.java
@@ -0,0 +1,20 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package br.ufrgs.inf.prosoft.memoizeit.cache;
+
+/**
+ *
+ * @author romulo
+ */
+public interface Cache {
+
+    public Object put(String key, Object value);
+
+    public Object get(Object key);
+
+    public void invalidate(String key);
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/CachingPerformance.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/CachingPerformance.java
new file mode 100644
index 0000000..5fe7679
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/CachingPerformance.java
@@ -0,0 +1,64 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package br.ufrgs.inf.prosoft.memoizeit.cache;
+
+/**
+ *
+ * @author romulo
+ */
+public class CachingPerformance {
+
+    private int misses;
+    private int hits;
+    private int invalidations;
+    private int maximumSize;
+
+    void reduce(CachingPerformance cachingPerformance) {
+        this.misses += cachingPerformance.misses;
+        this.hits += cachingPerformance.hits;
+        this.invalidations += cachingPerformance.invalidations;
+        this.maximumSize = Math.max(this.maximumSize, cachingPerformance.maximumSize);
+    }
+
+    public void registerHit() {
+        this.hits++;
+    }
+
+    public void registerMiss() {
+        this.misses++;
+    }
+
+    public void registerInvalidation() {
+        this.invalidations++;
+    }
+
+    public void registerEntry() {
+        this.maximumSize++;
+    }
+
+    public void registerSize(int size) {
+        this.maximumSize = Math.max(this.maximumSize, size);
+    }
+
+    public long getHitRatio() {
+        return Math.round(this.hits * 100.0 / (this.hits + this.misses));
+    }
+
+    public String needInvalidation() {
+        return this.invalidations > 0 ? "yes" : "no";
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("H").append(this.hits);
+        stringBuilder.append(" M").append(this.misses);
+        stringBuilder.append(" I").append(this.invalidations);
+        stringBuilder.append(" S").append(this.maximumSize);
+        return stringBuilder.toString();
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/MultiCache.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/MultiCache.java
new file mode 100644
index 0000000..e05f4b7
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/MultiCache.java
@@ -0,0 +1,58 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package br.ufrgs.inf.prosoft.memoizeit.cache;
+
+import java.util.HashMap;
+
+/**
+ *
+ * @author romulo
+ */
+public class MultiCache extends HashMap<String, Object> implements Cache {
+
+    private final CachingPerformance cachingPerformance;
+
+    public MultiCache() {
+        this.cachingPerformance = new CachingPerformance();
+    }
+
+    public MultiCache(CachingPerformance cachingPerformance) {
+        this.cachingPerformance = cachingPerformance;
+    }
+
+    public CachingPerformance getCachingPerformance() {
+        return this.cachingPerformance;
+    }
+
+    @Override
+    public Object put(String key, Object value) {
+        Object oldReference = super.put(key, value);
+        if (oldReference == null) {
+            this.cachingPerformance.registerSize(size());
+        }
+        return oldReference;
+    }
+
+    @Override
+    public Object get(Object key) {
+        Object get = super.get(key);
+        if (get == null) {
+            this.cachingPerformance.registerMiss();
+        } else {
+            this.cachingPerformance.registerHit();
+        }
+        return get;
+    }
+
+    @Override
+    public void invalidate(String key) {
+        Object remove = this.remove(key);
+        if (remove != null) {
+            this.cachingPerformance.registerInvalidation();
+        }
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/SingleCache.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/SingleCache.java
new file mode 100644
index 0000000..3ae2f75
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/cache/SingleCache.java
@@ -0,0 +1,55 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package br.ufrgs.inf.prosoft.memoizeit.cache;
+
+/**
+ *
+ * @author romulo
+ */
+public class SingleCache implements Cache {
+
+    private final CachingPerformance cachingPerformance;
+    private String lastInput;
+    private Object result;
+
+    public SingleCache() {
+        this.cachingPerformance = new CachingPerformance();
+    }
+
+    public SingleCache(CachingPerformance cachingPerformance) {
+        this.cachingPerformance = cachingPerformance;
+    }
+
+    public CachingPerformance getCachingPerformance() {
+        return this.cachingPerformance;
+    }
+
+    @Override
+    public Object put(String key, Object value) {
+        this.lastInput = key;
+        this.result = value;
+        this.cachingPerformance.registerSize(1);
+        return this.result;
+    }
+
+    @Override
+    public Object get(Object key) {
+        if (key.equals(this.lastInput)) {
+            this.cachingPerformance.registerHit();
+            return this.result;
+        }
+        this.cachingPerformance.registerMiss();
+        return null;
+    }
+
+    @Override
+    public void invalidate(String key) {
+        this.lastInput = null;
+        this.result = null;
+        this.cachingPerformance.registerInvalidation();
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
index 59a0795..e0146d3 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
@@ -5,7 +5,9 @@
  */
 package br.ufrgs.inf.prosoft.memoizeit;
 
+import br.ufrgs.inf.prosoft.memoizeit.cache.CachingPerformance;
 import java.util.List;
+import java.util.Map;
 
 /**
  *
@@ -170,7 +172,64 @@ public class MemoizeIt {
             throw new RuntimeException("Empty execution traces");
         }
         filterInitialCandidates();
-        refineCandidates();
+        refineCandidatesIteratively();
+        rankMethods();
+        suggestImplementations();
     }
 
+//    3.3 clustering and ranking
+    private void rankMethods() {
+        rankMethods(true);
+    }
+
+    private void rankMethods(boolean cluster) {
+        if (cluster) {
+            clusterMethods();
+        }
+    }
+
+    private void clusterMethods() {
+    }
+
+//    3.4 suggest cache implementation
+    private void suggestImplementations() {
+        for (Method method : this.methods) {
+            System.out.println(method.getName());
+            suggestImplementation(method);
+            System.out.println();
+        }
+    }
+
+    private void suggestImplementation(Method method) {
+        Map<String, CachingPerformance> cachingStrategyHasPerformance = method.simulateCachingStrategies();
+        CachingPerformance globalMultiCachePerformance = cachingStrategyHasPerformance.get("globalMultiCache");
+        CachingPerformance globalSingleCachePerformance = cachingStrategyHasPerformance.get("globalSingleCache");
+        CachingPerformance instanceMultiCachePerformance = cachingStrategyHasPerformance.get("instanceMultiCache");
+        CachingPerformance instanceSingleCachePerformance = cachingStrategyHasPerformance.get("instanceSingleCache");
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("GS: ");
+        stringBuilder.append("R").append(globalSingleCachePerformance.getHitRatio());
+        stringBuilder.append(" * ").append(globalSingleCachePerformance);
+        stringBuilder.append(" | IS: ");
+        stringBuilder.append("R").append(instanceSingleCachePerformance.getHitRatio());
+        stringBuilder.append(" * ").append(instanceSingleCachePerformance);
+        stringBuilder.append(" | GM: ");
+        stringBuilder.append("R").append(globalMultiCachePerformance.getHitRatio());
+        stringBuilder.append(" * ").append(globalMultiCachePerformance);
+        stringBuilder.append(" | IM: ");
+        stringBuilder.append("R").append(instanceMultiCachePerformance.getHitRatio());
+        stringBuilder.append(" * ").append(instanceMultiCachePerformance);
+        System.out.println(stringBuilder);
+        if (globalSingleCachePerformance.getHitRatio() >= 50) {
+            System.out.println("single, global");
+        } else if (instanceSingleCachePerformance.getHitRatio() >= 50) {
+            System.out.println("single, instance");
+        } else if (globalMultiCachePerformance.getHitRatio() >= 50) {
+            System.out.println("multi, global");
+        } else if (instanceMultiCachePerformance.getHitRatio() >= 50) {
+            System.out.println("multi, instance");
+        } else {
+            System.out.println("none");
+        }
+    }
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
index 01a62eb..214aa5a 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
@@ -5,6 +5,9 @@
  */
 package br.ufrgs.inf.prosoft.memoizeit;
 
+import br.ufrgs.inf.prosoft.memoizeit.cache.CachingPerformance;
+import br.ufrgs.inf.prosoft.memoizeit.cache.MultiCache;
+import br.ufrgs.inf.prosoft.memoizeit.cache.SingleCache;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -21,11 +24,17 @@ public class Method {
     private final List<Occurrence> occurrences;
     private Map<String, List<Occurrence>> groupByParameter;
     private Boolean fullyExplored;
+    private final boolean isStatic;
 
-    public Method(String name, List<Occurrence> occurrences) {
+    public Method(String name, boolean isStatic, List<Occurrence> occurrences) {
         this.name = name;
         this.occurrences = occurrences;
         this.fullyExplored = false;
+        this.isStatic = isStatic;
+    }
+
+    public String getName() {
+        return name;
     }
 
     public int getOccurrencesSize() {
@@ -55,9 +64,11 @@ public class Method {
     protected void groupByParameter(int depth) {
         this.groupByParameter = new HashMap<>();
         this.occurrences.forEach((occurrence) -> {
-            Occurrence truncated = occurrence.getView(depth);
-            this.fullyExplored = truncated == occurrence;
-            occurrence = truncated;
+            if (depth < Integer.MAX_VALUE) {
+                Occurrence truncated = occurrence.getView(depth);
+                this.fullyExplored = truncated == occurrence;
+                occurrence = truncated;
+            }
             String parameters = occurrence.getParameters().toString();
             try {
                 this.groupByParameter.get(parameters).add(occurrence);
@@ -70,18 +81,7 @@ public class Method {
     }
 
     protected void groupByParameter() {
-        this.groupByParameter = new HashMap<>();
-        while (!this.occurrences.isEmpty()) {
-            Occurrence occurrence = this.occurrences.remove(0);
-            String parameters = occurrence.getParameters().toString();
-            try {
-                this.groupByParameter.get(parameters).add(occurrence);
-            } catch (Exception e) {
-                List<Occurrence> occurrences = new ArrayList<>();
-                occurrences.add(occurrence);
-                this.groupByParameter.put(parameters, occurrences);
-            }
-        }
+        groupByParameter(Integer.MAX_VALUE);
     }
 
     protected boolean isChangeful() {
@@ -91,7 +91,7 @@ public class Method {
             }
             Occurrence firstOccurrence = entry.getValue().get(0);
             for (Occurrence occurrence : entry.getValue()) {
-                if (!occurrence.getReturnValue().equals(firstOccurrence.getReturnValue())) {
+                if (occurrence.getReturnValue() != null && !occurrence.getReturnValue().equals(firstOccurrence.getReturnValue())) {
                     return true;
                 }
             }
@@ -109,6 +109,41 @@ public class Method {
         return potentialHitRatio;
     }
 
+    protected Map<String, CachingPerformance> simulateCachingStrategies() {
+        Map<String, CachingPerformance> cachingStrategyHasPerformance = new HashMap<>();
+        CachingPerformance globalMultiCachePerformance = new CachingPerformance();
+        CachingPerformance globalSingleCachePerformance = new CachingPerformance();
+        CachingPerformance instanceMultiCachePerformance = new CachingPerformance();
+        CachingPerformance instanceSingleCachePerformance = new CachingPerformance();
+        cachingStrategyHasPerformance.put("globalMultiCache", globalMultiCachePerformance);
+        cachingStrategyHasPerformance.put("globalSingleCache", globalSingleCachePerformance);
+        cachingStrategyHasPerformance.put("instanceMultiCache", instanceMultiCachePerformance);
+        cachingStrategyHasPerformance.put("instanceSingleCache", instanceSingleCachePerformance);
+        MultiCache globalMultiCache = new MultiCache(globalMultiCachePerformance);
+        SingleCache globalSingleCache = new SingleCache(globalSingleCachePerformance);
+        Map<String, MultiCache> instanceHasMultiCache = new HashMap<>();
+        Map<String, SingleCache> instanceHasSingleCache = new HashMap<>();
+        for (Occurrence occurrence : this.occurrences) {
+            if (!this.isStatic) {
+                MultiCache instanceMultiCache = instanceHasMultiCache.get(occurrence.getInstance());
+                if (instanceMultiCache == null) {
+                    instanceMultiCache = new MultiCache(instanceMultiCachePerformance);
+                    instanceHasMultiCache.put(occurrence.getInstance(), instanceMultiCache);
+                }
+                occurrence.simulateCaching(instanceMultiCache);
+                SingleCache instanceSingleCache = instanceHasSingleCache.get(occurrence.getInstance());
+                if (instanceSingleCache == null) {
+                    instanceSingleCache = new SingleCache(instanceSingleCachePerformance);
+                    instanceHasSingleCache.put(occurrence.getInstance(), instanceSingleCache);
+                }
+                occurrence.simulateCaching(instanceSingleCache);
+            }
+            occurrence.simulateCaching(globalMultiCache);
+            occurrence.simulateCaching(globalSingleCache);
+        }
+        return cachingStrategyHasPerformance;
+    }
+
     @Override
     public int hashCode() {
         int hash = 5;
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java
index c851120..7d1e54f 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java
@@ -5,8 +5,10 @@
  */
 package br.ufrgs.inf.prosoft.memoizeit;
 
+import br.ufrgs.inf.prosoft.memoizeit.cache.Cache;
+import br.ufrgs.inf.prosoft.memoizeit.utils.Action;
+import br.ufrgs.inf.prosoft.memoizeit.utils.ObjectUtils;
 import java.util.List;
-import java.util.Map;
 
 /**
  *
@@ -14,13 +16,15 @@ import java.util.Map;
  */
 public class Occurrence {
 
+    private final String instance;
     private final Object returnValue;
     private final List<Object> parameters;
     private final long startTime;
     private final long endTime;
     private boolean truncated;
 
-    public Occurrence(Object returnValue, List<Object> parameters, long startTime, long endTime) {
+    public Occurrence(String instance, Object returnValue, List<Object> parameters, long startTime, long endTime) {
+        this.instance = instance;
         this.returnValue = returnValue;
         this.parameters = parameters;
         this.startTime = startTime;
@@ -28,49 +32,46 @@ public class Occurrence {
         this.truncated = true;
     }
 
+    public String getInstance() {
+        return instance;
+    }
+
     public Object getReturnValue() {
-        return returnValue;
+        return this.returnValue;
     }
 
     public List<Object> getParameters() {
-        return parameters;
+        return this.parameters;
     }
 
     public long getExecutionTime() {
         return this.endTime - this.startTime;
     }
 
-    private Object truncateObject(Object object, int depth) {
-        if (depth == 0) {
-            object = "...";
-            this.truncated = true;
-            return object;
-        }
-        if (object instanceof Map) {
-            Map<String, Object> map = (Map<String, Object>) object;
-            map.entrySet().forEach((entry) -> {
-                entry.setValue(truncateObject(entry.getValue(), depth - 1));
-            });
-        } else if (object instanceof List) {
-            List list = (List) object;
-            for (int i = 0; i < list.size(); i++) {
-                list.set(i, truncateObject(list.get(i), depth - 1));
-            }
-        }
-        return object;
-    }
-
     protected Occurrence getView(int depth) {
         if (!this.truncated) {
             return this;
         }
         this.truncated = false;
         Object returnValue = ObjectUtils.deepCopy(this.returnValue);
-        truncateObject(returnValue, depth);
+        Action onTruncate = () -> {
+            this.truncated = true;
+        };
+        ObjectUtils.truncateObject(returnValue, depth, onTruncate);
         List<Object> parameters = ObjectUtils.deepCopy(this.parameters);
-        truncateObject(parameters, depth);
-        Occurrence occurrence = new Occurrence(returnValue, parameters, startTime, endTime);
+        ObjectUtils.truncateObject(parameters, depth, onTruncate);
+        Occurrence occurrence = new Occurrence(this.instance, returnValue, parameters, this.startTime, this.endTime);
         return occurrence;
     }
 
+    protected void simulateCaching(Cache cache) {
+        String key = this.parameters.toString();
+        Object cached = cache.get(key);
+        if (cached == null) {
+            cache.put(key, this.returnValue);
+        } else if (!cached.equals(this.returnValue)) {
+            cache.invalidate(key);
+        }
+    }
+
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/utils/Action.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/utils/Action.java
new file mode 100644
index 0000000..e6a0a07
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/utils/Action.java
@@ -0,0 +1,15 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package br.ufrgs.inf.prosoft.memoizeit.utils;
+
+/**
+ *
+ * @author romulo
+ */
+public interface Action {
+
+    public void perform();
+}