org.cloudsimplus.testbeds.heuristics.DatacenterBrokerHeuristicRunner.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudsimplus.testbeds.heuristics.DatacenterBrokerHeuristicRunner.java

Source

/**
 * CloudSim Plus: A modern, highly-extensible and easier-to-use Framework for
 * Modeling and Simulation of Cloud Computing Infrastructures and Services.
 * http://cloudsimplus.org
 *
 *     Copyright (C) 2015-2016  Universidade da Beira Interior (UBI, Portugal) and
 *     the Instituto Federal de Educao Cincia e Tecnologia do Tocantins (IFTO, Brazil).
 *
 *     This file is part of CloudSim Plus.
 *
 *     CloudSim Plus is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     CloudSim Plus is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with CloudSim Plus. If not, see <http://www.gnu.org/licenses/>.
 */
package org.cloudsimplus.testbeds.heuristics;

import org.apache.commons.math3.stat.descriptive.SummaryStatistics;

import org.cloudbus.cloudsim.cloudlets.Cloudlet;
import org.cloudbus.cloudsim.brokers.DatacenterBrokerSimple;
import org.cloudbus.cloudsim.util.Log;
import org.cloudbus.cloudsim.distributions.NormalDistr;
import org.cloudbus.cloudsim.distributions.UniformDistr;
import org.cloudsimplus.heuristics.CloudletToVmMappingSolution;
import org.cloudsimplus.heuristics.Heuristic;
import org.cloudsimplus.testbeds.ExperimentRunner;
import org.cloudsimplus.testbeds.SimulationExperiment;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.cloudbus.cloudsim.distributions.ContinuousDistribution;

/**
 * Runs the {@link DatacenterBrokerHeuristicExperiment} the number of times
 * defines by {@link #numberOfSimulationRuns} and compute statistics.
 *
 * @author Manoel Campos da Silva Filho
 */
final class DatacenterBrokerHeuristicRunner extends ExperimentRunner<DatacenterBrokerHeuristicExperiment> {

    /**
     * Number of Cloudlets to create for each experiment.
     */
    public static final int CLOUDLETS_TO_CREATE = 100;

    /**
     * Possible number of PEs for VMs to be created. Each VM has to have one of
     * this number of PEs, to be chosen randomly.
     */
    private static final int VM_PES_NUMBERS[] = { 2, 4, 8 };

    /**
     * Number of Vm's to create for each experiment.
     */
    private static final int VMS_TO_CREATE = VM_PES_NUMBERS.length * 20;

    /**
     * Number of PEs for each created Cloudlet. All the experiments run with the
     * same scenario configuration, including number of hosts, VMs and
     * Cloudlets. What changes is the random number generator seed for each
     * experiment.
     */
    private int cloudletPesArray[];

    /**
     * Number of PEs for each created VM. All the experiments run with the same
     * scenario configuration, including number of hosts, VMs and Cloudlets.
     * What changes is the random number generator seed for each experiment.
     */
    private int vmPesArray[];

    /**
     * The cost to map Cloudlets to VMs for each executed experiment.
     */
    private List<Double> experimentCosts;

    /**
     * An object that compute statistics about experiment execution time of all
     * executed experiment runs.
     */
    private final SummaryStatistics runtimeStats;

    /**
     * A Cloudlet to VM mapping that used a Round-Robin implementation to
     * cyclically select a Vm from the Vm list to host a Cloudlet. This is the
     * implementation used by the {@link DatacenterBrokerSimple} class.
     */
    private CloudletToVmMappingSolution roundRobinSolution = null;

    /**
     * Indicates if each experiment will output execution logs or not.
     */
    private final boolean experimentVerbose = false;

    /**
     * Starts the execution of the experiments the number of times defines in
     * {@link #numberOfSimulationRuns}.
     *
     * @param args command line arguments
     */
    public static void main(String[] args) {
        /*
        Values used for CloudSim Plus Paper:
        NumberOfSimulationRuns: 1200
        ApplyAntitheticVariatesTechnique: true
        NumberOfBatches: 6
        BaseSeed: 1475098589732L
         */
        new DatacenterBrokerHeuristicRunner().setNumberOfSimulationRuns(1200)
                .setApplyAntitheticVariatesTechnique(true).setNumberOfBatches(6) //Comment this or set to 0 to disable the "Batch Means Method"
                .setBaseSeed(1475098589732L) //Comment this to use the current time as base seed
                .setVerbose(true).run();
    }

