aplcachetf

replaced double by bigdecimal. replaced longstream by ttlsofinterest.

5/1/2020 12:27:07 AM

Details

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 cf68fd3..759e29a 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
@@ -61,16 +61,22 @@ public class APLCache {
         LOGGER.log(Level.INFO, "\tThreshold HitsPerTimeInCache: {0}", Thresholds.hitsPerTimeInCacheThreshold(kStdDev));
     }
 
-    private void filterUncacheableInputs(int 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} methods with no inputs recommemded", new Object[]{removedMethods, initialMethodsSize});
+            LOGGER.log(Level.INFO, "Removed {0} of {1} not reusable methods", new Object[]{removedMethods, initialMethodsSize});
         }
     }
 
@@ -79,9 +85,11 @@ public class APLCache {
     }
 
     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);
-        filterUncacheableInputs(kStdDev);
+        filterCacheableInputs(kStdDev);
 
         LOGGER.log(Level.INFO, "{0} cacheable methods detected", this.methods.size());
         Collections.sort(this.methods, (m1, m2) -> Long.compare(m2.getSavedTime(), m1.getSavedTime()));
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 9719bbd..611b32a 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
@@ -9,10 +9,12 @@ import br.ufrgs.inf.prosoft.aplcachetf.extension.metrics.Thresholds;
 import br.ufrgs.inf.prosoft.aplcachetf.extension.metrics.Metrics;
 import br.ufrgs.inf.prosoft.tfcache.Simulator;
 import br.ufrgs.inf.prosoft.tfcache.metadata.Occurrence;
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.util.stream.LongStream;
 import java.util.stream.Stream;
 import org.apache.commons.lang3.builder.EqualsBuilder;
 
@@ -60,30 +62,39 @@ public class GroupOfOccurrences {
         return getBestMetrics().getSavedTime();
     }
 
