Method.java

173 lines | 6.301 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

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

    private final String name;
    private final List<Occurrence> occurrences;
    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 int getDistinctOccurrencesSize() {
        return this.groupByParameter.size();
    }

    public long getTotalExecutionTime() {
        return this.occurrences.stream()
                .map(occurrence -> 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) {
        this.groupByParameter = new HashMap<>();
        this.occurrences.forEach((occurrence) -> {
            if (depth < Integer.MAX_VALUE) {
                Occurrence truncated = occurrence.getView(depth);
                this.fullyExplored = truncated == occurrence;
                occurrence = truncated;
            }
            String parameters = occurrence.getParameters().toString();
            try {
                this.groupByParameter.get(parameters).add(occurrence);
            } catch (Exception e) {
                List<Occurrence> occurrences = new ArrayList<>();
                occurrences.add(occurrence);
                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);
            for (Occurrence occurrence : entry.getValue()) {
                if (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 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;
    }

}