Method.java

224 lines | 8.344 kB Blame History Raw Download
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufrgs.inf.prosoft.memoizeit;

import br.ufrgs.inf.prosoft.memoizeit.cache.CachingPerformance;
import br.ufrgs.inf.prosoft.memoizeit.cache.MultiCache;
import br.ufrgs.inf.prosoft.memoizeit.cache.SingleCache;
import br.ufrgs.inf.prosoft.memoizeit.graph.Node;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author romulo
 */
public class Method {

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

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

    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 void setRepresentativeness(double representativeness) {
        this.representativeness = representativeness;
    }

    public double getRepresentativeness() {
        return 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.INFO, "Grouping 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) {
                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 isChangeful() {
        for (Map.Entry<String, List<Occurrence>> entry : this.groupByParameter.entrySet()) {
            if (entry.getValue().size() == 1) {
                continue;
            }
            Occurrence firstOccurrence = entry.getValue().get(0);
            if (entry.getValue().stream()
                    .anyMatch(occurrence -> occurrence.getReturnValue() != null
                    && !occurrence.getReturnValue().equals(firstOccurrence.getReturnValue()))) {
                return true;
            }
        }
        return false;
    }

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

    protected void removeUnusedFields(Node<String> methodNode) {
        logger.log(Level.INFO, "Removing 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) {
                        System.out.print(".");
                        if (i++ % 100 == 0) {
                            System.out.println();
                        }
                        occurrence.removeUnusedFields(methodNode);
                    }
                });
        System.out.println();
    }

    protected Map<String, CachingPerformance> simulateCachingStrategies() {
        Map<String, CachingPerformance> cachingStrategyHasPerformance = new HashMap<>();
        CachingPerformance globalMultiCachePerformance = new CachingPerformance();
        CachingPerformance globalSingleCachePerformance = new CachingPerformance();
        CachingPerformance instanceMultiCachePerformance = new CachingPerformance();
        CachingPerformance instanceSingleCachePerformance = new CachingPerformance();
        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;
    }

}