-    public Double getHitsPerTimeInCache() {
+    public BigDecimal getHitsPerTimeInCache() {
         return getBestMetrics().getHitsPerTimeInCache();
     }
 
-    public void calculateHitsPerTimeInCache() {
+    private void calculateHitsPerTimeInCache() {
         if (this.bestMetrics != null) {
             LOGGER.log(Level.WARNING, "HitsPerTimeInCache already calculated");
         }
         this.bestMetrics = new Metrics();
-        if (this.occurrences.size() < 2) {
-            return;
+
+        Collection<Long> ttlsOfInterest = new HashSet<>();
+        for (int hits = 1; hits < this.occurrences.size(); hits++) {
+            for (int shift = 0; shift < this.occurrences.size() - hits; shift++) {
+                long ttl = 0;
+                for (int k = shift + 1; k < shift + 1 + hits; k++) {
+                    ttl += this.occurrences.get(k).getStartTime() - this.occurrences.get(k - 1).getEndTime();
+                }
+                if (ttl > 0) {
+                    ttlsOfInterest.add(ttl);
+                }
+            }
         }
-        long maxTTL = this.occurrences.get(this.occurrences.size() - 1).getStartTime() - this.occurrences.get(0).getStartTime();
-        LongStream.range(1, maxTTL).parallel().forEach(actualTTL -> {
+
+        ttlsOfInterest.stream().parallel().forEach(actualTTL -> {
             Simulator.simulate(occurrences(), actualTTL, this.bestMetrics);
         });
     }
 
     protected void calculateMetrics() {
-        calculateHitsPerTimeInCache();
-        if (this.occurrences.size() == 1) {
-            this.bestMetrics.addSameOccurrence(this.occurrences.get(0));
-            return;
+        if (this.occurrences.size() < 2) {
+            throw new RuntimeException("Cannot calculate metrics for not reusable input");
         }
+        calculateHitsPerTimeInCache();
         for (int i = 0; i < this.occurrences.size(); i++) {
             Occurrence occurrence = this.occurrences.get(i);
             Object returnValue = occurrence.getReturnValue();
@@ -111,10 +122,8 @@ public class GroupOfOccurrences {
         Thresholds.sumShareability += this.bestMetrics.getShareability();
         Thresholds.shareabilities.add(this.bestMetrics.getShareability());
 
-        if (this.bestMetrics.getHitsPerTimeInCache() > 0) {
-            Thresholds.sumHitsPerTimeInCache += this.bestMetrics.getHitsPerTimeInCache();
-            Thresholds.hitsPerTimeInCache.add(this.bestMetrics.getHitsPerTimeInCache());
-        }
+        Thresholds.sumHitsPerTimeInCache.add(this.bestMetrics.getHitsPerTimeInCache());
+        Thresholds.hitsPerTimeInCache.add(this.bestMetrics.getHitsPerTimeInCache());
     }
 
 }
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 6a9af4d..480c262 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,8 +7,12 @@ 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.Simulator;
 import br.ufrgs.inf.prosoft.tfcache.metadata.Occurrence;
+import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -60,7 +64,7 @@ public class Method {
         return getBestMetrics().getSavedTime();
     }
 
-    public Double getHitsPerTimeInCache() {
+    public BigDecimal getHitsPerTimeInCache() {
         return getBestMetrics().getHitsPerTimeInCache();
     }
 
@@ -109,16 +113,60 @@ public class Method {
         this.occurrences = null;
     }
 
+    public void recommendTTL() {
+        if (this.bestMetrics != null) {
+            LOGGER.log(Level.WARNING, "HitsPerTimeInCache already calculated");
+        }
+        if (this.occurrences == null) {
+            throw new RuntimeException("groupByInputs called. Cannot proceed");
+        }
+        this.bestMetrics = new Metrics();
+        if (this.occurrences.size() < 2) {
+            return;
+        }
+
+        Collection<Long> ttlsOfInterest = new HashSet<>();
+        for (int hits = 1; hits < this.occurrences.size(); hits++) {
+            for (int shift = 0; shift < this.occurrences.size() - hits; shift++) {
+                long ttl = 0;
+                for (int k = shift + 1; k < shift + 1 + hits; k++) {
+                    ttl += this.occurrences.get(k).getStartTime() - this.occurrences.get(k - 1).getEndTime();
+                }
+                if (ttl > 0) {
+                    ttlsOfInterest.add(ttl);
+                }
+            }
+        }
+
+        ttlsOfInterest.stream().parallel().forEach(actualTTL -> {
+            Simulator.simulate(occurrences(), actualTTL, this.bestMetrics);
+        });
+    }
+
+    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});
+        }
+    }
+
     public void calculateMetrics() {
         if (this.groupsOfOccurrences == null) {
             groupByInput();
         }
-        this.groupsOfOccurrences.stream().forEach(GroupOfOccurrences::calculateMetrics);
-        long savedTime = groupsOfOccurrences().map(GroupOfOccurrences::getSavedTime).reduce(Long::sum).get();
-        GroupOfOccurrences max = groupsOfOccurrences().max((group1, group2) -> Long.compare(group1.getSavedTime(), group2.getSavedTime())).get();
-        long ttl = max.getTtl();
-        double hitsPerTimeInCache = max.getHitsPerTimeInCache();
-        this.bestMetrics = new Metrics(ttl, savedTime, hitsPerTimeInCache);
+        groupsOfOccurrences().forEach(GroupOfOccurrences::calculateMetrics);
+        if (this.bestMetrics == null) {
+            long savedTime = groupsOfOccurrences().map(GroupOfOccurrences::getSavedTime).reduce(Long::sum).get();
+            GroupOfOccurrences max = groupsOfOccurrences().max((group1, group2) -> Long.compare(group1.getSavedTime(), group2.getSavedTime())).get();
+            long ttl = max.getTtl();
+            BigDecimal hitsPerTimeInCache = max.getHitsPerTimeInCache();
+            this.bestMetrics = new Metrics(ttl, savedTime, hitsPerTimeInCache);
+        }
     }
 
     public void calculateThresholds() {
@@ -136,7 +184,7 @@ public class Method {
         this.groupsOfOccurrences.removeIf(groupOfOccurrence -> groupOfOccurrence.getTtl() == 0);
         removedInputs = initialInputsSize - this.groupsOfOccurrences.size();
         if (removedInputs > 0) {
-            LOGGER.log(Level.INFO, "\tRemoved {0} of {1} single-occurrence inputs from method {2}", new Object[]{removedInputs, initialInputsSize, this.name});
+            LOGGER.log(Level.INFO, "\tRemoved {0} of {1} inputs with 0 TTL from method {2}", new Object[]{removedInputs, initialInputsSize, this.name});
         }
     }
 
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 541d854..820778c 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
@@ -17,7 +17,7 @@ public class CacheabilityMetrics {
     }
 
     public static Optional<Boolean> usedByManyRequests(GroupOfOccurrences groupOfOccurrences) {
-        return Optional.of(groupOfOccurrences.getBestMetrics().getHitsPerTimeInCache() >= Thresholds.hitsPerTimeInCacheThreshold(K_STANDARD_DEVIATION));
+        return Optional.of(groupOfOccurrences.getBestMetrics().getHitsPerTimeInCache().compareTo(Thresholds.hitsPerTimeInCacheThreshold(K_STANDARD_DEVIATION)) >= 0);
     }
 
     public static Optional<Boolean> isUserSpecific(GroupOfOccurrences groupOfOccurrences) {
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 895c0d3..edc8a75 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
@@ -6,6 +6,8 @@
 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;
@@ -20,14 +22,14 @@ public class Thresholds {
     public static double sumHitRatio;
     public static double sumExecutionTime;
     public static double sumShareability;
-    public static double sumHitsPerTimeInCache;
+    public static BigDecimal sumHitsPerTimeInCache;
 
-    public static Double averageHitsPerTimeInCache;
+    public static BigDecimal averageHitsPerTimeInCache;
 
     public static Double stdDevHitRatio;
     public static Double stdDevMissRatio;
     public static Double stdDevExecutionTimeRatio;
-    public static Double stdDevHitsPerTimeInCache;
+    public static BigDecimal stdDevHitsPerTimeInCache;
     public static Double stdDevShareability;
 
     public static long population;
@@ -36,14 +38,14 @@ public class Thresholds {
     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<Double> hitsPerTimeInCache = new ArrayList<>();
+    public static final List<BigDecimal> hitsPerTimeInCache = new ArrayList<>();
 
     public static void reset() {
         Thresholds.sumMissRatio = 0;
         Thresholds.sumHitRatio = 0;
         Thresholds.sumExecutionTime = 0;
         Thresholds.sumShareability = 0;
-        Thresholds.sumHitsPerTimeInCache = 0;
+        Thresholds.sumHitsPerTimeInCache = new BigDecimal(BigInteger.ZERO);
 
         Thresholds.averageHitsPerTimeInCache = null;
 
@@ -145,20 +147,20 @@ public class Thresholds {
         return stdDevExecutionTimeRatio;
     }
 
-    public static double getStdDevHitsPerTimeInCache() {
+    public static BigDecimal getStdDevHitsPerTimeInCache() {
         if (population == 0) {
-            return 0;
+            return new BigDecimal(BigInteger.ZERO);
         }
         if (stdDevHitsPerTimeInCache != null) {
             return stdDevHitsPerTimeInCache;
         }
 
-        double mean = getAverageHitsPerTimeInCache();
-        double temp = hitsPerTimeInCache.stream()
-                .map(frequency -> (frequency - mean) * (frequency - mean))
-                .reduce(Double::sum)
-                .orElse(0D);
-        stdDevHitsPerTimeInCache = Math.sqrt(temp / population);
+        BigDecimal mean = getAverageHitsPerTimeInCache();
+        BigDecimal temp = hitsPerTimeInCache.stream()
+                .map(frequency -> frequency.subtract(mean).multiply(frequency.subtract(mean)))
+                .reduce(BigDecimal::add)
+                .orElse(new BigDecimal(BigInteger.ZERO));
+        stdDevHitsPerTimeInCache = temp.divide(new BigDecimal(population), MathContext.DECIMAL128).sqrt(MathContext.DECIMAL128);
         return stdDevHitsPerTimeInCache;
     }
 
@@ -179,15 +181,15 @@ public class Thresholds {
         return stdDevShareability;
     }
 
-    public static double getAverageHitsPerTimeInCache() {
+    public static BigDecimal getAverageHitsPerTimeInCache() {
         if (hitsPerTimeInCache.isEmpty()) {
-            return 0;
+            return new BigDecimal(BigInteger.ZERO);
         }
         if (averageHitsPerTimeInCache != null) {
             return averageHitsPerTimeInCache;
         }
 
-        averageHitsPerTimeInCache = new BigDecimal(sumHitsPerTimeInCache).divide(new BigDecimal(hitsPerTimeInCache.size()), 5, RoundingMode.HALF_UP).doubleValue();
+        averageHitsPerTimeInCache = sumHitsPerTimeInCache.divide(new BigDecimal(hitsPerTimeInCache.size()), 5, RoundingMode.HALF_UP);
         return averageHitsPerTimeInCache;
     }
 
@@ -211,8 +213,8 @@ public class Thresholds {
     }
 
 //getting X% most frenquent
-    public static double hitsPerTimeInCacheThreshold(int kStdDev) {
-        return getAverageHitsPerTimeInCache() + (kStdDev * getStdDevHitsPerTimeInCache());
+    public static BigDecimal hitsPerTimeInCacheThreshold(int kStdDev) {
+        return getAverageHitsPerTimeInCache().add(getStdDevHitsPerTimeInCache().multiply(new BigDecimal(kStdDev)));
     }
 
 }