memoizeit
Changes
pom.xml 1(+1 -0)
Details
pom.xml 1(+1 -0)
diff --git a/pom.xml b/pom.xml
index c86f907..49d20a0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
+ <name>MemoizeIt</name>
<groupId>br.ufrgs.inf.prosoft.memoizeit</groupId>
<artifactId>MemoizeIt</artifactId>
<version>1.0</version>
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 8eeac6c..d9a5bfc 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
@@ -14,11 +14,11 @@ 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;
+import java.util.stream.Stream;
/**
*
@@ -26,13 +26,15 @@ import java.util.logging.Logger;
*/
public class CallGraphReader {
+ private static final Logger logger = Logger.getLogger(CallGraphReader.class.getName());
+
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) {
+ Stream<String> lines = Files.lines(Paths.get(path));
+ lines.forEach(line -> {
if (line.charAt(0) != 'M') {
- continue;
+ return;
}
int indexOfSpace = line.indexOf(" ");
String callerString = line.substring(2, indexOfSpace);
@@ -50,10 +52,10 @@ public class CallGraphReader {
callHasNode.put(calleeString, calleeNode);
}
callerNode.addLink(calleeNode);
- }
+ });
return new Graph<>(callHasNode);
} catch (IOException ex) {
- Logger.getLogger(CallGraphReader.class.getName()).log(Level.SEVERE, null, ex);
+ logger.log(Level.SEVERE, "Failed to open {0}", path);
}
return new Graph<>();
}
@@ -61,10 +63,10 @@ public class CallGraphReader {
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) {
+ Stream<String> lines = Files.lines(Paths.get(path));
+ lines.forEach(line -> {
if (line.charAt(0) != 'M') {
- continue;
+ return;
}
int indexOfSpace = line.indexOf(" ");
String callerString = line.substring(2, indexOfSpace);
@@ -77,9 +79,9 @@ public class CallGraphReader {
nodeHasLinks.put(callerString, links);
}
links.add(calleeString);
- }
+ });
} catch (IOException ex) {
- Logger.getLogger(CallGraphReader.class.getName()).log(Level.SEVERE, null, ex);
+ logger.log(Level.SEVERE, null, ex);
}
return nodeHasLinks;
}
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 19fc7e8..2d32a79 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
@@ -10,6 +10,8 @@ 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;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
*
@@ -17,7 +19,11 @@ import java.util.List;
*/
public class Main {
+ private static final Logger logger = Logger.getLogger(Main.class.getName());
+
public static void main(String[] args) {
+ System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT+%1$tL] [%4$-7s] [MemoizeIt] %5$s %n");
+
String tracePath = null;
String callGraphPath = null;
if (args.length < 2) {
@@ -27,8 +33,11 @@ public class Main {
tracePath = args[0];
callGraphPath = args[1];
}
+ logger.log(Level.INFO, "Reading callgraph");
Graph<String> graph = CallGraphReader.parseFile(callGraphPath);
- List<Trace> traces = TraceReader.parseFile(tracePath);
+ logger.log(Level.INFO, "Reading traces");
+ List<Trace> traces = TraceReader.partiallyParseFile(tracePath);
+ logger.log(Level.INFO, "Grouping methods");
List<Method> methods = TraceReader.groupByMethods(traces);
MemoizeIt memoizeIt = new MemoizeIt();
memoizeIt.setCallGraph(graph);
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 468fee0..4c4b296 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,11 +7,19 @@ 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.OccurrenceConcrete;
+import br.ufrgs.inf.prosoft.memoizeit.OccurrenceReference;
import br.ufrgs.inf.prosoft.memoizeit.Parameter;
import br.ufrgs.inf.prosoft.trace.Trace;
+import br.ufrgs.inf.prosoft.trace.TraceConcrete;
+import br.ufrgs.inf.prosoft.trace.TraceReference;
+import br.ufrgs.inf.prosoft.trace.Traces;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -20,8 +28,10 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Stream;
/**
*
@@ -29,21 +39,76 @@ import java.util.logging.Logger;
*/
public class TraceReader {
+ private static final Logger logger = Logger.getLogger(TraceReader.class.getName());
+
+ public static List<Trace> partiallyParseFile(String path) {
+ Traces.PATH = path;
+ return parseFile(path, true);
+ }
+
public static List<Trace> parseFile(String path) {
+ return parseFile(path, false);
+ }
+
+ public static String getLineCount(String path) throws IOException {
+ try {
+ Process process = Runtime.getRuntime().exec("wc -l " + path);
+ Thread.sleep(2000);
+ if (process.isAlive()) {
+ return "-2";
+ }
+ InputStream inputStream = process.getInputStream();
+ StringBuilder count = new StringBuilder();
+ int c;
+ while (true) {
+ c = inputStream.read();
+ if (c == 32 || c == -1 || c == 10) {
+ break;
+ }
+ count.append((char) c);
+ }
+ return count.toString();
+ } catch (Exception ex) {
+ }
+ return "-1";
+ }
+
+ private static List<Trace> parseFile(String path, boolean partial) {
List<Trace> traces = new ArrayList<>();
try {
- List<String> lines = Files.readAllLines(Paths.get(path));
+ logger.log(Level.INFO, "Parsing {0} traces", getLineCount(path));
+ Stream<String> lines = Files.lines(Paths.get(path));
Gson gson = new Gson();
- for (String line : lines) {
- try {
- Trace trace = gson.fromJson(line, Trace.class);
- traces.add(trace);
- } catch (JsonSyntaxException e) {
- System.err.println("Malformed Trace: " + line);
+ lines.forEach(new Consumer<String>() {
+ int i = 0;
+
+ @Override
+ public void accept(String line) {
+ try {
+ Trace trace;
+ if (partial) {
+ trace = gson.fromJson(line, TraceReference.class);
+ ((TraceReference) trace).setIndex(i);
+ } else {
+ trace = gson.fromJson(line, TraceConcrete.class);
+ }
+ traces.add(trace);
+ System.out.print(".");
+ if (i != 0 && i % 100 == 0) {
+ System.out.println();
+ }
+ i++;
+ } catch (JsonSyntaxException e) {
+ if (line.length() > 2000) {
+ line = line.substring(0, 2000);
+ }
+ logger.log(Level.INFO, "\nMalformed Trace {0}: {1}", new Object[]{i, line});
+ }
}
- }
+ });
+ System.out.println();
} catch (IOException ex) {
- Logger.getLogger(TraceReader.class.getName()).log(Level.SEVERE, null, ex);
+ logger.log(Level.SEVERE, null, ex);
}
return traces;
}
@@ -54,11 +119,17 @@ public class TraceReader {
while (!traces.isEmpty()) {
Trace trace = traces.remove(0);
try {
- List<Parameter> parameters = new ArrayList<>();
- trace.getParameters().forEach((parameter) -> {
- parameters.add(new Parameter(parameter.getType(), parameter.getData()));
- });
- Occurrence occurrence = new Occurrence(trace.getInstance(), trace.getReturn().getData(), parameters, trace.getStartTime(), trace.getEndTime());
+ Occurrence occurrence;
+ if (trace instanceof TraceReference) {
+ TraceReference traceReference = (TraceReference) trace;
+ occurrence = new OccurrenceReference(traceReference.getIndex(), trace.getInstance(), trace.getStartTime(), trace.getEndTime());
+ } else {
+ List<Parameter> parameters = new ArrayList<>();
+ trace.getParameters().forEach((parameter) -> {
+ parameters.add(new Parameter(parameter.getType(), parameter.getData()));
+ });
+ occurrence = new OccurrenceConcrete(trace.getInstance(), trace.getReturn().getData(), parameters, trace.getStartTime(), trace.getEndTime());
+ }
try {
methodNameHasOccurrences.get(trace.getName()).add(occurrence);
} catch (Exception ex) {
@@ -70,7 +141,7 @@ public class TraceReader {
}
}
} catch (Exception e) {
- System.err.println("Trace discarted: " + trace);
+ logger.log(Level.INFO, "Trace discarted: {0}", trace);
}
}
List<Method> methods = new 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 b7b99e9..43e5f54 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/MemoizeIt.java
@@ -13,6 +13,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
@@ -40,6 +42,8 @@ public class MemoizeIt {
// Call Graph
private Graph<String> callGraph;
+ private static final Logger logger = Logger.getLogger(MemoizeIt.class.getName());
+
public MemoizeIt() {
this.maxDepthReached = false;
this.minimumHitRatio = 0.5;
@@ -90,18 +94,19 @@ public class MemoizeIt {
}
private void estimateTotalProgramExecution() {
- this.totalProgramExecution = this.methods.stream().map(method -> method.getTotalExecutionTime()).reduce(Long::sum).get();
+ this.totalProgramExecution = this.methods.stream().map(Method::getTotalExecutionTime).reduce(Long::sum).get();
}
private void calculateAverageExecutionTime() {
- this.averageProgramExecution = this.methods.stream().map(method -> method.getAverageExecutionTime()).reduce(Long::sum).get();
+ this.averageProgramExecution = this.methods.stream().map(Method::getAverageExecutionTime).reduce(Long::sum).get();
this.averageProgramExecution /= this.methods.size();
}
// 3.1 time and frequency profiling
private void filterInitialCandidates() {
+ logger.log(Level.INFO, "Fitering {0} initial candidates", this.methods.size());
if (this.totalProgramExecution == 0) {
- System.out.println("Warning: total program execution not informed. Using average of calls");
+ logger.log(Level.WARNING, "Total program execution not informed. Using average of calls");
calculateAverageExecutionTime();
}
int i = 0;
@@ -121,11 +126,13 @@ public class MemoizeIt {
}
private void removeUnusedFields() {
+ logger.log(Level.INFO, "Removing unused fields of {0} candidates left", this.methods.size());
this.methods.forEach(method -> method.removeUnusedFields(this.callGraph.getNode(method.getName())));
}
// 3.2 input-output profiling
- private void refineCandidates() {
+ private void refineCandidatesExhaustively() {
+ logger.log(Level.INFO, "Exhaustively refining {0} candidates", this.methods.size());
refineCandidates(Integer.MAX_VALUE);
}
@@ -164,16 +171,17 @@ public class MemoizeIt {
}
private void refineCandidatesIteratively() {
+ logger.log(Level.INFO, "Iteratively refining {0} candidates", this.methods.size());
int depth = 1;
while (true) {
- System.out.println("Exploring depth " + depth);
+ logger.log(Level.INFO, "Exploring depth {0}", depth);
refineCandidates(depth);
if (this.methods.isEmpty()) {
- System.out.println("No caching candidates left to explore");
+ logger.log(Level.INFO, "No caching candidates left to explore");
break;
}
if (this.maxDepthReached) {
- System.out.println("Max depth reached");
+ logger.log(Level.INFO, "Max depth reached");
break;
}
depth *= 2;
@@ -191,7 +199,7 @@ public class MemoizeIt {
this.methods.stream()
.filter(method -> method.getName().equals(directCallee.getContent()))
.findAny()
- .ifPresent((callee) -> {
+ .ifPresent(callee -> {
String calleePackage = callee.getName().substring(0, callee.getName().lastIndexOf("."));
if (calleePackage.equals(rootPackage)) {
cluster.add(callee);
@@ -251,8 +259,10 @@ public class MemoizeIt {
// 3.3 clustering and ranking
private void printClusters(boolean shouldRank) {
+ logger.log(Level.INFO, "Clustering {0} cacheable methods", this.methods.size());
List<Collection<Method>> clusters = clusterMethods();
if (shouldRank) {
+ logger.log(Level.INFO, "Ranking {0} clusters", clusters.size());
rankClusters(clusters);
}
for (int i = 0; i < clusters.size(); i++) {
@@ -302,6 +312,7 @@ public class MemoizeIt {
// 3.4 suggest cache implementation
private void suggestImplementations() {
+ logger.log(Level.INFO, "Suggesting caching implementation");
for (Method method : this.methods) {
System.out.println(method.getName());
suggestImplementation(method);
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 b2b4eb0..489727f 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Method.java
@@ -14,6 +14,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
*
@@ -21,6 +25,8 @@ import java.util.Objects;
*/
public class Method {
+ private static final Logger logger = Logger.getLogger(Method.class.getName());
+
private final String name;
private final List<Occurrence> occurrences;
private Map<String, List<Occurrence>> groupByParameter;
@@ -48,7 +54,7 @@ public class Method {
public long getTotalExecutionTime() {
return this.occurrences.stream()
- .map(occurrence -> occurrence.getExecutionTime())
+ .map(Occurrence::getExecutionTime)
.reduce(Long::sum).get();
}
@@ -66,7 +72,7 @@ public class Method {
protected void groupByParameter(int depth) {
this.groupByParameter = new HashMap<>();
- this.occurrences.forEach((occurrence) -> {
+ this.occurrences.forEach(occurrence -> {
if (depth < Integer.MAX_VALUE) {
Occurrence truncated = occurrence.getView(depth);
this.fullyExplored = truncated == occurrence;
@@ -93,7 +99,7 @@ public class Method {
continue;
}
Occurrence firstOccurrence = entry.getValue().get(0);
- if (entry.getValue().stream().anyMatch((occurrence) -> (occurrence.getReturnValue() != null && !occurrence.getReturnValue().equals(firstOccurrence.getReturnValue())))) {
+ if (entry.getValue().stream().anyMatch(occurrence -> occurrence.getReturnValue() != null && !occurrence.getReturnValue().equals(firstOccurrence.getReturnValue()))) {
return true;
}
}
@@ -107,11 +113,25 @@ public class Method {
}
protected void removeUnusedFields(Node<String> methodNode) {
+ logger.log(Level.INFO, "Analysing fields of {0} occurrences of {1}", new Object[]{this.occurrences.size(), this.name});
if (methodNode == null) {
- System.err.println("methodNode null: " + this.name);
+ logger.log(Level.WARNING, "methodNode null: {0}", this.name);
return;
}
- this.occurrences.stream().forEach(occurrence -> occurrence.removeUnusedFields(methodNode));
+ this.occurrences.stream().parallel()
+ .forEach(new Consumer<Occurrence>() {
+ private int i = 1;
+
+ @Override
+ public void accept(Occurrence occurrence) {
+ System.out.print(".");
+ if (i++ % 100 == 0) {
+ System.out.println();
+ }
+ occurrence.removeUnusedFields(methodNode);
+ }
+ });
+ System.out.println();
}
protected Map<String, CachingPerformance> simulateCachingStrategies() {
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 5a7dce4..27fd05f 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/Occurrence.java
@@ -7,46 +7,38 @@ 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;
/**
*
* @author romulo
*/
-public class Occurrence {
+public abstract class Occurrence {
private final String instance;
- private final Object returnValue;
- private final List<Parameter> parameters;
private final long startTime;
private final long endTime;
- private boolean truncated;
- public Occurrence(String instance, Object returnValue, List<Parameter> parameters, long startTime, long endTime) {
+ public Occurrence(String instance, long startTime, long endTime) {
this.instance = instance;
- this.returnValue = returnValue;
- this.parameters = parameters;
this.startTime = startTime;
this.endTime = endTime;
- this.truncated = true;
}
public String getInstance() {
return instance;
}
- public Object getReturnValue() {
- return this.returnValue;
+ public abstract Object getReturnValue();
+
+ public abstract List<Parameter> getParameters();
+
+ protected long getStartTime() {
+ return startTime;
}
- public List<Parameter> getParameters() {
- return this.parameters;
+ protected long getEndTime() {
+ return endTime;
}
public long getExecutionTime() {
@@ -54,61 +46,29 @@ public class Occurrence {
}
protected Occurrence getView(int depth) {
- if (!this.truncated) {
- return this;
- }
- this.truncated = false;
- Object returnValue = ObjectUtils.deepCopy(this.returnValue);
- Action onTruncate = () -> {
- this.truncated = true;
- };
- ObjectUtils.truncateObject(returnValue, 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;
+ return getConcrete().getView(depth);
+ }
+
+ protected Occurrence removeUnusedFields(Node<String> methodNode) {
+ return loadConcrete().removeUnusedFields(methodNode);
}
protected void simulateCaching(Cache cache) {
- String key = this.parameters.toString();
+ String key = getParameters().toString();
Object cached = cache.get(key);
if (cached == null) {
- cache.put(key, this.returnValue);
- } else if (!cached.equals(this.returnValue)) {
+ cache.put(key, getReturnValue());
+ } else if (!cached.equals(getReturnValue())) {
cache.invalidate(key);
}
}
- 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();
- }
- }
-
+ public OccurrenceConcrete getConcrete() {
+ return (OccurrenceConcrete) this;
}
- 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);
- }
- }
+ public Occurrence loadConcrete() {
+ return this;
}
}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/OccurrenceConcrete.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/OccurrenceConcrete.java
new file mode 100644
index 0000000..2bad9a6
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/OccurrenceConcrete.java
@@ -0,0 +1,95 @@
+/*
+ * 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;
+
+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;
+
+/**
+ *
+ * @author romulo
+ */
+public class OccurrenceConcrete extends Occurrence {
+
+ private final Object returnValue;
+ private final List<Parameter> parameters;
+ private boolean truncated;
+
+ public OccurrenceConcrete(String instance, Object returnValue, List<Parameter> parameters, long startTime, long endTime) {
+ super(instance, startTime, endTime);
+ this.returnValue = returnValue;
+ this.parameters = parameters;
+ this.truncated = true;
+ }
+
+ @Override
+ public Object getReturnValue() {
+ return this.returnValue;
+ }
+
+ @Override
+ public List<Parameter> getParameters() {
+ return this.parameters;
+ }
+
+ 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();
+ }
+ }
+
+ }
+
+ @Override
+ protected Occurrence removeUnusedFields(Node<String> methodNode) {
+ for (Parameter parameter : getParameters()) {
+ 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);
+ }
+ }
+ return this;
+ }
+
+ @Override
+ protected OccurrenceConcrete getView(int depth) {
+ if (!this.truncated) {
+ return this;
+ }
+ this.truncated = false;
+ Object returnValue = ObjectUtils.deepCopy(this.returnValue);
+ Action onTruncate = () -> {
+ this.truncated = true;
+ };
+ ObjectUtils.truncateObject(returnValue, 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));
+ }
+ OccurrenceConcrete occurrenceConcrete = new OccurrenceConcrete(getInstance(), returnValue, parameters, getStartTime(), getEndTime());
+ return occurrenceConcrete;
+ }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/memoizeit/OccurrenceReference.java b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/OccurrenceReference.java
new file mode 100644
index 0000000..16c648f
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/memoizeit/OccurrenceReference.java
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+import br.ufrgs.inf.prosoft.trace.TraceConcrete;
+import br.ufrgs.inf.prosoft.trace.Traces;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author romulo
+ */
+public class OccurrenceReference extends Occurrence {
+
+ private final int index;
+ private OccurrenceConcrete occurrenceConcrete;
+
+ public OccurrenceReference(int index, String instance, long startTime, long endTime) {
+ super(instance, startTime, endTime);
+ this.index = index;
+ }
+
+ @Override
+ public Object getReturnValue() {
+ if (this.occurrenceConcrete != null) {
+ return this.occurrenceConcrete.getReturnValue();
+ }
+ TraceConcrete traceConcrete = Traces.getTraceConcrete(this.index);
+ if (traceConcrete != null && traceConcrete.getReturn() != null) {
+ return traceConcrete.getReturn().getData();
+ }
+ return null;
+ }
+
+ @Override
+ public List<Parameter> getParameters() {
+ if (this.occurrenceConcrete != null) {
+ return this.occurrenceConcrete.getParameters();
+ }
+ TraceConcrete traceConcrete = Traces.getTraceConcrete(this.index);
+ if (traceConcrete != null && traceConcrete.getParameters() != null) {
+ return traceConcrete.getParameters().stream()
+ .map(parameter -> new Parameter(parameter.getType(), parameter.getData()))
+ .collect(Collectors.toList());
+ }
+ return new ArrayList<>();
+ }
+
+ @Override
+ public OccurrenceConcrete getConcrete() {
+ TraceConcrete traceConcrete = Traces.getTraceConcrete(this.index);
+ Object returnValue = null;
+ List<Parameter> parameters = new ArrayList<>();
+ if (traceConcrete != null) {
+ returnValue = traceConcrete.getReturn();
+ parameters = traceConcrete.getParameters().stream()
+ .map(parameter -> new Parameter(parameter.getType(), parameter.getData()))
+ .collect(Collectors.toList());
+ }
+ return new OccurrenceConcrete(getInstance(), returnValue, parameters, getStartTime(), getEndTime());
+ }
+
+ @Override
+ public OccurrenceConcrete loadConcrete() {
+ this.occurrenceConcrete = getConcrete();
+ return this.occurrenceConcrete;
+ }
+
+ public OccurrenceReference cleanConcrete() {
+ this.occurrenceConcrete = null;
+ return this;
+ }
+
+}