aplcachetf

code style. replaced SVPTIC for Euclidean Distance from objetive.

1/10/2021 6:01:53 AM

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/adapter/TraceReader.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/adapter/TraceReader.java
index d1f63d4..bb4d95a 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/adapter/TraceReader.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/adapter/TraceReader.java
@@ -12,6 +12,7 @@ import br.ufrgs.inf.prosoft.tfcache.metadata.OccurrenceReference;
 import br.ufrgs.inf.prosoft.trace.Parameter;
 import br.ufrgs.inf.prosoft.trace.Trace;
 import br.ufrgs.inf.prosoft.trace.TraceReference;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -21,7 +22,6 @@ import java.util.logging.Logger;
 import java.util.stream.Collectors;
 
 /**
- *
  * @author romulo
  */
 public class TraceReader extends br.ufrgs.inf.prosoft.trace.reader.TraceReader {
@@ -39,9 +39,7 @@ public class TraceReader extends br.ufrgs.inf.prosoft.trace.reader.TraceReader {
                     occurrence = new OccurrenceReference(traceReference.getIndex(), traceReference.getInstance(), trace.getStartTime(), trace.getEndTime(), trace.getUserSession());
                 } else {
                     occurrence = new OccurrenceConcrete(trace.getInstance(),
-                            trace.getParameters().stream()
-                                    .map(Parameter::getData)
-                                    .collect(Collectors.toList()).toArray(),
+                            trace.getParameters().stream().map(Parameter::getData).toArray(),
                             trace.getReturn().getData(),
                             trace.getStartTime(),
                             trace.getEndTime(),
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/APLCache.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/APLCache.java
index db01d6e..ca6ca94 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/APLCache.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/APLCache.java
@@ -1,8 +1,3 @@
-/*
- * 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.aplcachetf.extension;
 
 import br.ufrgs.inf.prosoft.aplcachetf.extension.metadata.Method;
@@ -11,122 +6,117 @@ import br.ufrgs.inf.prosoft.aplcachetf.extension.metrics.Thresholds;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonObject;
+
 import java.io.FileWriter;
 import java.io.IOException;
+import java.text.MessageFormat;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-/**
- *
- * @author root
- */
 public class APLCache {
 
-    private static final Logger LOGGER = Logger.getLogger(APLCache.class.getName());
-
-    private final List<Method> methods;
-
-    public APLCache(List<Method> methods) {
-        this.methods = methods;
-    }
-
-    private void calculateMetrics() {
-        LOGGER.log(Level.INFO, "Calculating metrics for {0} methods...", this.methods.size());
-        this.methods.stream().parallel().forEach(Method::calculateMetrics);
-    }
-
-    private void calculateThresholds(int kStdDev) {
-        LOGGER.log(Level.INFO, "Calculating thresholds for {0} methods with {1} stdDev...", new Object[]{this.methods.size(), kStdDev});
-
-        Thresholds.reset();
-        Thresholds.population = getPopulation();
-        this.methods.stream().forEach(Method::calculateThresholds);
-
-        LOGGER.log(Level.INFO, "\tAverage   ExecutionTime:           {0}", Thresholds.getAverageExecutionTime());
-        LOGGER.log(Level.INFO, "\tStdDv     ExecutionTime:           {0}", Thresholds.getStdDevExecutionTimeRatio());
-        LOGGER.log(Level.INFO, "\tThreshold ExecutionTime:           {0}", Thresholds.expensivenessThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "\tAverage   HitRatio:                {0}", Thresholds.getAverageHitRatio());
-        LOGGER.log(Level.INFO, "\tStdDv     HitRatio:                {0}", Thresholds.getStdDevHitRatio());
-        LOGGER.log(Level.INFO, "\tThreshold HitRatio:                {0}", Thresholds.hitThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "\tAverage   MissRatio:               {0}", Thresholds.getAverageMissRatio());
-        LOGGER.log(Level.INFO, "\tStdDv     MissRatio:               {0}", Thresholds.getStdDevMissRatio());
-        LOGGER.log(Level.INFO, "\tThreshold MissRatio:               {0}", Thresholds.missThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "\tAverage   Shareability:            {0}", Thresholds.getAverageShareability());
-        LOGGER.log(Level.INFO, "\tStdDv     Shareability:            {0}", Thresholds.getStdDevShareability());
-        LOGGER.log(Level.INFO, "\tThreshold Shareability:            {0}", Thresholds.shareabilityThreshold(kStdDev));
-        LOGGER.log(Level.INFO, "\tAverage   SavedTimePerTimeInCache: {0}", Thresholds.getAverageSavedTimePerTimeInCache());
-        LOGGER.log(Level.INFO, "\tStdDv     SavedTimePerTimeInCache: {0}", Thresholds.getStdDevSavedTimePerTimeInCache());
-        LOGGER.log(Level.INFO, "\tThreshold SavedTimePerTimeInCache: {0}", Thresholds.savedTimePerTimeInCacheThreshold(kStdDev));
-    }
-
-    private void filterCacheableInputs(int kStdDev) {
-        LOGGER.log(Level.INFO, "Filtering inputs of {0} methods under {1} stdDev threshold...", new Object[]{this.methods.size(), kStdDev});
-        CacheabilityMetrics.K_STANDARD_DEVIATION = kStdDev;
-        this.methods.forEach(Method::filterCacheableInputs);
-        this.methods.removeIf(method -> method.groupsOfOccurrences().count() == 0);
-    }
-
-    private void removeSingleOccurrences() {
-        int initialMethodsSize = this.methods.size();
-        LOGGER.log(Level.INFO, "Removing not reusable inputs from {0} methods", this.methods.size());
-        this.methods.forEach(Method::removeSingleOccurrences);
-        LOGGER.log(Level.INFO, "Removing not reusable methods from {0} methods", this.methods.size());
-        this.methods.removeIf(method -> method.groupsOfOccurrences().count() == 0);
-        int removedMethods = initialMethodsSize - this.methods.size();
-        if (removedMethods > 0) {
-            LOGGER.log(Level.INFO, "Removed {0} of {1} not reusable methods", new Object[]{removedMethods, initialMethodsSize});
-        }
-    }
-
-    public void recommend(String outputPath) {
-        recommend(0, outputPath);
-    }
-
-    public void recommend(int kStdDev, String outputPath) {
-        LOGGER.log(Level.INFO, "Recommending TTL per method for {0} methods", this.methods.size());
-        removeSingleOccurrences();
-        calculateMetrics();
-        calculateThresholds(kStdDev);
-        filterCacheableInputs(kStdDev);
-
-        LOGGER.log(Level.INFO, "{0} cacheable methods detected", this.methods.size());
-        this.methods.sort((method1, method2) -> method2.getEstimatedSavedTimePerTimeInCache().compareTo(method1.getEstimatedSavedTimePerTimeInCache()));
-
-        this.methods.forEach(method -> {
-            if (method.getBestMetrics() != null) {
-                System.out.println(method.getName()
-                        + " Occurrences " + method.getOccurrencesSize()
-                        + " Inputs " + method.groupsOfOccurrences().count()
-                        + " TTL " + method.getBestMetrics().getTtl()
-                        + " STpTiC " + method.getBestMetrics().getSavedTimePerTimeInCache()
-                        + " Saves " + method.getBestMetrics().getSavedTime()
-                        + " Hits " + method.getBestMetrics().getHits()
-                        + " Stales " + method.getBestMetrics().getStales());
-            } else {
-                System.out.println(method.getName()
-                        + " Occurrences " + method.getOccurrencesSize()
-                        + " Inputs " + method.groupsOfOccurrences().count());
-            }
-        });
-        try (FileWriter fileWriter = new FileWriter(outputPath)) {
-            JsonObject jsonCacheableParameters = new JsonObject();
-            this.methods.forEach(method -> {
-                JsonObject cacheableParameters = new JsonObject();
-                method.groupsOfOccurrences().forEach(group -> {
-                    cacheableParameters.addProperty(group.getParameters(), group.getTtl());
-                });
-                jsonCacheableParameters.add(method.getName(), cacheableParameters);
-            });
-            Gson gson = new GsonBuilder().setPrettyPrinting().create();
-            gson.toJson(jsonCacheableParameters, fileWriter);
-        } catch (IOException ex) {
-            LOGGER.log(Level.SEVERE, "invalid <outputPath>");
-        }
+  private static final Logger LOGGER = Logger.getLogger(APLCache.class.getName());
+
+  private final List<Method> methods;
+
+  public APLCache(List<Method> methods) {
+    this.methods = methods;
+  }
+
+  private void calculateMetrics() {
+    LOGGER.info(MessageFormat.format("Calculating metrics for {0} methods...", this.methods.size()));
+    this.methods.stream().parallel().forEach(Method::calculateMetrics);
+  }
+
+  private void calculateThresholds(int kStdDev) {
+    LOGGER.info(MessageFormat.format("Calculating thresholds for {0} methods with {1} stdDev...", this.methods.size(), kStdDev));
+
+    Thresholds.reset();
+    Thresholds.population = getPopulation();
+    this.methods.forEach(Method::calculateThresholds);
+
+    LOGGER.info(MessageFormat.format("\tAverage   ExecutionTime: {0}", Thresholds.getAverageExecutionTime()));
+    LOGGER.info(MessageFormat.format("\tStdDv     ExecutionTime: {0}", Thresholds.getStdDevExecutionTime()));
+    LOGGER.info(MessageFormat.format("\tThreshold ExecutionTime: {0}", Thresholds.expensivenessThreshold(kStdDev)));
+    LOGGER.info(MessageFormat.format("\tAverage   HitRatio:      {0}", Thresholds.getAverageHitRatio()));
+    LOGGER.info(MessageFormat.format("\tStdDv     HitRatio:      {0}", Thresholds.getStdDevHitRatio()));
+    LOGGER.info(MessageFormat.format("\tThreshold HitRatio:      {0}", Thresholds.hitThreshold(kStdDev)));
+    LOGGER.info(MessageFormat.format("\tAverage   MissRatio:     {0}", Thresholds.getAverageMissRatio()));
+    LOGGER.info(MessageFormat.format("\tStdDv     MissRatio:     {0}", Thresholds.getStdDevMissRatio()));
+    LOGGER.info(MessageFormat.format("\tThreshold MissRatio:     {0}", Thresholds.missThreshold(kStdDev)));
+    LOGGER.info(MessageFormat.format("\tAverage   Shareability:  {0}", Thresholds.getAverageShareability()));
+    LOGGER.info(MessageFormat.format("\tStdDv     Shareability:  {0}", Thresholds.getStdDevShareability()));
+    LOGGER.info(MessageFormat.format("\tThreshold Shareability:  {0}", Thresholds.shareabilityThreshold(kStdDev)));
+    LOGGER.info(MessageFormat.format("\tAverage   Distance:      {0}", Thresholds.getAverageDistance()));
+    LOGGER.info(MessageFormat.format("\tStdDv     Distance:      {0}", Thresholds.getStdDevDistance()));
+    LOGGER.info(MessageFormat.format("\tThreshold Distance:      {0}", Thresholds.distanceThreshold(kStdDev)));
+  }
+
+  private void filterCacheableInputs(int kStdDev) {
+    LOGGER.info(MessageFormat.format("Filtering inputs of {0} methods under {1} stdDev threshold...", this.methods.size(), kStdDev));
+    CacheabilityMetrics.K_STANDARD_DEVIATION = kStdDev;
+    this.methods.forEach(Method::filterCacheableInputs);
+    this.methods.removeIf(method -> method.groupsOfOccurrences().count() == 0);
+  }
+
+  private void removeSingleOccurrences() {
+    int initialMethodsSize = this.methods.size();
+    LOGGER.info(MessageFormat.format("Removing not reusable inputs from {0} methods", this.methods.size()));
+    this.methods.forEach(Method::removeSingleOccurrences);
+    LOGGER.info(MessageFormat.format("Removing not reusable methods from {0} methods", this.methods.size()));
+    this.methods.removeIf(method -> method.groupsOfOccurrences().count() == 0);
+    int removedMethods = initialMethodsSize - this.methods.size();
+    if (removedMethods > 0) LOGGER.info(MessageFormat.format("Removed {0} of {1} not reusable methods", removedMethods, initialMethodsSize));
+  }
+
+  public void recommend(String outputPath) {
+    recommend(0, outputPath);
+  }
+
+  public void recommend(int kStdDev, String outputPath) {
+    LOGGER.info(MessageFormat.format("Recommending TTL per method for {0} methods", this.methods.size()));
+    removeSingleOccurrences();
+    calculateMetrics();
+    calculateThresholds(kStdDev);
+    filterCacheableInputs(kStdDev);
+
+    LOGGER.info(MessageFormat.format("{0} cacheable methods detected", this.methods.size()));
+    this.methods.sort((method1, method2) -> Double.compare(method2.getEstimatedSavedTime(), method1.getEstimatedSavedTime()));
+
+    this.methods.forEach(method -> {
+      if (method.getBestTFMetrics() != null) {
+        System.out.println(method.getName()
+          + " Occurrences " + method.occurrences().count()
+          + " Inputs " + method.groupsOfOccurrences().count()
+          + " TTL " + method.getBestTFMetrics().getTtl()
+          + " Saves " + method.getBestTFMetrics().getSavedTime()
+          + " Hits " + method.getBestTFMetrics().getHits()
+          + " Computation " + method.getBestTFMetrics().getComputationTime()
+          + " TimeInCache " + method.getBestTFMetrics().getTimeInCache()
+          + " Stales " + method.getBestTFMetrics().getStales());
+      } else {
+        System.out.println(method.getName()
+          + " Occurrences " + method.occurrences().count()
+          + " Inputs " + method.groupsOfOccurrences().count());
+      }
+    });
+    try (FileWriter fileWriter = new FileWriter(outputPath)) {
+      JsonObject jsonCacheableParameters = new JsonObject();
+      this.methods.forEach(method -> {
+        JsonObject cacheableParameters = new JsonObject();
+        method.groupsOfOccurrences().forEach(group -> cacheableParameters.addProperty(group.getParameters(), group.getMetrics().getTtl()));
+        jsonCacheableParameters.add(method.getName(), cacheableParameters);
+      });
+      Gson gson = new GsonBuilder().setPrettyPrinting().create();
+      gson.toJson(jsonCacheableParameters, fileWriter);
+    } catch (IOException ex) {
+      LOGGER.log(Level.SEVERE, "invalid <outputPath>");
     }
+  }
 
-    private long getPopulation() {
-        return this.methods.stream().map(Method::getOccurrencesSize).reduce(Integer::sum).orElse(0);
-    }
+  private long getPopulation() {
+    return this.methods.stream().map(it -> it.occurrences().count()).reduce(Long::sum).orElse(0L);
+  }
 
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/GroupOfOccurrences.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/GroupOfOccurrences.java
index 575546c..8336b5d 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/GroupOfOccurrences.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/GroupOfOccurrences.java
@@ -1,110 +1,71 @@
-/*
- * 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.aplcachetf.extension.metadata;
 
 import br.ufrgs.inf.prosoft.aplcachetf.extension.metrics.Metrics;
 import br.ufrgs.inf.prosoft.aplcachetf.extension.metrics.Thresholds;
 import br.ufrgs.inf.prosoft.tfcache.Simulator;
 import br.ufrgs.inf.prosoft.tfcache.metadata.Occurrence;
-import java.math.BigDecimal;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+
+import java.util.Comparator;
 import java.util.List;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Stream;
-import org.apache.commons.lang3.builder.EqualsBuilder;
 
-/**
- *
- * @author root
- */
 public class GroupOfOccurrences {
 
-    private static final Logger LOGGER = Logger.getLogger(GroupOfOccurrences.class.getName());
-
-    private final String parameters;
-    private final List<Occurrence> occurrences;
-    private Metrics bestMetrics;
-
-    public GroupOfOccurrences(String parameters, List<Occurrence> occurrences) {
-        this.parameters = parameters;
-        this.occurrences = occurrences;
-    }
-
-    public String getParameters() {
-        return this.parameters;
-    }
-
-    public Stream<Occurrence> occurrences() {
-        return this.occurrences.stream();
-    }
-
-    public int getOccurrencesSize() {
-        return this.occurrences.size();
-    }
-
-    public Metrics getBestMetrics() {
-        if (this.bestMetrics == null) {
-            throw new RuntimeException("SavedTimePerTimeInCache must be calculated");
-        }
-        return this.bestMetrics;
-    }
+  private static final Logger LOGGER = Logger.getLogger(GroupOfOccurrences.class.getName());
 
-    public long getTtl() {
-        return getBestMetrics().getTfmetrics().getTtl();
-    }
+  private final String parameters;
+  private final List<Occurrence> occurrences;
+  private Metrics metrics;
 
-    public long getHits() {
-        return getBestMetrics().getTfmetrics().getHits();
-    }
+  public GroupOfOccurrences(String parameters, List<Occurrence> occurrences) {
+    this.parameters = parameters;
+    this.occurrences = occurrences;
+  }
 
-    public long getStales() {
-        return getBestMetrics().getTfmetrics().getStales();
-    }
+  public String getParameters() {
+    return this.parameters;
+  }
 
-    public long getSavedTime() {
-        return getBestMetrics().getTfmetrics().getSavedTime();
-    }
+  public Stream<Occurrence> occurrences() {
+    return this.occurrences.stream();
+  }
 
-    public BigDecimal getSavedTimePerTimeInCache() {
-        return getBestMetrics().getTfmetrics().getSavedTimePerTimeInCache();
-    }
+  public Metrics getMetrics() {
+    if (this.metrics == null) throw new RuntimeException("Metrics must be calculated");
+    return this.metrics;
+  }
 
-    protected void calculateMetrics() {
-        if (this.bestMetrics != null) {
-            LOGGER.log(Level.WARNING, "Metrics already calculated");
-        }
-        if (this.occurrences.size() < 2) {
-            throw new RuntimeException("Not reusable input");
-        }
+  protected void calculateMetrics() {
+    if (this.metrics != null) LOGGER.warning("Metrics already calculated");
+    if (this.occurrences.size() < 2) throw new RuntimeException("Not reusable input");
 
-        this.bestMetrics = new Metrics();
+    this.metrics = new Metrics();
 
-        this.occurrences.sort((occurrence1, occurrence2) -> Long.compare(occurrence1.getStartTime(), occurrence2.getStartTime()));
-        Simulator.simulate(this.occurrences, this.bestMetrics.getTfmetrics());
+    this.occurrences.sort(Comparator.comparingLong(Occurrence::getStartTime));
+    Simulator.simulate(this.occurrences, getMetrics().getPareto());
 
-        for (int i = 0; i < this.occurrences.size(); i++) {
-            Occurrence occurrence = this.occurrences.get(i);
-            Object returnValue = occurrence.getReturnValue();
-            for (int j = i + 1; j < this.occurrences.size(); j++) {
-                Occurrence other = this.occurrences.get(j);
-                if (EqualsBuilder.reflectionEquals(returnValue, other.getReturnValue())) {
-                    this.bestMetrics.addSameOccurrence(occurrence);
-                    continue;
-                }
-                this.bestMetrics.addDifferentReturnOccurrence();
-            }
+    for (int i = 0; i < this.occurrences.size(); i++) {
+      Occurrence occurrence = this.occurrences.get(i);
+      Object returnValue = occurrence.getReturnValue();
+      for (int j = i + 1; j < this.occurrences.size(); j++) {
+        Occurrence other = this.occurrences.get(j);
+        if (EqualsBuilder.reflectionEquals(returnValue, other.getReturnValue())) {
+          getMetrics().registerReuse(occurrence);
+        } else {
+          getMetrics().registerChange();
         }
+      }
     }
-
-    protected void calculateThresholds() {
-        Thresholds.executionTimes.add(this.bestMetrics.getSameOccurrencesTotalExecutionTime());
-        Thresholds.hitRatios.add(this.bestMetrics.getHitRatio());
-        Thresholds.missRatios.add(this.bestMetrics.getMissRatio());
-        Thresholds.shareabilities.add(this.bestMetrics.getShareability());
-        Thresholds.savedTimePerTimeInCache.add(this.bestMetrics.getTfmetrics().getSavedTimePerTimeInCache());
-    }
+  }
+
+  protected void calculateThresholds() {
+    Thresholds.EXECUTION_TIMES.add(getMetrics().getReusableExecutionTime());
+    Thresholds.HIT_RATIOS.add(getMetrics().getHitRatio());
+    Thresholds.MISS_RATIOS.add(getMetrics().getMissRatio());
+    Thresholds.SHAREABILITIES.add(getMetrics().getShareability());
+    Thresholds.DISTANCES.add(getMetrics().getMinEuclideanDistance());
+  }
 
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/Method.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/Method.java
index cf32a1f..abd39a5 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/Method.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metadata/Method.java
@@ -7,22 +7,21 @@ package br.ufrgs.inf.prosoft.aplcachetf.extension.metadata;
 
 import br.ufrgs.inf.prosoft.aplcachetf.extension.metrics.CacheabilityPatternDecider;
 import br.ufrgs.inf.prosoft.tfcache.Metrics;
+import br.ufrgs.inf.prosoft.tfcache.Pareto;
 import br.ufrgs.inf.prosoft.tfcache.StorageManager;
 import br.ufrgs.inf.prosoft.tfcache.configuration.Configuration;
 import br.ufrgs.inf.prosoft.tfcache.metadata.Occurrence;
-import java.math.BigDecimal;
+
+import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
- *
  * @author root
  */
 public class Method {
@@ -30,18 +29,14 @@ public class Method {
     private static final Logger LOGGER = Logger.getLogger(Method.class.getName());
 
     private final String name;
-    private List<Occurrence> occurrences;
+    private final List<Occurrence> occurrences;
     private List<GroupOfOccurrences> groupsOfOccurrences;
-    private Metrics bestMetrics;
+    private Metrics bestTFMetrics;
 
     public Method(String name, List<Occurrence> occurrences) {
         this.name = name;
-        if (occurrences == null) {
-            throw new RuntimeException("Occurrences is null");
-        }
-        if (occurrences.isEmpty()) {
-            throw new RuntimeException("Occurrences is empty");
-        }
+        if (occurrences == null) throw new RuntimeException("Occurrences is null");
+        if (occurrences.isEmpty()) throw new RuntimeException("Occurrences is empty");
         this.occurrences = occurrences;
     }
 
@@ -49,23 +44,14 @@ public class Method {
         return this.name;
     }
 
-    public Metrics getBestMetrics() {
-        return this.bestMetrics;
+    public Metrics getBestTFMetrics() {
+        if (this.bestTFMetrics == null) throw new RuntimeException("trying to access metrics before calculating it");
+        return this.bestTFMetrics;
     }
 
-    public long getEstimatedSavedTime() {
-        if (getBestMetrics() != null) {
-            return getBestMetrics().getSavedTime();
-        }
-        return groupsOfOccurrences().map(group -> group.getSavedTime()).reduce(Long::sum).orElse(0L);
-    }
-    
-    public BigDecimal getEstimatedSavedTimePerTimeInCache() {
-        if (getBestMetrics() != null) {
-            return getBestMetrics().getSavedTimePerTimeInCache();
-        }
-        GroupOfOccurrences max = groupsOfOccurrences().max(Comparator.comparing(GroupOfOccurrences::getSavedTimePerTimeInCache)).get();
-        return max.getSavedTimePerTimeInCache();
+    public double getEstimatedSavedTime() {
+        if (getBestTFMetrics() != null) return getBestTFMetrics().getSavedTime();
+        return groupsOfOccurrences().map(it -> it.getMetrics().getSavedTime()).reduce(Double::sum).orElse(0D);
     }
 
     public Stream<Occurrence> occurrences() {
@@ -73,24 +59,16 @@ public class Method {
     }
 
     public Stream<GroupOfOccurrences> groupsOfOccurrences() {
-        if (this.groupsOfOccurrences == null) {
-            groupByInput();
-        }
+        if (this.groupsOfOccurrences == null) groupByInput();
         return this.groupsOfOccurrences.stream();
     }
 
-    public int getOccurrencesSize() {
-        return this.occurrences.size();
-    }
-
     private void groupByInput() {
         Map<String, List<Occurrence>> inputHasOccurrences = new ConcurrentHashMap<>();
         occurrences().forEach(occurrence -> {
             String parameters = occurrence.getParametersSerialised();
             inputHasOccurrences.compute(parameters, (key, oldValue) -> {
-                if (oldValue == null) {
-                    oldValue = new ArrayList<>();
-                }
+                if (oldValue == null) oldValue = new ArrayList<>();
                 oldValue.add(occurrence);
                 return oldValue;
             });
@@ -101,46 +79,34 @@ public class Method {
     }
 
     public void removeSingleOccurrences() {
-        if (this.groupsOfOccurrences == null) {
-            groupByInput();
-        }
-        int initialCountofOccurrences = this.groupsOfOccurrences.size();
-        this.groupsOfOccurrences.removeIf(groupOfOccurrences -> groupOfOccurrences.getOccurrencesSize() < 2);
-        int removedOccurrences = initialCountofOccurrences - this.groupsOfOccurrences.size();
-        if (removedOccurrences > 0) {
-            LOGGER.log(Level.INFO, "\tRemoved {0} of {1} inputs from method {2}", new Object[]{removedOccurrences, initialCountofOccurrences, this.name});
-        }
+        if (this.groupsOfOccurrences == null) groupByInput();
+        int initialCountOfOccurrences = this.groupsOfOccurrences.size();
+        this.groupsOfOccurrences.removeIf(groupOfOccurrences -> groupOfOccurrences.occurrences().count() < 2);
+        int removedOccurrences = initialCountOfOccurrences - this.groupsOfOccurrences.size();
+        if (removedOccurrences > 0) LOGGER.info(MessageFormat.format("\tRemoved {0} of {1} inputs from method {2}", removedOccurrences, initialCountOfOccurrences, this.name));
     }
 
     public void calculateMetrics() {
-        if (this.groupsOfOccurrences == null) {
-            groupByInput();
-        }
+        if (this.groupsOfOccurrences == null) groupByInput();
         groupsOfOccurrences().forEach(GroupOfOccurrences::calculateMetrics);
         String uuid = Configuration.getUUID().replace("level:input", "level:method");
-        Metrics metrics = StorageManager.get(uuid, this.occurrences);
-        if (this.bestMetrics == null && metrics != null) {
-            this.bestMetrics = metrics;
-        }
+        Pareto pareto = StorageManager.get(uuid, this.occurrences);
+        if (pareto != null) this.bestTFMetrics = pareto.getBestMetrics();
     }
 
     public void calculateThresholds() {
-        this.groupsOfOccurrences.stream().forEach(GroupOfOccurrences::calculateThresholds);
+        this.groupsOfOccurrences.forEach(GroupOfOccurrences::calculateThresholds);
     }
 
     public void filterCacheableInputs() {
         int initialInputsSize = this.groupsOfOccurrences.size();
         this.groupsOfOccurrences.removeIf(CacheabilityPatternDecider::isNotCacheable);
         int removedInputs = initialInputsSize - this.groupsOfOccurrences.size();
-        if (removedInputs > 0) {
-            LOGGER.log(Level.INFO, "\tRemoved {0} of {1} uncacheable inputs from method {2}", new Object[]{removedInputs, initialInputsSize, this.name});
-        }
+        if (removedInputs > 0) LOGGER.info(MessageFormat.format("\tRemoved {0} of {1} unreachable inputs from method {2}", removedInputs, initialInputsSize, this.name));
         initialInputsSize = this.groupsOfOccurrences.size();
-        this.groupsOfOccurrences.removeIf(groupOfOccurrence -> groupOfOccurrence.getTtl() == 0);
+        this.groupsOfOccurrences.removeIf(groupOfOccurrence -> groupOfOccurrence.getMetrics().getTtl() == 0);
         removedInputs = initialInputsSize - this.groupsOfOccurrences.size();
-        if (removedInputs > 0) {
-            LOGGER.log(Level.INFO, "\tRemoved {0} of {1} inputs with 0 TTL from method {2}", new Object[]{removedInputs, initialInputsSize, this.name});
-        }
+        if (removedInputs > 0) LOGGER.info(MessageFormat.format("\tRemoved {0} of {1} inputs with 0 TTL from method {2}", removedInputs, initialInputsSize, this.name));
     }
 
     @Override
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityMetrics.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityMetrics.java
index cdd857c..9e74b48 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityMetrics.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityMetrics.java
@@ -7,37 +7,33 @@ public class CacheabilityMetrics {
     public static int K_STANDARD_DEVIATION = 0;
 
     public static boolean isStaticData(GroupOfOccurrences groupOfOccurrences) {
-        if (groupOfOccurrences.getBestMetrics().getTfmetrics().getSavedTimePerTimeInCache().compareTo(Thresholds.savedTimePerTimeInCacheThreshold(K_STANDARD_DEVIATION)) < 0) {
-            return false;
-        }
-        return groupOfOccurrences.getBestMetrics().getHitRatio() == 100.0;
+        if (groupOfOccurrences.getMetrics().getMinEuclideanDistance() > Thresholds.distanceThreshold(K_STANDARD_DEVIATION)) return false;
+        return groupOfOccurrences.getMetrics().getHitRatio() == 100.0;
     }
 
     public static boolean isNotStaticData(GroupOfOccurrences groupOfOccurrences) {
         return !isStaticData(groupOfOccurrences);
     }
 
-    public static boolean changeMoreThanUsed(GroupOfOccurrences groupOfOccurrences) {
-        return groupOfOccurrences.getBestMetrics().getMissRatio() > Thresholds.missThreshold(K_STANDARD_DEVIATION);
+    public static boolean isChangeable(GroupOfOccurrences groupOfOccurrences) {
+        return groupOfOccurrences.getMetrics().getMissRatio() > Thresholds.missThreshold(K_STANDARD_DEVIATION);
     }
 
-    public static boolean hasHighUsagePerCaching(GroupOfOccurrences groupOfOccurrences) {
-        return groupOfOccurrences.getBestMetrics().getTfmetrics().getSavedTimePerTimeInCache().compareTo(Thresholds.savedTimePerTimeInCacheThreshold(K_STANDARD_DEVIATION)) >= 0;
+    public static boolean hasHighSavedTimeAndLowIdleTime(GroupOfOccurrences groupOfOccurrences) {
+        return groupOfOccurrences.getMetrics().getMinEuclideanDistance() <= Thresholds.distanceThreshold(K_STANDARD_DEVIATION);
     }
 
-    public static boolean hasLowUsagePerCaching(GroupOfOccurrences groupOfOccurrences) {
-        return !hasHighUsagePerCaching(groupOfOccurrences);
+    public static boolean hasLowSavedTimeAndHighIdleTime(GroupOfOccurrences groupOfOccurrences) {
+        return !hasHighSavedTimeAndLowIdleTime(groupOfOccurrences);
     }
 
     public static boolean isUserSpecific(GroupOfOccurrences groupOfOccurrences) {
-        if (groupOfOccurrences.getBestMetrics().getAmountOfIdentifiedSameOccurences() == 0) {
-            return false;
-        }
-        return groupOfOccurrences.getBestMetrics().getShareability() < Thresholds.shareabilityThreshold(K_STANDARD_DEVIATION);
+        if (groupOfOccurrences.getMetrics().getShareableReuses() == 0) return false;
+        return groupOfOccurrences.getMetrics().getShareability() < Thresholds.shareabilityThreshold(K_STANDARD_DEVIATION);
     }
 
     public static boolean isExpensive(GroupOfOccurrences groupOfOccurrences) {
-        return groupOfOccurrences.getBestMetrics().getSameOccurrencesAverageExecutionTime() >= Thresholds.expensivenessThreshold(K_STANDARD_DEVIATION);
+        return groupOfOccurrences.getMetrics().getAverageReusableExecutionTime() >= Thresholds.expensivenessThreshold(K_STANDARD_DEVIATION);
     }
 
     public static boolean isCheap(GroupOfOccurrences groupOfOccurrences) {
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityPatternDecider.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityPatternDecider.java
index 72d97f8..babf47b 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityPatternDecider.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/CacheabilityPatternDecider.java
@@ -4,34 +4,16 @@ import br.ufrgs.inf.prosoft.aplcachetf.extension.metadata.GroupOfOccurrences;
 
 public class CacheabilityPatternDecider {
 
-    /**
-     * Flowchart definition
-     *
-     * @param groupOfOccurrences
-     * @return
-     */
-    public static boolean isCacheable(GroupOfOccurrences groupOfOccurrences) {
-        boolean isStaticData = CacheabilityMetrics.isStaticData(groupOfOccurrences);
-        if (isStaticData) {
-            return true;
-        }
-        boolean changeMoreThanUsed = CacheabilityMetrics.changeMoreThanUsed(groupOfOccurrences);
-        if (changeMoreThanUsed) {
-            return false;
-        }
-        boolean hasHighUsagePerCaching = CacheabilityMetrics.hasHighUsagePerCaching(groupOfOccurrences);
-        if (!hasHighUsagePerCaching) {
-            return false;
-        }
-        boolean isUserSpecific = CacheabilityMetrics.isUserSpecific(groupOfOccurrences);
-        if (isUserSpecific) {
-            return true;
-        }
-        return CacheabilityMetrics.isExpensive(groupOfOccurrences);
-    }
+  public static boolean isCacheable(GroupOfOccurrences groupOfOccurrences) {
+    if (CacheabilityMetrics.isStaticData(groupOfOccurrences)) return true;
+    if (CacheabilityMetrics.isChangeable(groupOfOccurrences)) return false;
+    if (CacheabilityMetrics.hasLowSavedTimeAndHighIdleTime(groupOfOccurrences)) return false;
+    if (CacheabilityMetrics.isUserSpecific(groupOfOccurrences)) return true;
+    return CacheabilityMetrics.isExpensive(groupOfOccurrences);
+  }
 
-    public static boolean isNotCacheable(GroupOfOccurrences groupOfOccurrences) {
-        return !isCacheable(groupOfOccurrences);
-    }
+  public static boolean isNotCacheable(GroupOfOccurrences groupOfOccurrences) {
+    return !isCacheable(groupOfOccurrences);
+  }
 
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Metrics.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Metrics.java
index 1e17c21..fd25e16 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Metrics.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Metrics.java
@@ -1,133 +1,123 @@
-/*
- * 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.aplcachetf.extension.metrics;
 
+import br.ufrgs.inf.prosoft.tfcache.Pareto;
 import br.ufrgs.inf.prosoft.tfcache.metadata.Occurrence;
+
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.HashSet;
 import java.util.Set;
 
-/**
- *
- * @author root
- */
 public class Metrics {
-//exactly same method calls
-
-    private final br.ufrgs.inf.prosoft.tfcache.Metrics tfmetrics;
-    private long sameOccurrences;
-
-    //number of same method calls with different return
-    private long differentReturnOccurrences;
-    private long sameOccurrencesExecutionTime;
-
-    private long amountOfIdentifiedSameOccurences;
-    private final Set<String> uniqueUsers;
-
-    public Metrics() {
-        sameOccurrences = 0L;
-        differentReturnOccurrences = 0L;
-        sameOccurrencesExecutionTime = 0L;
-        amountOfIdentifiedSameOccurences = 0L;
-        uniqueUsers = new HashSet<>();
-        this.tfmetrics = new br.ufrgs.inf.prosoft.tfcache.Metrics();
-    }
-
-    public br.ufrgs.inf.prosoft.tfcache.Metrics getTfmetrics() {
-        return tfmetrics;
-    }
-
-    public void addSameOccurrence(Occurrence occurrence) {
-        sameOccurrences++;
-        addSameOccurrencesTotalExecutionTime(occurrence.getExecutionTime());
-
-        if (occurrence.getUserId() != null && !occurrence.getUserId().equals("Anonymous")) {
-            uniqueUsers.add(occurrence.getUserId());
-            addIdentifiedSameOccurence();
-        }
-    }
-
-    public void addDifferentReturnOccurrence() {
-        differentReturnOccurrences++;
-    }
-
-    private void addSameOccurrencesTotalExecutionTime(Long executionTime) {
-        sameOccurrencesExecutionTime += executionTime;
-    }
-
-    private void addIdentifiedSameOccurence() {
-        amountOfIdentifiedSameOccurences++;
-    }
-
-    public long getSameOccurrencesTotalExecutionTime() {
-        return sameOccurrencesExecutionTime;
-    }
-
-    public double getSameOccurrencesAverageExecutionTime() {
-        if (sameOccurrences == 0) {
-            return 0;
-        }
-        return new BigDecimal(getSameOccurrencesTotalExecutionTime())
-                .divide(new BigDecimal(sameOccurrences), 5, RoundingMode.HALF_UP)
-                .doubleValue();
-    }
-
-    public Long getNumberOfOccurrences() {
-        return sameOccurrences + differentReturnOccurrences;
-    }
-
-    public Long getNumberOfSameOccurrences() {
-        return sameOccurrences;
-    }
-
-    public Long getNumberOfDifferentReturnOccurrences() {
-        return differentReturnOccurrences;
-    }
-
-    //from 0% to 100%
-    public double getHitRatio() {
-        BigDecimal bd = new BigDecimal(getNumberOfSameOccurrences() * 100);
-        return bd.divide(new BigDecimal(getNumberOfOccurrences()), 5, RoundingMode.HALF_UP).doubleValue();
-    }
-
-    //from 0% to 100%
-    public double getMissRatio() {
-        BigDecimal bd = new BigDecimal(getNumberOfDifferentReturnOccurrences() * 100);
-        return bd.divide(new BigDecimal(getNumberOfOccurrences()), 5, RoundingMode.HALF_UP).doubleValue();
-    }
-
-    public double getShareability() {
-        Long amountOfIdentifiedSameOccurences = getAmountOfIdentifiedSameOccurences();
-        if (amountOfIdentifiedSameOccurences == 0) {
-            return 100;
-        }
-        BigDecimal bd = new BigDecimal(getAmountOfUniqueIdentifiedSameOccurences() * 100);
-        return bd.divide(new BigDecimal(amountOfIdentifiedSameOccurences), 5, RoundingMode.HALF_UP).doubleValue();
-    }
-
-    public Long getAmountOfIdentifiedSameOccurences() {
-        return amountOfIdentifiedSameOccurences;
-    }
 
-    public int getAmountOfUniqueIdentifiedSameOccurences() {
-        return uniqueUsers.size();
-    }
-
-    public Long getAmountOfAnonymousSameOccurences() {
-        return sameOccurrences - amountOfIdentifiedSameOccurences;
-    }
-
-    @Override
-    public String toString() {
-        return "{"
-                + "\"hitRatio\":" + getHitRatio() + ","
-                + "\"missRatio\":" + getMissRatio() + ","
-                + "\"shareability\":" + getShareability()
-                + "}";
-    }
+  private final Set<String> users;
+  private final Pareto pareto;
+  private long changeable;
+  private long reuses;
+  private long shareableReuses;
+  private long reusableExecutionTime;
+  private Double minEuclideanDistance;
+
+  public Metrics() {
+    users = new HashSet<>();
+    changeable = 0L;
+    reuses = 0L;
+    shareableReuses = 0L;
+    reusableExecutionTime = 0L;
+    pareto = new Pareto();
+  }
+
+  public void registerReuse(Occurrence occurrence) {
+    reuses++;
+    reusableExecutionTime += occurrence.getExecutionTime();
+    if (occurrence.getUserId() != null && !occurrence.getUserId().equals("Anonymous")) {
+      users.add(occurrence.getUserId());
+      shareableReuses++;
+    }
+  }
+
+  public void registerChange() {
+    changeable++;
+  }
+
+  public Pareto getPareto() {
+    return pareto;
+  }
+
+  public long getTtl() {
+    return getPareto().getBestMetrics().getTtl();
+  }
+
+  public double getSavedTime() {
+    return getPareto().getBestMetrics().getSavedTime();
+  }
+
+  public double getMinEuclideanDistance() {
+    if (minEuclideanDistance == null) minEuclideanDistance = getPareto().getNormalised().getMinEuclideanDistance();
+    return minEuclideanDistance;
+  }
+
+  public long getReusableExecutionTime() {
+    return reusableExecutionTime;
+  }
+
+  public double getAverageReusableExecutionTime() {
+    if (reuses == 0) return 0;
+    return new BigDecimal(getReusableExecutionTime())
+      .divide(new BigDecimal(reuses), 5, RoundingMode.HALF_UP)
+      .doubleValue();
+  }
+
+  public long getComparisons() {
+    return reuses + changeable;
+  }
+
+  public long getReuses() {
+    return reuses;
+  }
+
+  public long getChanges() {
+    return changeable;
+  }
+
+  public double getHitRatio() {
+    BigDecimal bd = new BigDecimal(getReuses() * 100);
+    return bd.divide(new BigDecimal(getComparisons()), 5, RoundingMode.HALF_UP).doubleValue();
+  }
+
+  public double getMissRatio() {
+    BigDecimal bd = new BigDecimal(getChanges() * 100);
+    return bd.divide(new BigDecimal(getComparisons()), 5, RoundingMode.HALF_UP).doubleValue();
+  }
+
+  public double getShareability() {
+    long shareableReuses = getShareableReuses();
+    if (shareableReuses == 0) {
+      return 100;
+    }
+    BigDecimal bd = new BigDecimal(getUsers() * 100);
+    return bd.divide(new BigDecimal(shareableReuses), 5, RoundingMode.HALF_UP).doubleValue();
+  }
+
+  public long getShareableReuses() {
+    return shareableReuses;
+  }
+
+  public int getUsers() {
+    return users.size();
+  }
+
+  public long getAnonymousReuses() {
+    return reuses - shareableReuses;
+  }
+
+  @Override
+  public String toString() {
+    return "{"
+      + "\"hitRatio\":" + getHitRatio() + ","
+      + "\"missRatio\":" + getMissRatio() + ","
+      + "\"shareability\":" + getShareability()
+      + "}";
+  }
 
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Thresholds.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Thresholds.java
index 03eeca8..d5e7e6f 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Thresholds.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/extension/metrics/Thresholds.java
@@ -1,209 +1,150 @@
-/*
- * 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.aplcachetf.extension.metrics;
 
 import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
 import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.List;
 
-/**
- *
- * @author romulo
- */
 public class Thresholds {
 
-    public static BigDecimal averageSavedTimePerTimeInCache;
-
-    public static Double stdDevHitRatio;
-    public static Double stdDevMissRatio;
-    public static Double stdDevExecutionTimeRatio;
-    public static BigDecimal stdDevSavedTimePerTimeInCache;
-    public static Double stdDevShareability;
-
-    public static long population;
-
-    public static final List<Double> hitRatios = new ArrayList<>();
-    public static final List<Double> missRatios = new ArrayList<>();
-    public static final List<Long> executionTimes = new ArrayList<>();
-    public static final List<Double> shareabilities = new ArrayList<>();
-    public static final List<BigDecimal> savedTimePerTimeInCache = new ArrayList<>();
-
-    public static void reset() {
-        Thresholds.averageSavedTimePerTimeInCache = null;
-
-        Thresholds.stdDevHitRatio = null;
-        Thresholds.stdDevMissRatio = null;
-        Thresholds.stdDevExecutionTimeRatio = null;
-        Thresholds.stdDevSavedTimePerTimeInCache = null;
-        Thresholds.stdDevShareability = null;
-
-        Thresholds.population = 0;
-
-        Thresholds.hitRatios.clear();
-        Thresholds.missRatios.clear();
-        Thresholds.executionTimes.clear();
-        Thresholds.shareabilities.clear();
-        Thresholds.savedTimePerTimeInCache.clear();
-    }
-
-    /**
-     * General mean hit ratio of all calls
-     *
-     * @return
-     */
-    public static double getAverageHitRatio() {
-        if (population == 0) {
-            return 0;
-        }
-        return new BigDecimal(hitRatios.stream().reduce(Double::sum).orElse(0D)).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
-    }
-
-    public static double getAverageMissRatio() {
-        if (population == 0) {
-            return 0;
-        }
-        return new BigDecimal(missRatios.stream().reduce(Double::sum).orElse(0D)).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
-    }
-
-    public static double getAverageExecutionTime() {
-        if (population == 0) {
-            return 0;
-        }
-        return new BigDecimal(executionTimes.stream().reduce(Long::sum).orElse(0L)).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
-    }
-
-    public static double getAverageShareability() {
-        if (population == 0) {
-            return 0;
-        }
-        return new BigDecimal(shareabilities.stream().reduce(Double::sum).orElse(0D)).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
-    }
-
-    public static double getStdDevHitRatio() {
-        if (population == 0) {
-            return 0;
-        }
-        if (stdDevHitRatio != null) {
-            return stdDevHitRatio;
-        }
-
-        double mean = getAverageHitRatio();
-        double temp = hitRatios.stream()
-                .map(hitRate -> (hitRate - mean) * (hitRate - mean))
-                .reduce(Double::sum)
-                .orElse(0D);
-        stdDevHitRatio = Math.sqrt(temp / population);
-        return stdDevHitRatio;
-    }
-
-    public static double getStdDevMissRatio() {
-        if (population == 0) {
-            return 0;
-        }
-        if (stdDevMissRatio != null) {
-            return stdDevMissRatio;
-        }
-
-        double mean = getAverageMissRatio();
-        double temp = missRatios.stream().map(missRatio -> (missRatio - mean) * (missRatio - mean))
-                .reduce(Double::sum)
-                .orElse(0D);
-        stdDevMissRatio = Math.sqrt(temp / population);
-        return stdDevMissRatio;
-    }
-
-    public static double getStdDevExecutionTimeRatio() {
-        if (population == 0) {
-            return 0;
-        }
-        if (stdDevExecutionTimeRatio != null) {
-            return stdDevExecutionTimeRatio;
-        }
-
-        double mean = getAverageExecutionTime();
-        double temp = executionTimes.stream()
-                .map(executionTime -> (executionTime - mean) * (executionTime - mean))
-                .reduce(Double::sum)
-                .orElse(0D);
-        stdDevExecutionTimeRatio = Math.sqrt(temp / population);
-        return stdDevExecutionTimeRatio;
-    }
-
-    public static BigDecimal getStdDevSavedTimePerTimeInCache() {
-        if (population == 0) {
-            return new BigDecimal(BigInteger.ZERO);
-        }
-        if (stdDevSavedTimePerTimeInCache != null) {
-            return stdDevSavedTimePerTimeInCache;
-        }
-
-        BigDecimal mean = getAverageSavedTimePerTimeInCache();
-        BigDecimal temp = savedTimePerTimeInCache.stream()
-                .map(frequency -> frequency.subtract(mean).multiply(frequency.subtract(mean)))
-                .reduce(BigDecimal::add)
-                .orElse(new BigDecimal(BigInteger.ZERO));
-        stdDevSavedTimePerTimeInCache = temp.divide(new BigDecimal(population), MathContext.DECIMAL128).sqrt(MathContext.DECIMAL128);
-        return stdDevSavedTimePerTimeInCache;
-    }
-
-    public static double getStdDevShareability() {
-        if (population == 0) {
-            return 0;
-        }
-        if (stdDevShareability != null) {
-            return stdDevShareability;
-        }
-
-        double mean = getAverageShareability();
-        double temp = shareabilities.stream()
-                .map(shareability -> (shareability - mean) * (shareability - mean))
-                .reduce(Double::sum)
-                .orElse(0D);
-        stdDevShareability = Math.sqrt(temp / population);
-        return stdDevShareability;
-    }
-
-    public static BigDecimal getAverageSavedTimePerTimeInCache() {
-        if (savedTimePerTimeInCache.isEmpty()) {
-            return new BigDecimal(BigInteger.ZERO);
-        }
-        if (averageSavedTimePerTimeInCache != null) {
-            return averageSavedTimePerTimeInCache;
-        }
-
-        averageSavedTimePerTimeInCache = savedTimePerTimeInCache.stream().reduce(BigDecimal::add).orElse(new BigDecimal(BigInteger.ZERO))
-                .divide(new BigDecimal(savedTimePerTimeInCache.size()), MathContext.DECIMAL128);
-        return averageSavedTimePerTimeInCache;
-    }
-
-//getting X% with most hits
-    public static double hitThreshold(int kStdDev) {
-        return getAverageHitRatio() + (kStdDev * getStdDevHitRatio());
-    }
-
-//getting X% with most misses
-    public static double missThreshold(int kStdDev) {
-        return getAverageMissRatio() + (kStdDev * getStdDevMissRatio());
-    }
-
-//getting X% most expensive methods
-    public static double expensivenessThreshold(int kStdDev) {
-        return getAverageExecutionTime() + (kStdDev * getStdDevExecutionTimeRatio());
-    }
-
-    public static double shareabilityThreshold(int kStdDev) {
-        return getAverageShareability() + (kStdDev * getStdDevShareability());
-    }
-
-//getting X% most frenquent
-    public static BigDecimal savedTimePerTimeInCacheThreshold(int kStdDev) {
-        return getAverageSavedTimePerTimeInCache().add(getStdDevSavedTimePerTimeInCache().multiply(new BigDecimal(kStdDev)));
-    }
+  public static final List<Double> DISTANCES = new ArrayList<>();
+  public static final List<Double> HIT_RATIOS = new ArrayList<>();
+  public static final List<Double> MISS_RATIOS = new ArrayList<>();
+  public static final List<Long> EXECUTION_TIMES = new ArrayList<>();
+  public static final List<Double> SHAREABILITIES = new ArrayList<>();
+  public static long population;
+  private static Double stdDevDistance;
+  private static Double stdDevHitRatio;
+  private static Double stdDevMissRatio;
+  private static Double stdDevExecutionTime;
+  private static Double stdDevShareability;
+
+
+  public static void reset() {
+    Thresholds.population = 0;
+
+    Thresholds.DISTANCES.clear();
+    Thresholds.stdDevDistance = null;
+
+    Thresholds.HIT_RATIOS.clear();
+    Thresholds.stdDevHitRatio = null;
+
+    Thresholds.MISS_RATIOS.clear();
+    Thresholds.stdDevMissRatio = null;
+
+    Thresholds.EXECUTION_TIMES.clear();
+    Thresholds.stdDevExecutionTime = null;
+
+    Thresholds.SHAREABILITIES.clear();
+    Thresholds.stdDevShareability = null;
+  }
+
+  public static double getAverageDistance() {
+    if (DISTANCES.isEmpty()) return 0D;
+    return DISTANCES.stream().reduce(Double::sum).orElse(0D) / DISTANCES.size();
+  }
+
+  public static double getStdDevDistance() {
+    if (population == 0) return 0;
+    if (stdDevDistance != null) return stdDevDistance;
+    double mean = getAverageDistance();
+    double temp = DISTANCES.stream()
+      .map(difference -> (difference - mean) * (difference - mean))
+      .reduce(Double::sum)
+      .orElse(0D);
+    stdDevDistance = Math.sqrt(temp / population);
+    return stdDevDistance;
+  }
+
+  public static double distanceThreshold(int kStdDev) {
+    return getAverageDistance() - (kStdDev * getStdDevDistance());
+  }
+
+
+  public static double getAverageHitRatio() {
+    if (population == 0) return 0;
+    return HIT_RATIOS.stream().reduce(Double::sum).orElse(0D) / population;
+  }
+
+  public static double getStdDevHitRatio() {
+    if (population == 0) return 0;
+    if (stdDevHitRatio != null) return stdDevHitRatio;
+    double mean = getAverageHitRatio();
+    double temp = HIT_RATIOS.stream()
+      .map(hitRate -> (hitRate - mean) * (hitRate - mean))
+      .reduce(Double::sum)
+      .orElse(0D);
+    stdDevHitRatio = Math.sqrt(temp / population);
+    return stdDevHitRatio;
+  }
+
+  public static double hitThreshold(int kStdDev) {
+    return getAverageHitRatio() + (kStdDev * getStdDevHitRatio());
+  }
+
+
+  public static double getAverageMissRatio() {
+    if (population == 0) return 0;
+    return BigDecimal.valueOf(MISS_RATIOS.stream().reduce(Double::sum).orElse(0D)).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
+  }
+
+  public static double getStdDevMissRatio() {
+    if (population == 0) return 0;
+    if (stdDevMissRatio != null) return stdDevMissRatio;
+    double mean = getAverageMissRatio();
+    double temp = MISS_RATIOS.stream().map(missRatio -> (missRatio - mean) * (missRatio - mean))
+      .reduce(Double::sum)
+      .orElse(0D);
+    stdDevMissRatio = Math.sqrt(temp / population);
+    return stdDevMissRatio;
+  }
+
+  public static double missThreshold(int kStdDev) {
+    return getAverageMissRatio() + (kStdDev * getStdDevMissRatio());
+  }
+
+
+  public static double getAverageExecutionTime() {
+    if (population == 0) return 0;
+    return new BigDecimal(EXECUTION_TIMES.stream().reduce(Long::sum).orElse(0L)).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
+  }
+
+  public static double getStdDevExecutionTime() {
+    if (population == 0) return 0;
+    if (stdDevExecutionTime != null) return stdDevExecutionTime;
+    double mean = getAverageExecutionTime();
+    double temp = EXECUTION_TIMES.stream()
+      .map(executionTime -> (executionTime - mean) * (executionTime - mean))
+      .reduce(Double::sum)
+      .orElse(0D);
+    stdDevExecutionTime = Math.sqrt(temp / population);
+    return stdDevExecutionTime;
+  }
+
+  public static double expensivenessThreshold(int kStdDev) {
+    return getAverageExecutionTime() + (kStdDev * getStdDevExecutionTime());
+  }
+
+
+  public static double getAverageShareability() {
+    if (population == 0) return 0;
+    return BigDecimal.valueOf(SHAREABILITIES.stream().reduce(Double::sum).orElse(0D)).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
+  }
+
+  public static double getStdDevShareability() {
+    if (population == 0) return 0;
+    if (stdDevShareability != null) return stdDevShareability;
+    double mean = getAverageShareability();
+    double temp = SHAREABILITIES.stream()
+      .map(shareability -> (shareability - mean) * (shareability - mean))
+      .reduce(Double::sum)
+      .orElse(0D);
+    stdDevShareability = Math.sqrt(temp / population);
+    return stdDevShareability;
+  }
+
+  public static double shareabilityThreshold(int kStdDev) {
+    return getAverageShareability() + (kStdDev * getStdDevShareability());
+  }
 
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/Main.java b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/Main.java
index 6ec6242..d8beda9 100755
--- a/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/aplcachetf/Main.java
@@ -13,13 +13,14 @@ import br.ufrgs.inf.prosoft.tfcache.configuration.Arguments;
 import br.ufrgs.inf.prosoft.tfcache.configuration.Configuration;
 import br.ufrgs.inf.prosoft.trace.Trace;
 import br.ufrgs.inf.prosoft.trace.reader.Mode;
+
+import java.text.MessageFormat;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- *
  * @author romulo
  */
 public class Main {
@@ -30,7 +31,16 @@ public class Main {
         System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT+%1$tL] [%4$-7s] [APLCacheTF] %5$s %n");
 
         if (args.length < 2) {
-            System.err.println("--trace=<TracePath> --output=<OutputPath> [--tfstore=<storePath>] [--tfkernel=<exhaustive|optimised>] [--tfstaleness=<ignore|shrink>] [--mode=<complete|hashed|partial>] [--k=<kStandardDeviation>] [--window=<windowSize>] [--shift=<shiftTime>]");
+            System.err.println("--trace=<TracePath>" +
+                    " --output=<OutputPath>" +
+                    " [--tfstore=<storePath>]" +
+                    " [--tfkernel=<exhaustive|optimised>]" +
+                    " [--tfstaleness=<ignore|shrink>]" +
+                    " [--mode=<complete|hashed|partial>]" +
+                    " [--k=<kStandardDeviation>]" +
+                    " [--objective=(savedTime)0..1,0..1(idleTime)]" +
+                    " [--window=<windowSize>]" +
+                    " [--shift=<shiftTime>]");
             System.exit(1);
         }
 
@@ -49,15 +59,15 @@ public class Main {
         String mode = arguments.get("mode");
         if (mode == null) {
             mode = "complete";
-            LOGGER.log(Level.INFO, "Using default mode: {0}", mode);
+            LOGGER.info(MessageFormat.format("Using default mode: {0}", mode));
         }
         int k = 0;
         String kStr = arguments.get("k");
         if (kStr == null) {
-            LOGGER.log(Level.INFO, "Using default k: {0}", k);
+            LOGGER.info(MessageFormat.format("Using default k: {0}", k));
         } else {
             try {
-                k = Integer.valueOf(kStr);
+                k = Integer.parseInt(kStr);
             } catch (NumberFormatException ex) {
                 System.err.println("<k> must be a number");
                 System.exit(1);
@@ -67,24 +77,26 @@ public class Main {
         Long window = null;
         try {
             window = Long.valueOf(arguments.get("window"));
-        } catch (NumberFormatException ex) {
+        } catch (NumberFormatException ignored) {
         }
         Long shift = null;
         try {
             shift = Long.valueOf(arguments.get("shift"));
-        } catch (NumberFormatException ex) {
+        } catch (NumberFormatException ignored) {
         }
 
-        LOGGER.log(Level.INFO, "Reading traces");
+        LOGGER.info("Reading traces");
         List<Trace> traces = TraceReader.parseFile(tracePath, Mode.valueOf(mode.toUpperCase()), window, shift);
-        LOGGER.log(Level.INFO, "Grouping {0} traces by methods", traces.size());
+        LOGGER.info(MessageFormat.format("Grouping {0} traces by methods", traces.size()));
         List<Method> methods = TraceReader.groupByMethods(traces);
-        LOGGER.log(Level.INFO, "grouped traces into {0} methods", methods.size());
+        LOGGER.info(MessageFormat.format("grouped traces into {0} methods", methods.size()));
 
         Configuration.setLevel("input");
         Configuration.setKernel(arguments.get("tfkernel"));
         Configuration.setStaleness(arguments.get("tfstaleness"));
         Configuration.setStore(arguments.get("tfstore"));
+        Configuration.setInput(Arrays.stream(tracePath.split("/")).reduce((a, b) -> b).orElse(""));
+        Configuration.setPreferences(arguments.get("objective"));
         StorageManager.load();
         APLCache aplcache = new APLCache(methods);
         aplcache.recommend(k, outputPath);