Details
diff --git a/src/main/java/br/ufrgs/inf/prosoft/tfcache/Main.java b/src/main/java/br/ufrgs/inf/prosoft/tfcache/Main.java
index ab6e6fd..e33362d 100755
--- a/src/main/java/br/ufrgs/inf/prosoft/tfcache/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/tfcache/Main.java
@@ -72,6 +72,10 @@ public class Main {
LOGGER.log(Level.INFO, "Grouping {0} traces by methods", traces.size());
List<Method> methods = TraceReader.groupByMethods(traces);
TFCache tfCache = new TFCache(methods);
- tfCache.recommend(changeability.equals("true"), output);
+ if (level.equals("input")) {
+ tfCache.recommend(changeability.equals("true"), output);
+ } else {
+ tfCache.recommend(changeability.equals("true"));
+ };
}
}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/GroupOfOccurrences.java b/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/GroupOfOccurrences.java
index 4bc3a88..dfb2750 100755
--- a/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/GroupOfOccurrences.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/GroupOfOccurrences.java
@@ -7,11 +7,17 @@ package br.ufrgs.inf.prosoft.tfcache.metadata;
import br.ufrgs.inf.prosoft.tfcache.Metrics;
import br.ufrgs.inf.prosoft.tfcache.Simulator;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;
@@ -56,7 +62,7 @@ public class GroupOfOccurrences {
return getBestMetrics().getSavedTime();
}
- public Double getHitsPerTimeInCache() {
+ public BigDecimal getHitsPerTimeInCache() {
return getBestMetrics().getHitsPerTimeInCache();
}
@@ -83,9 +89,21 @@ public class GroupOfOccurrences {
if (this.occurrences.size() < 2) {
throw new RuntimeException("Not reusable input");
}
- long maxTTL = this.occurrences.get(this.occurrences.size() - 1).getStartTime() - this.occurrences.get(0).getStartTime();
this.bestMetrics = new Metrics();
- LongStream.range(1, maxTTL).parallel().forEach(actualTTL -> {
+
+ 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);
});
}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/Method.java b/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/Method.java
index 1c5c3d8..bdfc484 100755
--- a/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/Method.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/tfcache/metadata/Method.java
@@ -7,8 +7,11 @@ package br.ufrgs.inf.prosoft.tfcache.metadata;
import br.ufrgs.inf.prosoft.tfcache.Metrics;
import br.ufrgs.inf.prosoft.tfcache.Simulator;
+import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -17,7 +20,6 @@ import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
-import java.util.stream.LongStream;
import java.util.stream.Stream;
/**
@@ -27,7 +29,6 @@ import java.util.stream.Stream;
public class Method {
private static final Logger LOGGER = Logger.getLogger(Method.class.getName());
- private static final boolean TRACER_VERBOSE = System.getenv("TRACER_VERBOSE") != null && System.getenv("TRACER_VERBOSE").equals("true");
private final String name;
private List<Occurrence> occurrences;
@@ -67,7 +68,7 @@ public class Method {
return getBestMetrics().getSavedTime();
}
- public Double getHitsPerTimeInCache() {
+ public BigDecimal getHitsPerTimeInCache() {
return getBestMetrics().getHitsPerTimeInCache();
}
@@ -157,7 +158,10 @@ public class Method {
}
int initialCountofOccurrences = this.groupsOfOccurrences.size();
this.groupsOfOccurrences.removeIf(groupOfOccurrences -> groupOfOccurrences.getOccurrencesSize() < 2);
- LOGGER.log(Level.INFO, "\tKept {0} of {1} inputs from method {2}", new Object[]{this.groupsOfOccurrences.size(), initialCountofOccurrences, this.name});
+ 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 boolean isReusable() {
@@ -182,38 +186,48 @@ public class Method {
if (this.occurrences == null) {
throw new RuntimeException("groupByInputs called. Cannot proceed");
}
+ this.bestMetrics = new Metrics();
if (this.occurrences.size() < 2) {
- throw new RuntimeException("Not reusable method");
+ return;
}
- long maxTTL = this.occurrences.get(this.occurrences.size() - 1).getStartTime() - this.occurrences.get(0).getStartTime();
- this.bestMetrics = new Metrics();
- LongStream.range(1, maxTTL).parallel().forEach(actualTTL -> {
+ 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 recommendTTLPerInput() {
- if (this.bestMetrics != null) {
- throw new RuntimeException("ttl already computed");
- }
if (this.groupsOfOccurrences == null) {
groupByInput();
removeSingleOccurrences();
}
groupsOfOccurrences().forEach(GroupOfOccurrences::calculateHitsPerTimeInCache);
- 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);
+ 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 rankRecommendations() {
if (this.groupsOfOccurrences == null) {
throw new RuntimeException("groupsOfOccurrences is null");
}
- this.groupsOfOccurrences.sort((occurrence1, occurrence2) -> Long.compare(occurrence2.getSavedTime(), occurrence1.getSavedTime()));
+ this.groupsOfOccurrences.sort((group1, group2) -> Long.compare(group2.getSavedTime(), group1.getSavedTime()));
}
@Override
diff --git a/src/main/java/br/ufrgs/inf/prosoft/tfcache/Metrics.java b/src/main/java/br/ufrgs/inf/prosoft/tfcache/Metrics.java
index 7671a73..196d3bd 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/tfcache/Metrics.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/tfcache/Metrics.java
@@ -5,6 +5,15 @@
*/
package br.ufrgs.inf.prosoft.tfcache;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
/**
*
* @author romulo
@@ -13,12 +22,13 @@ public class Metrics implements Comparable<Metrics> {
private long ttl;
private long savedTime;
- private double hitsPerTimeInCache;
+ private BigDecimal hitsPerTimeInCache;
public Metrics() {
+ this.hitsPerTimeInCache = new BigDecimal(BigInteger.ZERO);
}
- public Metrics(long ttl, long savedTime, double hitsPerTimeInCache) {
+ public Metrics(long ttl, long savedTime, BigDecimal hitsPerTimeInCache) {
this.ttl = ttl;
this.savedTime = savedTime;
this.hitsPerTimeInCache = hitsPerTimeInCache;
@@ -32,17 +42,23 @@ public class Metrics implements Comparable<Metrics> {
return this.savedTime;
}
- public double getHitsPerTimeInCache() {
+ public BigDecimal getHitsPerTimeInCache() {
return this.hitsPerTimeInCache;
}
public synchronized void keepBestMetrics(long ttl, long hits, long timeInCache, long savedTime) {
- if (hits == 0) {
+ if (ttl < 0 || hits < 0 || timeInCache < 0 || savedTime < 0) {
+ throw new RuntimeException("Metrics cannot be under zero. TTL: " + ttl + " hits: " + hits + " timeInCache: " + timeInCache + " savedTime: " + savedTime);
+ }
+ if (ttl == 0 || hits == 0) {
return;
}
- double hitsPerTimeInCache = (double) (hits) / timeInCache;
+ if (timeInCache == 0 || savedTime == 0) {
+ throw new RuntimeException("timeInCache and savedTime should not be zero");
+ }
+ BigDecimal hitsPerTimeInCache = new BigDecimal(hits).divide(new BigDecimal(timeInCache), MathContext.DECIMAL128);
if (this.ttl == 0
- || this.hitsPerTimeInCache < hitsPerTimeInCache
+ || this.hitsPerTimeInCache.compareTo(hitsPerTimeInCache) == -1
|| (this.hitsPerTimeInCache == hitsPerTimeInCache && this.savedTime < savedTime)
|| (this.hitsPerTimeInCache == hitsPerTimeInCache && this.savedTime == savedTime && this.ttl > ttl)) {
this.ttl = ttl;
@@ -51,12 +67,32 @@ public class Metrics implements Comparable<Metrics> {
}
}
+ public static void removeDominatedMetrics(Collection<Metrics> metrics) {
+ Map<Long, List<Metrics>> groupBySavedTime = metrics.stream().collect(Collectors.groupingBy(Metrics::getSavedTime));
+ groupBySavedTime.forEach((savedTime, value) -> {
+ if (savedTime == 0) {
+ value.clear();
+ return;
+ }
+ Metrics max = value.stream().max(Metrics::compareTo).get();
+ value.removeIf(metric -> metric.getHitsPerTimeInCache().compareTo(max.getHitsPerTimeInCache()) == -1);
+ });
+
+ List<Metrics> localMaxima = groupBySavedTime.entrySet().stream()
+ .map(entry -> entry.getValue().stream())
+ .reduce(Stream::concat)
+ .orElse(Stream.empty())
+ .collect(Collectors.toList());
+
+ metrics.removeIf(metric -> !localMaxima.contains(metric));
+ }
+
@Override
public int compareTo(Metrics other) {
- if (this.hitsPerTimeInCache > other.hitsPerTimeInCache) {
+ if (this.hitsPerTimeInCache.compareTo(other.hitsPerTimeInCache) == 1) {
return 1;
}
- if (this.hitsPerTimeInCache < other.hitsPerTimeInCache) {
+ if (this.hitsPerTimeInCache.compareTo(other.hitsPerTimeInCache) == -1) {
return -1;
}
if (this.savedTime > other.savedTime) {
@@ -74,4 +110,29 @@ public class Metrics implements Comparable<Metrics> {
return 0;
}
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 97 * hash + (int) (this.ttl ^ (this.ttl >>> 32));
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Metrics)) {
+ return false;
+ }
+ return compareTo((Metrics) obj) == 0;
+ }
+
+ @Override
+ public Metrics clone() {
+ return new Metrics(this.ttl, this.savedTime, this.hitsPerTimeInCache);
+ }
+
+ @Override
+ public String toString() {
+ return "TTL: " + this.ttl + " HpTiC: " + this.hitsPerTimeInCache + " SavedTime: " + this.savedTime;
+ }
+
}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/tfcache/TFCache.java b/src/main/java/br/ufrgs/inf/prosoft/tfcache/TFCache.java
index 22342c6..b1a591b 100755
--- a/src/main/java/br/ufrgs/inf/prosoft/tfcache/TFCache.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/tfcache/TFCache.java
@@ -46,7 +46,7 @@ public class TFCache {
this.methods.sort((method1, method2) -> Long.compare(method2.getSavedTime(), method1.getSavedTime()));
LOGGER.log(Level.INFO, "Printing recommendations for {0} methods", this.methods.size());
this.methods.forEach(method -> {
- System.out.println(method.getName() + " -> TTL " + method.getBestMetrics().getTtl() + " saves " + method.getSavedTime());
+ System.out.println(method.getName() + " Occurrences " + method.getOccurrencesSize() + " Inputs " + method.groupsOfOccurrences().count() + " TTL " + method.getTtl() + " HpTiC " + method.getHitsPerTimeInCache() + " Saves " + method.getSavedTime());
});
}
@@ -61,14 +61,14 @@ public class TFCache {
this.methods.removeIf(method -> method.groupsOfOccurrences().count() < 1);
LOGGER.log(Level.INFO, "Recommending TTL to {0} methods", this.methods.size());
this.methods.forEach(Method::recommendTTLPerInput);
- LOGGER.log(Level.INFO, "Ranking {0} methods according saved time", this.methods.size());
+ LOGGER.log(Level.INFO, "Ranking {0} methods and inputs according saved time", this.methods.size());
this.methods.forEach(Method::rankRecommendations);
this.methods.sort((method1, method2) -> Long.compare(method2.getSavedTime(), method1.getSavedTime()));
LOGGER.log(Level.INFO, "Printing recommendations for {0} methods", this.methods.size());
this.methods.forEach(method -> {
- System.out.println(method.getName() + " TTL " + method.getTtl() + " saves " + method.getSavedTime());
- method.groupsOfOccurrences().forEach(occurrence -> {
- System.out.println("\t" + occurrence.getParameters().hashCode() + " -> TTL " + occurrence.getTtl() + " saves " + occurrence.getSavedTime());
+ System.out.println(method.getName() + " Occurrences " + method.getOccurrencesSize() + " Inputs " + method.groupsOfOccurrences().count() + " TTL " + method.getTtl() + " HpTiC " + method.getHitsPerTimeInCache() + " Saves " + method.getSavedTime());
+ method.groupsOfOccurrences().forEach(group -> {
+ System.out.println("\t" + group.getParameters().hashCode() + " Occurrences " + group.getOccurrencesSize() + " -> TTL " + group.getTtl() + " HpTiC " + group.getHitsPerTimeInCache() + " Saves " + group.getSavedTime());
});
});
try (FileWriter fileWriter = new FileWriter(outputPath)) {