in wayang-profiler/code/main/java/org/apache/wayang/profiler/log/GeneticOptimizerApp.java [321:440]
public void run() {
if (this.optimizationSpace.getNumDimensions() == 0) {
System.out.println("There is nothing to optimize - all estimators are specified in the configuration.");
System.exit(0);
}
// Initialize form the configuration.
long timeLimit = this.configuration.getLongProperty("wayang.profiler.ga.timelimit.ms", -1);
long stopMillis = timeLimit > 0 ? System.currentTimeMillis() + timeLimit : -1L;
int maxGen = (int) this.configuration.getLongProperty("wayang.profiler.ga.maxgenerations", 5000);
int maxStableGen = (int) this.configuration.getLongProperty("wayang.profiler.ga.maxstablegenerations", 2000);
double minFitness = this.configuration.getDoubleProperty("wayang.profiler.ga.minfitness", .0d);
int superOptimizations = (int) this.configuration.getLongProperty("wayang.profiler.ga.superoptimizations", 3);
boolean isBlocking = this.configuration.getBooleanProperty("wayang.profiler.ga.blocking", false);
long maxPartialExecutionRemovals = this.configuration.getLongProperty("wayang.profiler.ga.noise-filter.max", 3);
double partialExecutionRemovalThreshold = this.configuration.getDoubleProperty("wayang.profiler.ga.noise-filter.threshold", 2);
// Create the root optimizer and an initial population.
GeneticOptimizer generalOptimizer = this.createOptimizer(this.partialExecutions);
List<Individual> population = generalOptimizer.createInitialPopulation();
int generation = 0;
// Optimize on blocks.
if (isBlocking) {
for (List<PartialExecution> group : this.partialExecutionGroups) {
final PartialExecution representative = WayangCollections.getAny(group);
final Set<String> templateKeys = this.getLoadProfileEstimatorTemplateKeys(representative);
if (group.size() < 2) {
System.out.printf("Few measurement points for %s\n", templateKeys);
}
if (representative.getAtomicExecutionGroups().size() > 3) {
System.out.printf("Many subjects for %s\n", templateKeys);
}
long minExecTime = group.stream().mapToLong(PartialExecution::getMeasuredExecutionTime).min().getAsLong();
long maxExecTime = group.stream().mapToLong(PartialExecution::getMeasuredExecutionTime).max().getAsLong();
if (maxExecTime - minExecTime < 1000) {
System.out.printf("Narrow training data for %s\n", templateKeys);
continue;
}
final Tuple<Integer, List<Individual>> newGeneration = this.superOptimize(
superOptimizations, population, group, generation, maxGen, maxStableGen, minFitness, stopMillis
);
generation = newGeneration.getField0();
population = newGeneration.getField1();
final GeneticOptimizer tempOptimizer = this.createOptimizer(group);
this.printResults(tempOptimizer, population.get(0));
}
}
while (true) {
// Optimize on the complete training data.
final Tuple<Integer, List<Individual>> newGeneration = this.optimize(
population, generalOptimizer, generation, maxGen, maxStableGen, minFitness, stopMillis
);
generation = newGeneration.getField0();
population = newGeneration.getField1();
Individual fittestIndividual = population.get(0);
printResults(generalOptimizer, fittestIndividual);
if (maxPartialExecutionRemovals > 0) {
// Gather the PartialExecutions that are not well explained by the learned model.
List<Tuple<PartialExecution, Double>> partialExecutionDeviations = new ArrayList<>();
for (PartialExecution partialExecution : partialExecutions) {
final double timeEstimate = fittestIndividual.estimateTime(
partialExecution, this.platformOverheads, this.configuration
);
double deviation = (Math.max(timeEstimate, partialExecution.getMeasuredExecutionTime()) + 500) /
(Math.min(timeEstimate, partialExecution.getMeasuredExecutionTime()) + 500);
if (deviation > partialExecutionRemovalThreshold) {
partialExecutionDeviations.add(new Tuple<>(partialExecution, deviation));
}
}
// Check if we actually have a good model.
if (partialExecutionDeviations.isEmpty()) {
System.out.printf("All %d executions are explained well by the current model.\n", this.partialExecutions.size());
break;
}
// Check if we ran out of time.
if (stopMillis > 0 && System.currentTimeMillis() >= stopMillis) break;
// Remove the worst PartialExecutions.
System.out.printf("The current model is not explaining well %d of %d measured executions.\n",
partialExecutionDeviations.size(),
this.partialExecutions.size()
);
partialExecutionDeviations.sort((ped1, ped2) -> ped2.getField1().compareTo(ped1.getField1()));
long numRemovables = maxPartialExecutionRemovals;
for (Tuple<PartialExecution, Double> partialExecutionDeviation : partialExecutionDeviations) {
if (numRemovables-- <= 0) break;
final PartialExecution partialExecution = partialExecutionDeviation.getField0();
final double deviation = partialExecutionDeviation.getField1();
final double timeEstimate = fittestIndividual.estimateTime(
partialExecution, this.platformOverheads, this.configuration
);
System.out.printf("Removing %s... (estimated %s, deviation %,.2f)\n",
format(partialExecution), Formats.formatDuration(Math.round(timeEstimate)), deviation
);
this.partialExecutions.remove(partialExecution);
}
} else {
break;
}
}
String outputFile = this.configuration.getStringProperty("wayang.profiler.ga.output-file", null);
if (outputFile != null) {
Individual fittestIndividual = population.get(0);
try (PrintStream printStream = new PrintStream(new FileOutputStream(outputFile))) {
this.printLearnedConfiguration(generalOptimizer, fittestIndividual, printStream);
} catch (FileNotFoundException e) {
logger.error("Could not save learned configuration to output file.", e);
}
}
}