aplcache

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/FlowchartWorkFlow.java b/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/FlowchartWorkFlow.java
index ec1b496..2a269eb 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/FlowchartWorkFlow.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/FlowchartWorkFlow.java
@@ -4,12 +4,11 @@ import br.ufrgs.inf.prosoft.aplcache.flowchart.metrics.CacheabilityMetrics;
 import br.ufrgs.inf.prosoft.aplcache.flowchart.metrics.Thresholds;
 import br.ufrgs.inf.prosoft.aplcache.metadata.Method;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-public final class FlowchartWorkFlow {
+public class FlowchartWorkFlow {
 
     private static final Logger LOGGER = Logger.getLogger(FlowchartWorkFlow.class.getName());
 
@@ -20,7 +19,7 @@ public final class FlowchartWorkFlow {
         return this;
     }
 
-    private void countStats() {
+    private void calculateMetrics() {
         LOGGER.log(Level.INFO, "Counting stats of {0} methods", this.methods.size());
         Collections.sort(this.methods, (m1, m2) -> Integer.compare(m1.getOccurrencesSize(), m2.getOccurrencesSize()));
         this.methods.stream().parallel().forEach(Method::calculateMetrics);
@@ -32,22 +31,22 @@ public final class FlowchartWorkFlow {
         Thresholds.population = getPopulation();
         this.methods.stream().forEach(Method::calculateThresholds);
 
-        LOGGER.log(Level.INFO, "Average ExecutionTime: {0}", Thresholds.getAverageExecutionTime());
-        LOGGER.log(Level.INFO, "Average HitRatio: {0}", Thresholds.getAverageHitRatio());
-        LOGGER.log(Level.INFO, "Average MissRatio: {0}", Thresholds.getAverageMissRatio());
-        LOGGER.log(Level.INFO, "Average shareability: {0}", Thresholds.getAverageShareability());
-        LOGGER.log(Level.INFO, "StdDv ExecutionTime: {0}", Thresholds.getStdDevExecutionTimeRatio());
-        LOGGER.log(Level.INFO, "StdDv HitRatio: {0}", Thresholds.getStdDevHitRatio());
-        LOGGER.log(Level.INFO, "StdDv MissRatio: {0}", Thresholds.getStdDevMissRatio());
-        LOGGER.log(Level.INFO, "StdDv shareability: {0}", Thresholds.getStdDevShareability());
-        LOGGER.log(Level.INFO, "StdDv frequency: {0}", Thresholds.getStdDevFrequency());
+        LOGGER.log(Level.INFO, "\tAverage ExecutionTime: {0}", Thresholds.getAverageExecutionTime());
+        LOGGER.log(Level.INFO, "\tAverage HitRatio: {0}", Thresholds.getAverageHitRatio());
+        LOGGER.log(Level.INFO, "\tAverage MissRatio: {0}", Thresholds.getAverageMissRatio());
+        LOGGER.log(Level.INFO, "\tAverage shareability: {0}", Thresholds.getAverageShareability());
+        LOGGER.log(Level.INFO, "\tStdDv ExecutionTime: {0}", Thresholds.getStdDevExecutionTimeRatio());
+        LOGGER.log(Level.INFO, "\tStdDv HitRatio: {0}", Thresholds.getStdDevHitRatio());
+        LOGGER.log(Level.INFO, "\tStdDv MissRatio: {0}", Thresholds.getStdDevMissRatio());
+        LOGGER.log(Level.INFO, "\tStdDv shareability: {0}", Thresholds.getStdDevShareability());
+        LOGGER.log(Level.INFO, "\tStdDv frequency: {0}", Thresholds.getStdDevFrequency());
 
         LOGGER.log(Level.INFO, "Using {0} stdDev to calculate thresholds...", kStdDev);
-        LOGGER.log(Level.INFO, "Threshold ExecutionTime: {0}", Thresholds.expensivenessThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "Threshold HitRatio: {0}", Thresholds.hitThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "Threshold MissRatio: {0}", Thresholds.missThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "Threshold Shareability: {0}", Thresholds.shareabilityThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "Threshold frequency: {0}", Thresholds.frequencyThreshold(kStdDev));
+        LOGGER.log(Level.INFO, "\tThreshold ExecutionTime: {0}", Thresholds.expensivenessThreshold(kStdDev));
+        LOGGER.log(Level.INFO, "\tThreshold HitRatio: {0}", Thresholds.hitThreshold(kStdDev));
+        LOGGER.log(Level.INFO, "\tThreshold MissRatio: {0}", Thresholds.missThreshold(kStdDev));
+        LOGGER.log(Level.INFO, "\tThreshold Shareability: {0}", Thresholds.shareabilityThreshold(kStdDev));
+        LOGGER.log(Level.INFO, "\tThreshold frequency: {0}", Thresholds.frequencyThreshold(kStdDev));
     }
 
     public void filterCacheableInputs() {
@@ -55,21 +54,15 @@ public final class FlowchartWorkFlow {
     }
 
     public void filterCacheableInputs(int kStdDev) {
-        countStats();
+        calculateMetrics();
         calculateThresholds(kStdDev);
 
         LOGGER.log(Level.INFO, "Deciding if methods are cacheable...");
 
         CacheabilityMetrics.K_STANDARD_DEVIATION = kStdDev;
 
-        Iterator<Method> iterator = this.methods.iterator();
-        while (iterator.hasNext()) {
-            Method method = iterator.next();
-            method.filterCacheableInputs();
-            if (method.getGroupsOfOccurrences().isEmpty()) {
-                iterator.remove();
-            }
-        }
+        this.methods.forEach(Method::filterCacheableInputs);
+        this.methods.removeIf(method -> method.groupsOfOccurrences().count() == 0);
 
         LOGGER.log(Level.INFO, "{0} cacheable methods detected", this.methods.size());
     }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/metrics/CacheabilityPatternDecider.java b/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/metrics/CacheabilityPatternDecider.java
index 55f7065..03c7202 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/metrics/CacheabilityPatternDecider.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcache/flowchart/metrics/CacheabilityPatternDecider.java
@@ -35,4 +35,9 @@ public class CacheabilityPatternDecider {
         Optional<Boolean> isExpensive = CacheabilityMetrics.isExpensive(groupOfOccurrences);
         return isExpensive.isPresent() ? isExpensive.get() : true;
     }
+
+    public static boolean isNotCacheable(GroupOfOccurrences groupOfOccurrences) {
+        return !isCacheable(groupOfOccurrences);
+    }
+
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcache/Main.java b/src/main/java/br/ufrgs/inf/prosoft/aplcache/Main.java
index 26463fb..71da9dc 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcache/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcache/Main.java
@@ -95,19 +95,19 @@ public class Main {
         List<Trace> traces = TraceReader.parseFile(tracePath, Mode.valueOf(mode.toUpperCase()), window, shift);
         LOGGER.log(Level.INFO, "Grouping {0} traces by methods", traces.size());
         List<Method> methods = TraceReader.groupByMethods(traces);
-        LOGGER.log(Level.INFO, "grouped traces into {1} methods", methods.size());
+        LOGGER.log(Level.INFO, "grouped traces into {0} methods", methods.size());
         FlowchartWorkFlow flowchartWorkFlow = new FlowchartWorkFlow();
         flowchartWorkFlow.setMethods(methods);
         LOGGER.log(Level.INFO, "Filtering cacheable methods");
         flowchartWorkFlow.filterCacheableInputs(k);
         methods.forEach(method -> {
-            System.out.println(method + " : " + method.getGroupsOfOccurrences().size() + " parameters");
+            System.out.println(method + " : " + method.groupsOfOccurrences().count() + " parameters");
         });
         try (FileWriter fileWriter = new FileWriter(outputPath)) {
             JsonObject jsonCacheableParameters = new JsonObject();
             methods.forEach(method -> {
                 JsonArray cacheableParameters = new JsonArray();
-                method.getGroupsOfOccurrences().forEach(group -> {
+                method.groupsOfOccurrences().forEach(group -> {
                     cacheableParameters.add(group.getParameters());
                 });
                 jsonCacheableParameters.add(method.getName(), cacheableParameters);
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Method.java b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Method.java
index 04b83fb..f791336 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Method.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Method.java
@@ -6,17 +6,16 @@
 package br.ufrgs.inf.prosoft.aplcache.metadata;
 
 import br.ufrgs.inf.prosoft.aplcache.flowchart.metrics.CacheabilityPatternDecider;
-import com.google.gson.Gson;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  *
@@ -36,6 +35,11 @@ public class Method {
         this.occurrences = new ArrayList<>();
     }
 
+    public Method(String name, List<Occurrence> occurrences) {
+        this.name = name;
+        this.occurrences = occurrences;
+    }
+
     public String getName() {
         return name;
     }
@@ -49,21 +53,26 @@ public class Method {
         return this.occurrences.size();
     }
 
-    public List<GroupOfOccurrences> getGroupsOfOccurrences() {
-        return groupsOfOccurrences;
+    public Stream<Occurrence> occurrences() {
+        if (this.occurrences == null) {
+            throw new RuntimeException("Occurrences already consumed");
+        }
+        return this.occurrences.stream();
+    }
+
+    public Stream<GroupOfOccurrences> groupsOfOccurrences() {
+        return this.groupsOfOccurrences.stream();
     }
 
     private void groupByParameter() {
-        LOGGER.log(Level.INFO, "Grouping by parameters {0} occurrences of {1}", new Object[]{this.name, this.occurrences.size()});
+        LOGGER.log(Level.FINE, "Grouping by parameters {0} occurrences of {1}", new Object[]{this.name, this.occurrences.size()});
         Map<String, GroupOfOccurrences> groupByParameter = new HashMap<>();
         this.occurrences.stream().parallel().forEach(new Consumer<Occurrence>() {
 
             private int i;
-            private final Gson gson;
 
             {
                 this.i = 0;
-                this.gson = new Gson();
             }
 
             @Override
@@ -75,7 +84,7 @@ public class Method {
                         System.out.println();
                     }
                 }
-                String parameters = this.gson.toJson(occurrence.getParameters());
+                String parameters = occurrence.getParametersSerialised();
                 synchronized (groupByParameter) {
                     try {
                         groupByParameter.get(parameters).addOccurrence(occurrence);
@@ -101,13 +110,7 @@ public class Method {
     }
 
     public void filterCacheableInputs() {
-        Iterator<GroupOfOccurrences> iterator = this.groupsOfOccurrences.iterator();
-        while (iterator.hasNext()) {
-            GroupOfOccurrences groupOfOccurrences = iterator.next();
-            if (!CacheabilityPatternDecider.isCacheable(groupOfOccurrences)) {
-                iterator.remove();
-            }
-        }
+        this.groupsOfOccurrences.removeIf(CacheabilityPatternDecider::isNotCacheable);
     }
 
     @Override
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Occurrence.java b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Occurrence.java
index 3f38c56..b705d2f 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Occurrence.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/Occurrence.java
@@ -1,5 +1,7 @@
 package br.ufrgs.inf.prosoft.aplcache.metadata;
 
+import com.google.gson.Gson;
+
 public abstract class Occurrence {
 
     private final long startTime;
@@ -12,6 +14,14 @@ public abstract class Occurrence {
         this.userId = userId;
     }
 
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public long getEndTime() {
+        return endTime;
+    }
+
     public long getExecutionTime() {
         return endTime - startTime;
     }
@@ -24,4 +34,9 @@ public abstract class Occurrence {
 
     public abstract Object getReturnValue();
 
+    public String getParametersSerialised() {
+        Gson gson = new Gson();
+        return gson.toJson(getParameters());
+    }
+
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceConcrete.java b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceConcrete.java
index 920fa3a..de90413 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceConcrete.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceConcrete.java
@@ -13,6 +13,7 @@ public class OccurrenceConcrete extends Occurrence {
 
     private final Object[] parameters;
     private final Object returnValue;
+    private String parametersSerialised;
 
     public OccurrenceConcrete(Object[] arguments, Object returnedValue, long startTime, long endTime, String userId) {
         super(startTime, endTime, userId);
@@ -29,4 +30,13 @@ public class OccurrenceConcrete extends Occurrence {
     public Object getReturnValue() {
         return this.returnValue;
     }
+
+    @Override
+    public String getParametersSerialised() {
+        if (this.parametersSerialised == null) {
+            this.parametersSerialised = super.getParametersSerialised();
+        }
+        return this.parametersSerialised;
+    }
+
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceReference.java b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceReference.java
index d5c4e5d..45451c3 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceReference.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcache/metadata/OccurrenceReference.java
@@ -24,6 +24,10 @@ public class OccurrenceReference extends Occurrence {
         this.index = index;
     }
 
+    public int getIndex() {
+        return index;
+    }
+
     @Override
     public Object[] getParameters() {
         List<Parameter> parameters = Traces.getTraceParameter(this.index);