FlowchartWorkFlow.java

90 lines | 4.029 kB Blame History Raw Download
package br.ufrgs.inf.prosoft.aplcache.flowchart;

import br.ufrgs.inf.prosoft.aplcache.flowchart.metrics.CacheabilityMetrics;
import br.ufrgs.inf.prosoft.aplcache.flowchart.metrics.Thresholds;
import br.ufrgs.inf.prosoft.aplcache.metadata.Method;

import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FlowchartWorkFlow {

  private static final Logger LOGGER = Logger.getLogger(FlowchartWorkFlow.class.getName());

  private List<Method> methods;

  public FlowchartWorkFlow setMethods(List<Method> methods) {
    this.methods = methods;
    return this;
  }

  private void calculateMetrics() {
    LOGGER.log(Level.INFO, "Counting stats of {0} methods", this.methods.size());
    this.methods.sort(Comparator.comparingInt(Method::getOccurrencesSize));
    this.methods.stream().parallel().forEach(Method::calculateMetrics);
  }

  private void calculateThresholds(int kStdDev) {
    LOGGER.log(Level.INFO, "Calculating thresholds for {0} methods", this.methods.size());
    Thresholds.reset();
    Thresholds.population = getPopulation();
    this.methods.forEach(Method::calculateThresholds);

    LOGGER.log(Level.INFO, "\tAverage ExecutionTime: {0}", Thresholds.getAverageExecutionTime());
    LOGGER.log(Level.INFO, "\tAverage HitRatio: {0}", Thresholds.getAverageHitRatio());
    LOGGER.log(Level.INFO, "\tAverage MissRatio: {0}", Thresholds.getAverageMissRatio());
    LOGGER.log(Level.INFO, "\tAverage shareability: {0}", Thresholds.getAverageShareability());
    LOGGER.log(Level.INFO, "\tStdDv ExecutionTime: {0}", Thresholds.getStdDevExecutionTime());
    LOGGER.log(Level.INFO, "\tStdDv HitRatio: {0}", Thresholds.getStdDevHitRatio());
    LOGGER.log(Level.INFO, "\tStdDv MissRatio: {0}", Thresholds.getStdDevMissRatio());
    LOGGER.log(Level.INFO, "\tStdDv shareability: {0}", Thresholds.getStdDevShareability());
    LOGGER.log(Level.INFO, "\tStdDv frequency: {0}", Thresholds.getStdDevFrequency());

    LOGGER.log(Level.INFO, "Using {0} stdDev to calculate thresholds...", kStdDev);
    LOGGER.log(Level.INFO, "\tThreshold ExecutionTime: {0}", Thresholds.expensivenessThreshold(kStdDev));
    LOGGER.log(Level.INFO, "\tThreshold HitRatio: {0}", Thresholds.hitThreshold(kStdDev));
    LOGGER.log(Level.INFO, "\tThreshold MissRatio: {0}", Thresholds.missThreshold(kStdDev));
    LOGGER.log(Level.INFO, "\tThreshold Shareability: {0}", Thresholds.shareabilityThreshold(kStdDev));
    LOGGER.log(Level.INFO, "\tThreshold frequency: {0}", Thresholds.frequencyThreshold(kStdDev));
  }

  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() < 1);
    int removedMethods = initialMethodsSize - this.methods.size();
    if (removedMethods > 0) LOGGER.log(Level.INFO, "Removed {0} of {1} not reusable methods", new Object[]{removedMethods, initialMethodsSize});
  }

  public void filterCacheableInputs(boolean reusable) {
    filterCacheableInputs(0, reusable);
  }

  public void filterCacheableInputs(int kStdDev) {
    filterCacheableInputs(0, false);
  }

  public void filterCacheableInputs(int kStdDev, boolean reusable) {
    if (reusable) removeSingleOccurrences();
    calculateMetrics();
    calculateThresholds(kStdDev);
    LOGGER.log(Level.INFO, "Deciding if {0} methods are cacheable...", this.methods.size());
    CacheabilityMetrics.K_STANDARD_DEVIATION = kStdDev;
    this.methods.forEach(Method::filterCacheableInputs);
    this.methods.removeIf(method -> method.groupsOfOccurrences().count() == 0);
    LOGGER.log(Level.INFO, "{0} cacheable methods detected", this.methods.size());
  }

  private long getPopulation() {
    return this.methods.stream().parallel()
      .map(Method::getOccurrencesSize)
      .reduce(Integer::sum)
      .get();
  }

}