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