TFCache.java

122 lines | 6.125 kB Blame History Raw Download
package br.ufrgs.inf.prosoft.tfcache;

import br.ufrgs.inf.prosoft.tfcache.configuration.Configuration;
import br.ufrgs.inf.prosoft.tfcache.metadata.Method;
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.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;

public class TFCache {

  private static final Logger LOGGER = Logger.getLogger(TFCache.class.getName());
  private final List<Method> methods;

  public TFCache(List<Method> methods) {
    this.methods = methods;
  }

  public Stream<Method> methods() {
    return this.methods.stream();
  }

  private void recommendCacheableMethods() {
    if (Configuration.getChangeability().equals("deny")) {
      LOGGER.log(Level.INFO, "Removing changeable from {0} methods", this.methods.size());
      this.methods.removeIf(Method::isChangeable);
    }
    LOGGER.log(Level.INFO, "Removing not reusable from {0} methods", this.methods.size());
    this.methods.removeIf(Method::isNotReusable);
    LOGGER.log(Level.INFO, "Recommending TTL to {0} methods", this.methods.size());
    if (Configuration.getVerbose()) this.methods.forEach(Method::recommendTTL);
    else this.methods.stream().parallel().forEach(Method::recommendTTL);
    LOGGER.log(Level.INFO, "Removing not recommended from {0}", this.methods.size());
    this.methods.removeIf(method -> method.getBestMetrics().getSavedTime() == 0);
    LOGGER.log(Level.INFO, "Ranking {0} methods according saved time", this.methods.size());
    this.methods.sort((method1, method2) -> Double.compare(method2.getBestMetrics().getSavedTime(), method1.getBestMetrics().getSavedTime()));
    LOGGER.log(Level.INFO, "Printing recommendations for {0} methods", this.methods.size());
    this.methods.forEach(method -> System.out.println(method.getName()
      + " Occurrences " + method.occurrences().count()
      + " Inputs " + method.groupsOfOccurrences().count()
      + " TTL " + method.getBestMetrics().getTtl()
      + " Saves " + method.getBestMetrics().getSavedTime()
      + " Hits " + method.getBestMetrics().getHits()
      + " Computation " + method.getBestMetrics().getComputationTime()
      + " TimeInCache " + method.getBestMetrics().getTimeInCache()
      + " Stales " + method.getBestMetrics().getStales()));
  }

  private void recommendCacheableInputs() {
    if (Configuration.getChangeability().equals("deny")) {
      LOGGER.log(Level.INFO, "Removing changeable inputs from {0} methods", this.methods.size());
      this.methods.forEach(Method::removeChangeableInputs);
    }
    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() < 1);
    LOGGER.log(Level.INFO, "Recommending TTL to {0} methods", this.methods.size());
    if (Configuration.getVerbose()) this.methods.forEach(Method::recommendTTLPerInput);
    else this.methods.stream().parallel().forEach(Method::recommendTTLPerInput);
    LOGGER.log(Level.INFO, "Removing not recommended inputs from {0}", this.methods.size());
    this.methods.forEach(Method::removeNotRecommendedInputs);
    LOGGER.log(Level.INFO, "Removing not recommended methods from {0}", this.methods.size());
    this.methods.removeIf(method -> method.groupsOfOccurrences().count() < 1);
    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) -> Double.compare(method2.getEstimatedSavedTime(), method1.getEstimatedSavedTime()));
    LOGGER.log(Level.INFO, "Printing recommendations for {0} methods", this.methods.size());
    this.methods.forEach(method -> {
      if (method.getBestMetrics() != null) {
        System.out.println(method.getName()
          + " Occurrences " + method.occurrences().count()
          + " Inputs " + method.groupsOfOccurrences().count()
          + " TTL " + method.getBestMetrics().getTtl()
          + " Saves " + method.getBestMetrics().getSavedTime()
          + " Hits " + method.getBestMetrics().getHits()
          + " Computation " + method.getBestMetrics().getComputationTime()
          + " TimeInCache " + method.getBestMetrics().getTimeInCache()
          + " Stales " + method.getBestMetrics().getStales());
      } else {
        System.out.println(method.getName());
      }
      if (Configuration.getVerbose()) {
        method.groupsOfOccurrences().forEach(group -> System.out.println("\t" + group.getParameters().hashCode()
          + " Occurrences " + group.occurrences().count()
          + " -> TTL " + group.getBestMetrics().getTtl()
          + " Saves " + group.getBestMetrics().getSavedTime()
          + " Hits " + group.getBestMetrics().getHits()
          + " Computation " + group.getBestMetrics().getComputationTime()
          + " TimeInCache " + group.getBestMetrics().getTimeInCache()
          + " Stales " + group.getBestMetrics().getHits()));
      }
    });
    try (FileWriter fileWriter = new FileWriter(Configuration.getOutput())) {
      JsonObject jsonCacheableParameters = new JsonObject();
      this.methods.forEach(method -> {
        JsonObject cacheableParameters = new JsonObject();
        method.groupsOfOccurrences().forEach(it -> cacheableParameters.addProperty(it.getParameters(), it.getBestMetrics().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>");
    }
  }

  public void recommend() {
    if (Configuration.getVerbose()) Configuration.setInput(Arrays.stream(Configuration.getInput().split("/")).reduce((a, b) -> b).orElse(""));
    if (Configuration.getLevel().equals("method")) recommendCacheableMethods();
    else recommendCacheableInputs();
  }

}