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
new file mode 100644
index 0000000..c383207
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/CallGraphReader.java
@@ -0,0 +1,63 @@
+/*
+ * 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.approachescomparison.adapter;
+
+import br.ufrgs.inf.prosoft.memoizeit.graph.Graph;
+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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author romulo
+ */
+public class CallGraphReader {
+
+ public static Graph<String> parseFile(String path) {
+ try {
+ Map<String, Node<String>> callHasNode = new HashMap<>();
+ 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);
+ Node<String> callerNode = callHasNode.get(callerString);
+ if (callerNode == null) {
+ callerNode = new Node<>(callerString);
+ callHasNode.put(callerString, callerNode);
+ }
+ Node<String> calleeNode = callHasNode.get(calleeString);
+ if (calleeNode == null) {
+ calleeNode = new Node<>(calleeString);
+ callHasNode.put(calleeString, calleeNode);
+ }
+ callerNode.addLink(calleeNode);
+ }
+ return new Graph<>(callHasNode);
+ } catch (IOException ex) {
+ Logger.getLogger(CallGraphReader.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ return new Graph<>();
+ }
+
+ private static String reshapeMethodName(String methodName) {
+ return methodName.substring(0, methodName.indexOf("("))
+ .replace(":", ".")
+ .replace("$", ".");
+ }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/Main.java b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/Main.java
index 9ed36c0..19fc7e8 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/Main.java
@@ -7,6 +7,7 @@ package br.ufrgs.inf.prosoft.approachescomparison.adapter;
import br.ufrgs.inf.prosoft.memoizeit.MemoizeIt;
import br.ufrgs.inf.prosoft.memoizeit.Method;
+import br.ufrgs.inf.prosoft.memoizeit.graph.Graph;
import br.ufrgs.inf.prosoft.trace.Trace;
import java.util.List;
@@ -17,28 +18,22 @@ import java.util.List;
public class Main {
public static void main(String[] args) {
- String path = null;
- long totalExecutionTime = 0;
- if (args.length < 1) {
- System.err.println("No path provided");
+ String tracePath = null;
+ String callGraphPath = null;
+ if (args.length < 2) {
+ System.err.println("<TracePath> <CallGraphPath>");
System.exit(1);
} else {
- path = args[0];
- if (args.length < 2) {
- System.err.println("No execution time provided");
- try {
- totalExecutionTime = Long.parseLong(args[1]);
- } catch (NumberFormatException e) {
- System.err.println("Argument must be a long number");
- System.exit(1);
- }
- }
+ tracePath = args[0];
+ callGraphPath = args[1];
}
- List<Trace> traces = TraceReader.readFile(path);
- MemoizeIt memoizeIt = new MemoizeIt(totalExecutionTime);
+ Graph<String> graph = CallGraphReader.parseFile(callGraphPath);
+ List<Trace> traces = TraceReader.parseFile(tracePath);
List<Method> methods = TraceReader.groupByMethods(traces);
+ MemoizeIt memoizeIt = new MemoizeIt();
+ memoizeIt.setCallGraph(graph);
memoizeIt.setMethods(methods);
- memoizeIt.removeChangefulMethods();
+ memoizeIt.run();
methods.forEach(System.out::println);
}
}
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 99bb6bd..c23268b 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
@@ -28,7 +28,7 @@ import java.util.logging.Logger;
*/
public class TraceReader {
- public static List<Trace> readFile(String path) {
+ public static List<Trace> parseFile(String path) {
List<Trace> traces = new ArrayList<>();
try {
List<String> lines = Files.readAllLines(Paths.get(path));
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
new file mode 100644
index 0000000..9296ec9
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Graph.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author romulo
+ */
+public class Graph<U> {
+
+ private final Map<U, Node<U>> contentHasNode;
+
+ public Graph() {
+ this.contentHasNode = new HashMap<>();
+ }
+
+ public Graph(Map<U, Node<U>> contentHasNode) {
+ this.contentHasNode = contentHasNode;
+ }
+
+ public Node<U> getNode(U content) {
+ return this.contentHasNode.get(content);
+ }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Node.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Node.java
new file mode 100644
index 0000000..3cf33fb
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/graph/Node.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Objects;
+
+/**
+ *
+ * @author romulo
+ */
+public class Node<U> {
+
+ private final U content;
+ private final Collection<Node<U>> links;
+
+ public Node(U content) {
+ this.content = content;
+ this.links = new HashSet<>();
+ }
+
+ public U getContent() {
+ return content;
+ }
+
+ public Node addLink(Node node) {
+ links.add(node);
+ return this;
+ }
+
+ public Collection<Node<U>> getLinks() {
+ return links;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.content);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Node)) {
+ return false;
+ }
+ Node other = (Node) obj;
+ return this.content.equals(other.content);
+ }
+
+}
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 e0146d3..fda5a8b 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
@@ -6,8 +6,14 @@
package br.ufrgs.inf.prosoft.memoizeit;
import br.ufrgs.inf.prosoft.memoizeit.cache.CachingPerformance;
+import br.ufrgs.inf.prosoft.memoizeit.graph.Graph;
+import br.ufrgs.inf.prosoft.memoizeit.graph.Node;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
/**
*
@@ -31,6 +37,8 @@ public class MemoizeIt {
private List<Method> methods;
// Stoping condition to iterative algorithm
private boolean maxDepthReached;
+ // Call Graph
+ private Graph<String> callGraph;
public MemoizeIt() {
this.maxDepthReached = false;
@@ -76,6 +84,11 @@ public class MemoizeIt {
return this;
}
+ public MemoizeIt setCallGraph(Graph<String> callGraph) {
+ this.callGraph = callGraph;
+ return this;
+ }
+
private void estimateTotalProgramExecution() {
this.methods.forEach((method) -> {
this.totalProgramExecution += method.getTotalExecutionTime();
@@ -167,39 +180,91 @@ public class MemoizeIt {
}
}
- public void removeChangefulMethods() {
- if (this.methods.isEmpty()) {
- throw new RuntimeException("Empty execution traces");
+ private Collection<Method> getIndirectCallees(List<Node<String>> visited, String packageName, Node<String> node) {
+ Collection<Method> cluster = new ArrayList<>();
+ Collection<Node<String>> directCallees = node.getLinks();
+ for (Node<String> directCallee : directCallees) {
+ if (visited.contains(directCallee)) {
+ continue;
+ }
+ visited.add(directCallee);
+ this.methods.stream()
+ .filter(method -> method.getName().equals(directCallee.getContent()))
+ .findAny()
+ .ifPresent((callee) -> {
+ String calleePackage = callee.getName().substring(0, callee.getName().lastIndexOf("."));
+ if (calleePackage.equals(packageName)) {
+ cluster.add(callee);
+ }
+ });
+ cluster.addAll(getIndirectCallees(visited, packageName, directCallee));
}
- filterInitialCandidates();
- refineCandidatesIteratively();
- rankMethods();
- suggestImplementations();
+ return cluster;
}
-// 3.3 clustering and ranking
- private void rankMethods() {
- rankMethods(true);
+ private Collection<Method> getTreeCluster(List<Node<String>> visited, Method root) {
+ Collection<Method> cluster = new ArrayList<>();
+ cluster.add(root);
+ String rootPackage = root.getName().substring(0, root.getName().lastIndexOf("."));
+ Node<String> node = this.callGraph.getNode(root.getName());
+ visited.add(node);
+ Collection<Node<String>> directCallees = node.getLinks();
+ for (Node<String> directCallee : directCallees) {
+ if (visited.contains(directCallee)) {
+ continue;
+ }
+ visited.add(directCallee);
+ Map<String, Method> a = null;
+ this.methods.stream()
+ .filter(method -> method.getName().equals(directCallee.getContent()))
+ .findAny()
+ .ifPresent(cluster::add);
+ cluster.addAll(getIndirectCallees(visited, rootPackage, directCallee));
+ }
+ return cluster;
}
- private void rankMethods(boolean cluster) {
- if (cluster) {
- clusterMethods();
+ private List<Collection<Method>> clusterMethods() {
+ List<Method> methods = new ArrayList<>(this.methods);
+ List<Collection<Method>> clusters = new ArrayList<>();
+ List<Node<String>> visited = new ArrayList<>();
+ while (!methods.isEmpty()) {
+ Method method = methods.remove(0);
+ Collection<Method> treeCluster = getTreeCluster(visited, method);
+ methods.removeAll(treeCluster);
+ clusters.add(treeCluster);
}
+ return clusters;
}
- private void clusterMethods() {
+ private void rankClusters(List<Collection<Method>> clusters) {
+ Map<Collection<Method>, Double> clusterHasSavedTime = clusters.stream()
+ .collect(Collectors.toMap(
+ cluster -> cluster,
+ cluster -> cluster.stream().map(method -> method.getSavedTime()).max(Double::compare).get()));
+
+ Collections.sort(clusters, (cluster1, cluster2)
+ -> (Double.compare(clusterHasSavedTime.get(cluster1), clusterHasSavedTime.get(cluster2))));
}
-// 3.4 suggest cache implementation
- private void suggestImplementations() {
- for (Method method : this.methods) {
- System.out.println(method.getName());
- suggestImplementation(method);
+// 3.3 clustering and ranking
+ private void printClusters(boolean shouldRank) {
+ List<Collection<Method>> clusters = clusterMethods();
+ if (shouldRank) {
+ rankClusters(clusters);
+ }
+ for (int i = 0; i < clusters.size(); i++) {
+ Collection<Method> cluster = clusters.get(i);
+ System.out.println("Cluster#" + i);
+ cluster.forEach(System.out::println);
System.out.println();
}
}
+ private void printClusters() {
+ printClusters(true);
+ }
+
private void suggestImplementation(Method method) {
Map<String, CachingPerformance> cachingStrategyHasPerformance = method.simulateCachingStrategies();
CachingPerformance globalMultiCachePerformance = cachingStrategyHasPerformance.get("globalMultiCache");
@@ -232,4 +297,48 @@ public class MemoizeIt {
System.out.println("none");
}
}
+
+// 3.4 suggest cache implementation
+ private void suggestImplementations() {
+ for (Method method : this.methods) {
+ System.out.println(method.getName());
+ suggestImplementation(method);
+ System.out.println();
+ }
+ }
+
+ public void removeChangefulMethods() {
+ if (this.methods == null || this.methods.isEmpty()) {
+ throw new RuntimeException("Empty execution traces");
+ }
+ if (this.callGraph == null) {
+ throw new RuntimeException("Call Graph not set");
+ }
+ filterInitialCandidates();
+ refineCandidatesIteratively();
+ }
+
+ public void suggestCachingImplementations() {
+ if (this.methods == null || this.methods.isEmpty()) {
+ throw new RuntimeException("Empty execution traces");
+ }
+ if (this.callGraph == null) {
+ throw new RuntimeException("Call Graph not set");
+ }
+ printClusters();
+ suggestImplementations();
+ }
+
+ public void run() {
+ if (this.methods == null || this.methods.isEmpty()) {
+ throw new RuntimeException("Empty execution traces");
+ }
+ if (this.callGraph == null) {
+ throw new RuntimeException("Call Graph not set");
+ }
+ filterInitialCandidates();
+ 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 214aa5a..d330456 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
@@ -46,17 +46,19 @@ public class Method {
}
public long getTotalExecutionTime() {
- long averageExecutionTime = 0;
- for (Occurrence occurrence : this.occurrences) {
- averageExecutionTime += occurrence.getExecutionTime();
- }
- return averageExecutionTime;
+ return this.occurrences.stream()
+ .map(occurrence -> occurrence.getExecutionTime())
+ .reduce(Long::sum).get();
}
public long getAverageExecutionTime() {
return getTotalExecutionTime() / this.occurrences.size();
}
+ public double getSavedTime() {
+ return getAverageExecutionTime() * getPotentialHitRatio();
+ }
+
protected boolean wasFullyExplored() {
return this.fullyExplored;
}
@@ -100,12 +102,8 @@ public class Method {
}
protected double getPotentialHitRatio() {
- double potentialHitRatio = 0;
- for (Map.Entry<String, List<Occurrence>> entry : this.groupByParameter.entrySet()) {
- potentialHitRatio += entry.getValue().size();
- }
+ double potentialHitRatio = this.groupByParameter.entrySet().stream().map(entry -> entry.getValue().size()).reduce(Integer::sum).get();
potentialHitRatio = (potentialHitRatio - this.groupByParameter.size()) / potentialHitRatio;
- this.groupByParameter.clear();
return potentialHitRatio;
}
@@ -153,6 +151,12 @@ public class Method {
@Override
public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
if (!(obj instanceof Method)) {
return false;
}