memoizeit

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/CallGraphReader.java b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/CallGraphReader.java
index c383207..8eeac6c 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/CallGraphReader.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/CallGraphReader.java
@@ -10,9 +10,13 @@ import br.ufrgs.inf.prosoft.memoizeit.graph.Node;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
 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;
 
@@ -54,10 +58,42 @@ public class CallGraphReader {
         return new Graph<>();
     }
 
+    public static Map<String, Set<String>> parseFileToMap(String path) {
+        Map<String, Set<String>> nodeHasLinks = new HashMap<>();
+        try {
+            List<String> lines = Files.readAllLines(Paths.get(path));
+            for (String line : lines) {
+                if (line.charAt(0) != 'M') {
+                    continue;
+                }
+                int indexOfSpace = line.indexOf(" ");
+                String callerString = line.substring(2, indexOfSpace);
+                String calleeString = line.substring(indexOfSpace + 4, line.length());
+                callerString = reshapeMethodName(callerString);
+                calleeString = reshapeMethodName(calleeString);
+                Set<String> links = nodeHasLinks.get(callerString);
+                if (links == null) {
+                    links = new HashSet<>();
+                    nodeHasLinks.put(callerString, links);
+                }
+                links.add(calleeString);
+            }
+        } catch (IOException ex) {
+            Logger.getLogger(CallGraphReader.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        return nodeHasLinks;
+    }
+
     private static String reshapeMethodName(String methodName) {
         return methodName.substring(0, methodName.indexOf("("))
                 .replace(":", ".")
                 .replace("$", ".");
     }
 
+    private static Collection<Node<String>> getRoots(Graph<String> graph) {
+        Collection<Node<String>> roots = new ArrayList<>(graph.getNodes());
+        graph.getEdges().forEach(edge -> roots.remove(edge.getTarget()));
+        return roots;
+    }
+
 }
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 c23268b..468fee0 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
@@ -7,6 +7,7 @@ package br.ufrgs.inf.prosoft.approachescomparison.adapter;
 
 import br.ufrgs.inf.prosoft.memoizeit.Method;
 import br.ufrgs.inf.prosoft.memoizeit.Occurrence;
+import br.ufrgs.inf.prosoft.memoizeit.Parameter;
 import br.ufrgs.inf.prosoft.trace.Trace;
 import com.google.gson.Gson;
 import com.google.gson.JsonSyntaxException;
@@ -38,7 +39,7 @@ public class TraceReader {
                     Trace trace = gson.fromJson(line, Trace.class);
                     traces.add(trace);
                 } catch (JsonSyntaxException e) {
-                    System.err.println("Malformed Trace");
+                    System.err.println("Malformed Trace: " + line);
                 }
             }
         } catch (IOException ex) {
@@ -53,9 +54,9 @@ public class TraceReader {
         while (!traces.isEmpty()) {
             Trace trace = traces.remove(0);
             try {
-                List<Object> parameters = new ArrayList<>();
+                List<Parameter> parameters = new ArrayList<>();
                 trace.getParameters().forEach((parameter) -> {
-                    parameters.add(parameter.getData());
+                    parameters.add(new Parameter(parameter.getType(), parameter.getData()));
                 });
                 Occurrence occurrence = new Occurrence(trace.getInstance(), trace.getReturn().getData(), parameters, trace.getStartTime(), trace.getEndTime());
                 try {
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Edge.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Edge.java
new file mode 100644
index 0000000..ea16ecb
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Edge.java
@@ -0,0 +1,30 @@
+/*
+ * 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.graph;
+
+/**
+ *
+ * @author romulo
+ */
+public class Edge<U> {
+
+    private final Node<U> source;
+    private final Node<U> target;
+
+    public Edge(Node<U> source, Node<U> target) {
+        this.source = source;
+        this.target = target;
+    }
+
+    public Node<U> getSource() {
+        return source;
+    }
+
+    public Node<U> getTarget() {
+        return target;
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Graph.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Graph.java
index 9296ec9..1d30440 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Graph.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Graph.java
@@ -5,8 +5,12 @@
  */
 package br.ufrgs.inf.prosoft.memoizeit.graph;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  *
@@ -28,4 +32,21 @@ public class Graph<U> {
         return this.contentHasNode.get(content);
     }
 
+    public Collection<Node<U>> getNodes() {
+        return this.contentHasNode.values();
+    }
+
+    public Collection<Edge<U>> getEdges() {
+        return this.contentHasNode.values().stream()
+                .map(node
+                        -> node.getLinks().stream()
+                        .map(link -> new Edge<>(node, link))
+                        .collect(Collectors.toList()))
+                .reduce(new ArrayList<>(), (a, b) -> {
+                    List arrayList = new ArrayList<>(a);
+                    arrayList.addAll(b);
+                    return arrayList;
+                });
+    }
+
 }
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 fda5a8b..b7b99e9 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
@@ -90,15 +90,11 @@ public class MemoizeIt {
     }
 
     private void estimateTotalProgramExecution() {
-        this.methods.forEach((method) -> {
-            this.totalProgramExecution += method.getTotalExecutionTime();
-        });
+        this.totalProgramExecution = this.methods.stream().map(method -> method.getTotalExecutionTime()).reduce(Long::sum).get();
     }
 
     private void calculateAverageExecutionTime() {
-        this.methods.forEach((method) -> {
-            this.averageProgramExecution += method.getAverageExecutionTime();
-        });
+        this.averageProgramExecution = this.methods.stream().map(method -> method.getAverageExecutionTime()).reduce(Long::sum).get();
         this.averageProgramExecution /= this.methods.size();
     }
 
@@ -124,6 +120,10 @@ public class MemoizeIt {
         }
     }
 
+    private void removeUnusedFields() {
+        this.methods.forEach(method -> method.removeUnusedFields(this.callGraph.getNode(method.getName())));
+    }
+
 //    3.2 input-output profiling
     private void refineCandidates() {
         refineCandidates(Integer.MAX_VALUE);
@@ -180,7 +180,7 @@ public class MemoizeIt {
         }
     }
 
-    private Collection<Method> getIndirectCallees(List<Node<String>> visited, String packageName, Node<String> node) {
+    private Collection<Method> getIndirectCallees(List<Node<String>> visited, String rootPackage, Node<String> node) {
         Collection<Method> cluster = new ArrayList<>();
         Collection<Node<String>> directCallees = node.getLinks();
         for (Node<String> directCallee : directCallees) {
@@ -193,11 +193,11 @@ public class MemoizeIt {
                     .findAny()
                     .ifPresent((callee) -> {
                         String calleePackage = callee.getName().substring(0, callee.getName().lastIndexOf("."));
-                        if (calleePackage.equals(packageName)) {
+                        if (calleePackage.equals(rootPackage)) {
                             cluster.add(callee);
                         }
                     });
-            cluster.addAll(getIndirectCallees(visited, packageName, directCallee));
+            cluster.addAll(getIndirectCallees(visited, rootPackage, directCallee));
         }
         return cluster;
     }
@@ -207,6 +207,9 @@ public class MemoizeIt {
         cluster.add(root);
         String rootPackage = root.getName().substring(0, root.getName().lastIndexOf("."));
         Node<String> node = this.callGraph.getNode(root.getName());
+        if (node == null) {
+            return cluster;
+        }
         visited.add(node);
         Collection<Node<String>> directCallees = node.getLinks();
         for (Node<String> directCallee : directCallees) {
@@ -214,7 +217,6 @@ public class MemoizeIt {
                 continue;
             }
             visited.add(directCallee);
-            Map<String, Method> a = null;
             this.methods.stream()
                     .filter(method -> method.getName().equals(directCallee.getContent()))
                     .findAny()
@@ -315,6 +317,7 @@ public class MemoizeIt {
             throw new RuntimeException("Call Graph not set");
         }
         filterInitialCandidates();
+        removeUnusedFields();
         refineCandidatesIteratively();
     }
 
@@ -337,6 +340,7 @@ public class MemoizeIt {
             throw new RuntimeException("Call Graph not set");
         }
         filterInitialCandidates();
+        removeUnusedFields();
         refineCandidatesIteratively();
         printClusters();
         suggestImplementations();
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 d330456..b2b4eb0 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
@@ -8,6 +8,7 @@ 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 br.ufrgs.inf.prosoft.memoizeit.graph.Node;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -92,10 +93,8 @@ public class Method {
                 continue;
             }
             Occurrence firstOccurrence = entry.getValue().get(0);
-            for (Occurrence occurrence : entry.getValue()) {
-                if (occurrence.getReturnValue() != null && !occurrence.getReturnValue().equals(firstOccurrence.getReturnValue())) {
-                    return true;
-                }
+            if (entry.getValue().stream().anyMatch((occurrence) -> (occurrence.getReturnValue() != null && !occurrence.getReturnValue().equals(firstOccurrence.getReturnValue())))) {
+                return true;
             }
         }
         return false;
@@ -107,6 +106,14 @@ public class Method {
         return potentialHitRatio;
     }
 
+    protected void removeUnusedFields(Node<String> methodNode) {
+        if (methodNode == null) {
+            System.err.println("methodNode null: " + this.name);
+            return;
+        }
+        this.occurrences.stream().forEach(occurrence -> occurrence.removeUnusedFields(methodNode));
+    }
+
     protected Map<String, CachingPerformance> simulateCachingStrategies() {
         Map<String, CachingPerformance> cachingStrategyHasPerformance = new HashMap<>();
         CachingPerformance globalMultiCachePerformance = new CachingPerformance();
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 7d1e54f..5a7dce4 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java
@@ -6,9 +6,14 @@
 package br.ufrgs.inf.prosoft.memoizeit;
 
 import br.ufrgs.inf.prosoft.memoizeit.cache.Cache;
+import br.ufrgs.inf.prosoft.memoizeit.graph.Node;
 import br.ufrgs.inf.prosoft.memoizeit.utils.Action;
 import br.ufrgs.inf.prosoft.memoizeit.utils.ObjectUtils;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 /**
  *
@@ -18,12 +23,12 @@ public class Occurrence {
 
     private final String instance;
     private final Object returnValue;
-    private final List<Object> parameters;
+    private final List<Parameter> parameters;
     private final long startTime;
     private final long endTime;
     private boolean truncated;
 
-    public Occurrence(String instance, Object returnValue, List<Object> parameters, long startTime, long endTime) {
+    public Occurrence(String instance, Object returnValue, List<Parameter> parameters, long startTime, long endTime) {
         this.instance = instance;
         this.returnValue = returnValue;
         this.parameters = parameters;
@@ -40,7 +45,7 @@ public class Occurrence {
         return this.returnValue;
     }
 
-    public List<Object> getParameters() {
+    public List<Parameter> getParameters() {
         return this.parameters;
     }
 
@@ -58,8 +63,12 @@ public class Occurrence {
             this.truncated = true;
         };
         ObjectUtils.truncateObject(returnValue, depth, onTruncate);
-        List<Object> parameters = ObjectUtils.deepCopy(this.parameters);
-        ObjectUtils.truncateObject(parameters, depth, onTruncate);
+        List<Parameter> parameters = new ArrayList<>();
+        for (Parameter parameter : this.parameters) {
+            Object parameterView = ObjectUtils.deepCopy(parameter.getData());
+            ObjectUtils.truncateObject(parameterView, depth, onTruncate);
+            parameters.add(new Parameter(parameter.getType(), parameterView));
+        }
         Occurrence occurrence = new Occurrence(this.instance, returnValue, parameters, this.startTime, this.endTime);
         return occurrence;
     }
@@ -74,4 +83,32 @@ public class Occurrence {
         }
     }
 
+    private void removeUnusedFields(Map<String, Object> map, String parameterType, Node<String> methodNode) {
+        Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<String, Object> entry = iterator.next();
+            String getter = parameterType + ".get" + entry.getKey().substring(0, 1).toUpperCase() + entry.getKey().substring(1);
+            if (!methodNode.getLinks().stream().anyMatch(node -> node.getContent().equals(getter))) {
+                iterator.remove();
+            }
+        }
+
+    }
+
+    protected void removeUnusedFields(Node<String> methodNode) {
+        for (Parameter parameter : this.parameters) {
+            String parameterType = parameter.getType();
+            if (parameter.getData() instanceof Collection) {
+                Collection collection = (Collection) parameter.getData();
+                if (collection.stream().findAny().get() instanceof Map) {
+                    Collection<Map<String, Object>> cast = collection;
+                    cast.forEach(map -> removeUnusedFields(map, parameterType, methodNode));
+                }
+            } else if (parameter.getData() instanceof Map) {
+                Map<String, Object> map = (Map<String, Object>) parameter.getData();
+                removeUnusedFields(map, parameterType, methodNode);
+            }
+        }
+    }
+
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Parameter.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Parameter.java
new file mode 100644
index 0000000..6cb6bed
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Parameter.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ *
+ * @author romulo
+ */
+public class Parameter {
+
+    private final String type;
+    private final Object data;
+
+    public Parameter(String type, Object data) {
+        this.type = type;
+        this.data = data;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public String toString() {
+        return this.data.toString();
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/utils/ObjectUtils.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/utils/ObjectUtils.java
index 425a7c7..c2493ff 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/utils/ObjectUtils.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/utils/ObjectUtils.java
@@ -22,9 +22,8 @@ public class ObjectUtils {
 
     public static Object truncateObject(Object object, int depth, Action onTruncate) {
         if (depth == 0) {
-            object = "...";
             onTruncate.perform();
-            return object;
+            return "...";
         }
         if (object instanceof Map) {
             Map<String, Object> map = (Map<String, Object>) object;