Method.java

209 lines | 7.257 kB Blame History Raw Download
package br.ufrgs.inf.prosoft.memoizeit;

import br.ufrgs.inf.prosoft.cache.CachePerformance;
import br.ufrgs.inf.prosoft.cache.MultiCache;
import br.ufrgs.inf.prosoft.cache.SingleCache;
import br.ufrgs.inf.prosoft.memoizeit.graph.Node;

import java.util.*;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;

public class Method {

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

  private final String name;
  private final List<Occurrence> occurrences;
  private final boolean isStatic;
  private double representativeness;
  private Map<String, List<Occurrence>> groupByParameter;
  private Boolean fullyExplored;

  public Method(String name, boolean isStatic, List<Occurrence> occurrences) {
    this.name = name;
    this.occurrences = occurrences;
    this.fullyExplored = false;
    this.isStatic = isStatic;
  }

  public String getName() {
    return name;
  }

  public int getOccurrencesSize() {
    return this.occurrences.size();
  }

  public Stream<Occurrence> occurrences() {
    return this.occurrences.stream();
  }

  public double getRepresentativeness() {
    return representativeness;
  }

  public void setRepresentativeness(double representativeness) {
    this.representativeness = representativeness;
  }

  public int getDistinctOccurrencesSize() {
    return this.groupByParameter.size();
  }

  public long getTotalExecutionTime() {
    return this.occurrences.stream()
      .map(Occurrence::getExecutionTime)
      .reduce(Long::sum).get();
  }

  public long getAverageExecutionTime() {
    return getTotalExecutionTime() / this.occurrences.size();
  }

  public double getSavedTime() {
    return getAverageExecutionTime() * getPotentialHitRatio();
  }

  protected boolean wasFullyExplored() {
    return this.fullyExplored;
  }

  protected void groupByParameter(int depth) {
    LOGGER.log(Level.FINE, "\tGrouping by parameters {0} occurrences of {1}", new Object[]{this.name, this.occurrences.size()});
    this.groupByParameter = new HashMap<>();
    this.occurrences.stream().parallel().forEach(new Consumer<Occurrence>() {
      int i = 0;

      @Override
      public void accept(Occurrence occurrence) {
        String verbose = System.getenv("TRACER_VERBOSE");
        if (verbose != null && verbose.equals("true")) {
          System.out.print(".");
          System.out.flush();
          if (++i % 100 == 0) System.out.println();
        }
        if (depth < Integer.MAX_VALUE) {
          OccurrenceConcrete thisOccurrence = occurrence.getConcrete();
          OccurrenceConcrete truncated = thisOccurrence.getView(depth);
          Method.this.fullyExplored = truncated == thisOccurrence;
          occurrence = truncated;
        }
        String parameters = occurrence.getParameters().toString();
        synchronized (Method.this.groupByParameter) {
          try {
            Method.this.groupByParameter.get(parameters).add(occurrence);
          } catch (Exception e) {
            List<Occurrence> occurrences = new ArrayList<>();
            occurrences.add(occurrence);
            Method.this.groupByParameter.put(parameters, occurrences);
          }
        }
      }
    });
  }

  protected void groupByParameter() {
    groupByParameter(Integer.MAX_VALUE);
  }

  protected boolean isChangeable() {
    for (List<Occurrence> occurrences : this.groupByParameter.values()) {
      if (occurrences.size() == 1) continue;
      Occurrence firstOccurrence = occurrences.get(0);
      if (occurrences.stream().anyMatch(occurrence -> occurrence.getReturnValue() != null
        && !occurrence.getReturnValue().equals(firstOccurrence.getReturnValue()))) {
        return true;
      }
    }
    return false;
  }

  protected double getPotentialHitRatio() {
    double potentialHitRatio = this.groupByParameter.values().stream().map(List::size).reduce(Integer::sum).get();
    potentialHitRatio = (potentialHitRatio - this.groupByParameter.size()) / potentialHitRatio;
    return potentialHitRatio;
  }

  protected void removeUnusedFields(Node<String> methodNode) {
    LOGGER.log(Level.FINE, "\tRemoving unused fields of {0} occurrences of {1}", new Object[]{this.occurrences.size(), this.name});
    if (methodNode == null) {
      LOGGER.log(Level.WARNING, "methodNode null: {0}", this.name);
      return;
    }
    this.occurrences.stream().parallel()
      .forEach(new Consumer<Occurrence>() {
        private int i = 1;

        @Override
        public void accept(Occurrence occurrence) {
          String verbose = System.getenv("TRACER_VERBOSE");
          if (verbose != null && verbose.equals("true")) {
            System.out.print(".");
            if (i++ % 100 == 0) System.out.println();
          }
          occurrence.removeUnusedFields(methodNode);
        }
      });
  }

  protected Map<String, CachePerformance> simulateCachingStrategies() {
    Map<String, CachePerformance> cachingStrategyHasPerformance = new HashMap<>();
    CachePerformance globalMultiCachePerformance = new CachePerformance();
    CachePerformance globalSingleCachePerformance = new CachePerformance();
    CachePerformance instanceMultiCachePerformance = new CachePerformance();
    CachePerformance instanceSingleCachePerformance = new CachePerformance();
    cachingStrategyHasPerformance.put("globalMultiCache", globalMultiCachePerformance);
    cachingStrategyHasPerformance.put("globalSingleCache", globalSingleCachePerformance);
    cachingStrategyHasPerformance.put("instanceMultiCache", instanceMultiCachePerformance);
    cachingStrategyHasPerformance.put("instanceSingleCache", instanceSingleCachePerformance);
    MultiCache globalMultiCache = new MultiCache(globalMultiCachePerformance);
    SingleCache globalSingleCache = new SingleCache(globalSingleCachePerformance);
    Map<String, MultiCache> instanceHasMultiCache = new HashMap<>();
    Map<String, SingleCache> instanceHasSingleCache = new HashMap<>();
    for (Occurrence occurrence : this.occurrences) {
      if (!this.isStatic) {
        MultiCache instanceMultiCache = instanceHasMultiCache.get(occurrence.getInstance());
        if (instanceMultiCache == null) {
          instanceMultiCache = new MultiCache(instanceMultiCachePerformance);
          instanceHasMultiCache.put(occurrence.getInstance(), instanceMultiCache);
        }
        occurrence.simulateCaching(instanceMultiCache);
        SingleCache instanceSingleCache = instanceHasSingleCache.get(occurrence.getInstance());
        if (instanceSingleCache == null) {
          instanceSingleCache = new SingleCache(instanceSingleCachePerformance);
          instanceHasSingleCache.put(occurrence.getInstance(), instanceSingleCache);
        }
        occurrence.simulateCaching(instanceSingleCache);
      }
      occurrence.simulateCaching(globalMultiCache);
      occurrence.simulateCaching(globalSingleCache);
    }
    return cachingStrategyHasPerformance;
  }

  @Override
  public int hashCode() {
    int hash = 5;
    hash = 37 * hash + Objects.hashCode(this.name);
    return hash;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (!(obj instanceof Method)) return false;
    Method method = (Method) obj;
    return this.name.equals(method.name);
  }

  @Override
  public String toString() {
    return this.name;
  }

}