MemoizeIt.java

236 lines | 8.374 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 java.util.List;
import java.util.Map;

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

    // Total program execution time
    private long totalProgramExecution;
    // Average of all occurrences execution time
    private double averageProgramExecution;
    // Minimum Execution Time Threshold
    private long minimumExecutionTime;
    // Minimum Relative Execution Time Threshold
    private double minimumRelativeTime;
    // Minimum Calls
    private int minimumMethodCalls;
    // Minimum Potential Hit Ratio Threshold
    private double minimumHitRatio;
    // List of methods called
    private List<Method> methods;
    // Stoping condition to iterative algorithm
    private boolean maxDepthReached;

    public MemoizeIt() {
        this.maxDepthReached = false;
        this.minimumHitRatio = 0.5;
        this.minimumMethodCalls = 2;
        this.minimumRelativeTime = 1.0;
        this.minimumExecutionTime = 5;
    }

    public MemoizeIt(long totalProgramExecution) {
        this();
        this.maxDepthReached = false;
        this.totalProgramExecution = totalProgramExecution;
    }

    public MemoizeIt setTotalProgramExecution(long totalProgramExecution) {
        this.totalProgramExecution = totalProgramExecution;
        return this;
    }

    public MemoizeIt setMinimumExecutionTime(long minimumExecutionTime) {
        this.minimumExecutionTime = minimumExecutionTime;
        return this;
    }

    public MemoizeIt setMinimumRelativeTime(double minimumRelativeTime) {
        this.minimumRelativeTime = minimumRelativeTime;
        return this;
    }

    public MemoizeIt setMinimumMethodCalls(int minimumMethodCalls) {
        this.minimumMethodCalls = minimumMethodCalls;
        return this;
    }

    public MemoizeIt setMinimumHitRatio(double minimumHitRatio) {
        this.minimumHitRatio = minimumHitRatio;
        return this;
    }

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

    private void estimateTotalProgramExecution() {
        this.methods.forEach((method) -> {
            this.totalProgramExecution += method.getTotalExecutionTime();
        });
    }

    private void calculateAverageExecutionTime() {
        this.methods.forEach((method) -> {
            this.averageProgramExecution += method.getAverageExecutionTime();
        });
        this.averageProgramExecution /= this.methods.size();
    }

//    3.1 time and frequency profiling
    private void filterInitialCandidates() {
        if (this.totalProgramExecution == 0) {
            System.out.println("Warning: total program execution not informed. Using average of calls");
            calculateAverageExecutionTime();
        }
        int i = 0;
        while (i < this.methods.size()) {
            Method method = this.methods.get(i);
            double totalExecutionTime = method.getTotalExecutionTime();
            double averageExecutionTime = totalExecutionTime / method.getOccurrencesSize();
            double relativeExecutionTime = this.totalProgramExecution == 0 ? averageExecutionTime / this.averageProgramExecution : totalExecutionTime / this.totalProgramExecution;
            if (method.getOccurrencesSize() < this.minimumMethodCalls
                    || averageExecutionTime < this.minimumExecutionTime
                    || relativeExecutionTime < this.minimumRelativeTime) {
                this.methods.remove(method);
                continue;
            }
            i++;
        }
    }

//    3.2 input-output profiling
    private void refineCandidates() {
        refineCandidates(Integer.MAX_VALUE);
    }

    private void refineCandidates(int depth) {
        int i = 0;
        while (i < this.methods.size()) {
            Method method = this.methods.get(i);
            int occurrencesSize = method.getOccurrencesSize();
            if (depth < Integer.MAX_VALUE) {
                method.groupByParameter(depth);
                if (method.wasFullyExplored()) {
                    this.maxDepthReached = true;
                    i++;
                    continue;
                }
                this.maxDepthReached = false;
            } else {
                method.groupByParameter();
            }
            int distinctOccurrencesSize = method.getDistinctOccurrencesSize();
            if (occurrencesSize == distinctOccurrencesSize) {
                this.methods.remove(i);
                continue;
            }
            if (method.isChangeful()) {
                this.methods.remove(i);
                continue;
            }
            double potentialHitRatio = method.getPotentialHitRatio();
            if (potentialHitRatio < this.minimumHitRatio) {
                this.methods.remove(i);
                continue;
            }
            i++;
        }
    }

    private void refineCandidatesIteratively() {
        int depth = 1;
        while (true) {
            System.out.println("Exploring depth " + depth);
            refineCandidates(depth);
            if (this.methods.isEmpty()) {
                System.out.println("No caching candidates left to explore");
                break;
            }
            if (this.maxDepthReached) {
                System.out.println("Max depth reached");
                break;
            }
            depth *= 2;
        }
    }

    public void removeChangefulMethods() {
        if (this.methods.isEmpty()) {
            throw new RuntimeException("Empty execution traces");
        }
        filterInitialCandidates();
        refineCandidatesIteratively();
        rankMethods();
        suggestImplementations();
    }

//    3.3 clustering and ranking
    private void rankMethods() {
        rankMethods(true);
    }

    private void rankMethods(boolean cluster) {
        if (cluster) {
            clusterMethods();
        }
    }

    private void clusterMethods() {
    }

//    3.4 suggest cache implementation
    private void suggestImplementations() {
        for (Method method : this.methods) {
            System.out.println(method.getName());
            suggestImplementation(method);
            System.out.println();
        }
    }

    private void suggestImplementation(Method method) {
        Map<String, CachingPerformance> cachingStrategyHasPerformance = method.simulateCachingStrategies();
        CachingPerformance globalMultiCachePerformance = cachingStrategyHasPerformance.get("globalMultiCache");
        CachingPerformance globalSingleCachePerformance = cachingStrategyHasPerformance.get("globalSingleCache");
        CachingPerformance instanceMultiCachePerformance = cachingStrategyHasPerformance.get("instanceMultiCache");
        CachingPerformance instanceSingleCachePerformance = cachingStrategyHasPerformance.get("instanceSingleCache");
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("GS: ");
        stringBuilder.append("R").append(globalSingleCachePerformance.getHitRatio());
        stringBuilder.append(" * ").append(globalSingleCachePerformance);
        stringBuilder.append(" | IS: ");
        stringBuilder.append("R").append(instanceSingleCachePerformance.getHitRatio());
        stringBuilder.append(" * ").append(instanceSingleCachePerformance);
        stringBuilder.append(" | GM: ");
        stringBuilder.append("R").append(globalMultiCachePerformance.getHitRatio());
        stringBuilder.append(" * ").append(globalMultiCachePerformance);
        stringBuilder.append(" | IM: ");
        stringBuilder.append("R").append(instanceMultiCachePerformance.getHitRatio());
        stringBuilder.append(" * ").append(instanceMultiCachePerformance);
        System.out.println(stringBuilder);
        if (globalSingleCachePerformance.getHitRatio() >= 50) {
            System.out.println("single, global");
        } else if (instanceSingleCachePerformance.getHitRatio() >= 50) {
            System.out.println("single, instance");
        } else if (globalMultiCachePerformance.getHitRatio() >= 50) {
            System.out.println("multi, global");
        } else if (instanceMultiCachePerformance.getHitRatio() >= 50) {
            System.out.println("multi, instance");
        } else {
            System.out.println("none");
        }
    }
}