    DatacenterBrokerHeuristicRunner() {
        super();
        experimentCosts = new ArrayList<>();
        runtimeStats = new SummaryStatistics();
        vmPesArray = new int[0];
        cloudletPesArray = new int[0];
    }

    /**
     * Creates an array with the configuration of PEs for each Cloudlet to be
     * created in each experiment run. Every experiment will use the same
     * Cloudlets configurations.
     *
     * @return the created cloudlet PEs array
     */
    private int[] createCloudletPesArray() {
        int[] pesArray = new int[CLOUDLETS_TO_CREATE];
        int totalNumberOfPes = 0;
        NormalDistr random = new NormalDistr(getBaseSeed(), 2, 0.6);
        for (int i = 0; i < CLOUDLETS_TO_CREATE; i++) {
            pesArray[i] = (int) random.sample() + 1;
            totalNumberOfPes += pesArray[i];
        }

        return pesArray;
    }

    /**
     * Creates an array with the configuration of PEs for each VM to be created
     * in each experiment run. Every experiment will use the same VMs
     * configurations.
     *
     * @return the created VMs PEs array
     */
    private int[] createVmPesArray() {
        UniformDistr random = new UniformDistr(0, VM_PES_NUMBERS.length, getBaseSeed());
        int[] pesArray = new int[VMS_TO_CREATE];
        int totalNumberOfPes = 0;
        for (int i = 0; i < VMS_TO_CREATE; i++) {
            pesArray[i] = VM_PES_NUMBERS[(int) random.sample()];
            totalNumberOfPes += pesArray[i];
        }

        return pesArray;
    }

    /**
     * Adds the computed cost to map Cloudlets to a VM for the current
     * experiment to the list of mapping costs.
     *
     * @param cost the cost to add
     */
    public void addExperimentCost(double cost) {
        experimentCosts.add(cost);
    }

    /**
     * Adds the run time that the simulated annealing heuristic spent to compute
     * the mapping of Cloudlets to a VM for the current experiment to the list
     * of run times.
     *
     * @param runTime the run time to add
     */
    public void addSimulatedAnnealingRuntime(double runTime) {
        runtimeStats.addValue(runTime);
    }

    @Override
    protected DatacenterBrokerHeuristicExperiment createExperiment(int i) {
        ContinuousDistribution prng = createRandomGenAndAddSeedToList(i, 0, 1);
        DatacenterBrokerHeuristicExperiment exp = new DatacenterBrokerHeuristicExperiment(this, i)
                .setRandomGen(prng).setCloudletPesArray(cloudletPesArray).setVmPesArray(vmPesArray);

        exp.setVerbose(experimentVerbose).setAfterExperimentFinish(this::afterExperimentFinish);
        return exp;
    }

    @Override
    protected void setup() {
        experimentCosts = new ArrayList<>(getNumberOfSimulationRuns());
        vmPesArray = createVmPesArray();
        cloudletPesArray = createCloudletPesArray();
    }

    /**
     * Method automatically called after every experiment finishes running. It
     * performs some post-processing such as collection of data for statistic
     * analysis.
     *
     * @param experiment the finished experiment
     */
    private void afterExperimentFinish(DatacenterBrokerHeuristicExperiment experiment) {
        CloudletToVmMappingSolution solution = experiment.getHeuristic().getBestSolutionSoFar();
        addExperimentCost(solution.getCost());
        addSimulatedAnnealingRuntime(solution.getHeuristic().getSolveTime());
        createRoundRobinSolutionIfNotCreatedYet(experiment);
    }

    @Override
    protected Map<String, List<Double>> createMetricsMap() {
        Map<String, List<Double>> map = new HashMap<>();
        map.put("Experiments Cost", experimentCosts);
        return map;
    }

