tfcache

replaced longstream by ttlsofinterest [not exact]. fixed

5/1/2020 12:13:16 AM

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)) {