memoizeit

added OccurrenceReference, getConcrete or load, partially

11/30/2018 12:47:36 PM

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