MemoizeIt.java
Home
/
src /
main /
java /
br /
ufrgs /
inf /
prosoft /
memoizeit /
MemoizeIt.java
/*
* 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 java.util.List;
/**
*
* @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();
refineCandidates();
}
}