FlowchartWorkFlow.java

92 lines | 4.2 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.Collections;
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());
        Collections.sort(this.methods, (m1, m2) -> Integer.compare(m1.getOccurrencesSize(), m2.getOccurrencesSize()));
        this.methods.stream().parallel().forEach(Method::calculateMetrics);
    }

    private void calculateThresholds(int kStdDev) {
        LOGGER.log(Level.INFO, "Calculating thresholds");
        Thresholds.reset();
        Thresholds.population = getPopulation();
        this.methods.stream().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.getStdDevExecutionTimeRatio());
        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, boolean reusable) {
        if (reusable) {
            removeSingleOccurrences();
        }
        calculateMetrics();
        calculateThresholds(kStdDev);

        LOGGER.log(Level.INFO, "Deciding if methods are cacheable...");

        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();
    }
}