    @Override
    protected void printSimulationParameters() {
        System.out.printf("Executing %d experiments. Please wait ... It may take a while.\n",
                getNumberOfSimulationRuns());
        System.out.println("Experiments configurations:");
        System.out.printf("\tBase seed: %d | Number of VMs: %d | Number of Cloudlets: %d\n", getBaseSeed(),
                VMS_TO_CREATE, CLOUDLETS_TO_CREATE);
        System.out.printf("\tApply Antithetic Variates Technique: %b\n", isApplyAntitheticVariatesTechnique());
        if (isApplyBatchMeansMethod()) {
            System.out.println("\tApply Batch Means Method to reduce simulation results correlation: true");
            System.out.printf("\tNumber of Batches for Batch Means Method: %d", getNumberOfBatches());
            System.out.printf("\tBatch Size: %d\n", batchSizeCeil());
        }
        System.out.printf("\nSimulated Annealing Parameters\n");
        System.out.printf(
                "\tInitial Temperature: %.2f | Cold Temperature: %.4f | Cooling Rate: %.3f | Neighborhood searches by iteration: %d\n",
                DatacenterBrokerHeuristicExperiment.SA_INITIAL_TEMPERATURE,
                DatacenterBrokerHeuristicExperiment.SA_COLD_TEMPERATURE,
                DatacenterBrokerHeuristicExperiment.SA_COOLING_RATE,
                DatacenterBrokerHeuristicExperiment.SA_NUMBER_OF_NEIGHBORHOOD_SEARCHES);
    }

    @Override
    protected void printFinalResults(String metricName, SummaryStatistics stats) {
        System.out.printf("\n# %s for %d simulation runs\n", metricName, getNumberOfSimulationRuns());

        if (!simulationRunsAndNumberOfBatchesAreCompatible()) {
            System.out.println(
                    "\tBatch means method was not be applied because the number of simulation runs is not greater than the number of batches.");
        }
        System.out.printf("\tRound-robin solution used by DatacenterBrokerSimple - Cost: %.2f\n",
                roundRobinSolution.getCost());

        if (getNumberOfSimulationRuns() > 1) {
            System.out.printf("\tHeuristic solutions - Mean cost: %.2f Std. Dev.: %.2f\n", stats.getMean(),
                    stats.getStandardDeviation());
            showConfidenceInterval(stats);
            System.out.printf(
                    "\n\tThe mean cost of heuristic solutions represent %.2f%% of the Round-robin mapping used by the DatacenterBrokerSimple\n",
                    heuristicSolutionCostPercentageOfRoundRobinSolution(stats.getMean()));
            System.out.printf("Experiment execution mean time: %.2f seconds\n", runtimeStats.getMean());
        }
    }

    /**
     * Computes the percentage of the Round-robin solution cost that the
     * heuristic solution cost represents.
     *
     * @param heuristicSolutionCost the cost of the heuristic solution
     * @return the percentage of the Round-robin solution cost that the
     * heuristic solution represents
     */
    private double heuristicSolutionCostPercentageOfRoundRobinSolution(double heuristicSolutionCost) {
        return heuristicSolutionCost * 100.0 / roundRobinSolution.getCost();
    }

    private void showConfidenceInterval(SummaryStatistics stats) {
        // Calculate 95% confidence interval
        double intervalSize = computeConfidenceErrorMargin(stats, 0.95);
        double lower = stats.getMean() - intervalSize;
        double upper = stats.getMean() + intervalSize;
        System.out.printf("\tSolution cost mean 95%% Confidence Interval: %.2f  %.2f, that is [%.2f to %.2f]\n",
                stats.getMean(), intervalSize, lower, upper);
    }

    /**
     * Creates a Round-robin mapping between Cloudlets and Vm's from the
     * Cloudlets and Vm's of a given experiment, in the same way as the
     * {@link DatacenterBrokerSimple} does.
     *
     * @param exp the experiment to get the list of Cloudlets and Vm's
     */
    public void createRoundRobinSolutionIfNotCreatedYet(SimulationExperiment exp) {
        if (roundRobinSolution != null) {
            return;
        }

        roundRobinSolution = new CloudletToVmMappingSolution(Heuristic.NULL);
        int i = 0;
        for (Cloudlet c : exp.getCloudletList()) {
            //cyclically selects a Vm (as in a circular queue)
            roundRobinSolution.bindCloudletToVm(c, exp.getVmList().get(i));
            i = (i + 1) % exp.getVmList().size();
        }
    }

}