public void run()

in wayang-profiler/src/main/java/org/apache/wayang/profiler/log/GeneticOptimizerApp.java [320:439]


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

    }