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();
+}