All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cloudsimplus.testbeds.Experiment Maven / Gradle / Ivy

Go to download

CloudSim Plus: A modern, highly extensible and easier-to-use Java 8 Framework for Modeling and Simulation of Cloud Computing Infrastructures and Services

There is a newer version: 8.0.0
Show newest version
/*
 * 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-2018 Universidade da Beira Interior (UBI, Portugal) and
 *     the Instituto Federal de Educação Ciência 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 .
 */
package org.cloudsimplus.testbeds;

import org.cloudbus.cloudsim.allocationpolicies.VmAllocationPolicy;
import org.cloudbus.cloudsim.allocationpolicies.VmAllocationPolicySimple;
import org.cloudbus.cloudsim.brokers.DatacenterBroker;
import org.cloudbus.cloudsim.cloudlets.Cloudlet;
import org.cloudbus.cloudsim.core.CloudSim;
import org.cloudbus.cloudsim.datacenters.Datacenter;
import org.cloudbus.cloudsim.datacenters.DatacenterSimple;
import org.cloudbus.cloudsim.hosts.Host;
import org.cloudbus.cloudsim.vms.Vm;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * A base class to implement simulation experiments
 * that can be executed in a repeatable way
 * by a {@link ExperimentRunner}.
 *
 * @author Manoel Campos da Silva Filho
 * @since CloudSim Plus 1.0
 */
public abstract class Experiment implements Runnable {
    private final ExperimentRunner runner;
    private final CloudSim simulation;
    private final List datacenterList;
    private final List brokerList;
    private final List vmList;
    private final List cloudletList;
    private final long seed;

    private int datacentersNumber;
    protected int hostsNumber;
    private int brokersNumber;

    private final int index;
    private boolean verbose;
    private int lastVmId;
    private int lastCloudletId;

    private Consumer afterExperimentFinish;
    private Consumer afterExperimentBuild;

    /**@see #setVmsByBrokerFunction(Function) */
    private Function vmsByBrokerFunction;

    /**@see #setVmAllocationPolicySupplier(Supplier)  */
    private Supplier vmAllocationPolicySupplier;

    /**
     * Creates a simulation experiment that is not linked to a runner,
     * to enable it to execute just one run.
     *
     */
    public Experiment(final long seed) {
        this(0, null, seed);
    }

    /**
     * Instantiates a simulation experiment with 1 Datacenter by default.
     *
     * @param index the index that identifies the current experiment run.
     * @param runner The {@link ExperimentRunner} that is in charge of executing
     * this experiment a defined number of times and to collect data for
     * statistical analysis.
     * @see #setDatacentersNumber(int)
     */
    public Experiment(final int index, final ExperimentRunner runner) {
        //the seed will be generate from the Runner base seed
        this(index, runner, -1);
    }

    /**
     * Instantiates a simulation experiment
     * that will create 1 broker and 1 Datacenter by default.
     *
     * @param index the index that identifies the current experiment run.
     * @param runner The {@link ExperimentRunner} to execute the experiment.
     *               If omitted, it means the experiment is independent and may be run just once.
     *               If you don't provide a runner, you must provide a seed
     * @param seed the seed to be set. If a runner is given, this value is ignored
     *             and the seed is generated from the runner base seed.
     *             If you don't provide a seed, you must provide a runner.
     * @see #setBrokersNumber(int)
     * @see #setDatacentersNumber(int)
     */
    protected Experiment(final int index, final ExperimentRunner runner, final long seed) {
        if(seed == -1){
            Objects.requireNonNull(runner);
        }
        this.brokersNumber = 1;
        this.datacentersNumber = 1;
        this.verbose = false;
        this.simulation = new CloudSim();
        this.vmList = new ArrayList<>();
        this.index = index;
        this.datacenterList = new ArrayList<>();
        this.brokerList = new ArrayList<>();
        this.cloudletList = new ArrayList<>();
        this.runner = runner;

        //Defines an empty Consumer to avoid NullPointerException if an actual one is not set
        afterExperimentFinish = exp -> {};
        afterExperimentBuild = exp -> {};

        this.seed = validateSeed(seed);
    }

    private long validateSeed(long seed) {
        if(runner == null){
            return seed;
        }

        if (runner.isToReuseSeedFromFirstHalfOfExperiments(index)) {
            final int previousExperiment = index - runner.halfSimulationRuns();
            seed = runner.getSeed(previousExperiment);
        } else {
            seed = runner.getBaseSeed() + index;
        }

        runner.addSeed(seed);
        return seed;
    }

    public final List getCloudletList() {
        return Collections.unmodifiableList(cloudletList);
    }

    public List getVmList() {
        return Collections.unmodifiableList(vmList);
    }

    /**
     * Defines if simulation results of the experiment have to be output or not.
     *
     * @param verbose true if the results have to be output, false otherwise
     * @return
     */
    public Experiment setVerbose(final boolean verbose) {
        this.verbose = verbose;
        return this;
    }

    /**
     * The index that identifies the current experiment run.
     * @return
     */
    public int getIndex() {
        return index;
    }

    /**
     * Indicates if simulation results of the experiment don't have to be
     * output.
     * @return
     */
    public boolean isNotVerbose() {
        return !verbose;
    }

    /**
     * Indicates if simulation results of the experiment have to be output.
     * @return
     */
    public boolean isVerbose() {
        return verbose;
    }

    /**
     * Builds the simulation scenario and starts execution.
     *
     * @throws RuntimeException
     */
    @Override
    public final void run() {
        if(vmsByBrokerFunction == null){
            throw new NullPointerException("You need to set the function that indicates the number of VMs to create for each broker.");
        }

        build();
        simulation.start();
        afterExperimentFinish(this);
        printResultsInternal();
    }

    /**
     * Checks if {@link #isVerbose()} in order to call {@link #printResults()}
     * to print the experiment results.
     *
     * @see #printResults()
     */
    private void printResultsInternal() {
        if (isVerbose()) {
            printResults();
        }
    }

    /**
     * Prints the results for the experiment.
     *
     * The method has to be implemented by subclasses in order to output the
     * experiment results.
     *
     * @see #printResultsInternal()
     */
    public abstract void printResults();

    /**
     * Creates the simulation scenario to run the experiment.
     */
    protected final void build() {
        createDatacenters();
        createBrokers();

        brokerList.stream().sorted().forEach(b -> {
                createAndSubmitVmsInternal(b);
                createAndSubmitCloudletsInternal(b);
        });

        afterExperimentBuild(this);
    }

    private void createDatacenters() {
        if(datacentersNumber <= 0){
            throw new IllegalStateException("The number of Datacenters to create was not set");
        }

        for (int i = 0; i < datacentersNumber; i++) {
            datacenterList.add(createDatacenter(i));
        }
    }

    /**
     * Creates a datacenter using a {@link VmAllocationPolicy}
     * supplied by the {@link #vmAllocationPolicySupplier}.
     * @param index index of the datatacenter being created, from the {@link #datacentersNumber}.
     * @return
     * @see #setVmAllocationPolicySupplier(Supplier)
     */
    protected Datacenter createDatacenter(final int index) {
        return new DatacenterSimple(simulation, createHosts(), newVmAllocationPolicy());
    }

    /**
     * Creates a list of brokers.
     * This is the entry-point for broker creation.
     */
    protected void createBrokers() {
        if(brokersNumber <= 0){
            throw new IllegalStateException("The number of brokers to create was not set");
        }

        for (int i = 0; i < brokersNumber; i++) {
            createBrokerAndAddToList();
        }
    }

    /**
     * Creates a DatacenterBroker.
     *
     * @return the created DatacenterBroker
     */
    protected abstract DatacenterBroker createBroker();

    /**
     * Creates a list of Cloudlets to be used by the experiment.
     *
     * @return the list of created cloudlets
     * @param broker the broker to create the Cloudlets to
     */
    protected abstract List createCloudlets(DatacenterBroker broker);

    protected abstract Cloudlet createCloudlet(DatacenterBroker broker);

    /**
     * Creates the Vms to be used by the experiment.
     *
     * @return the List of created VMs
     * @param broker
     */
    protected List createVms(final DatacenterBroker broker) {
        final int numVms = vmsByBrokerFunction.apply(broker);
        final List newList = new ArrayList<>(numVms);
        for (int id = vmList.size(); id < vmList.size() + numVms; id++) {
            Vm vm = createVm(broker, nextVmId());
            newList.add(vm);
        }

        return newList;
    }

    protected abstract Vm createVm(DatacenterBroker broker, int id);

    protected final int nextVmId(){
        return ++lastVmId;
    }

    protected final int nextCloudletId(){
        return ++lastCloudletId;
    }
    /**
     * Creates a DatacenterBroker and adds it to the
     * {@link #getBrokerList() DatacenterBroker list}.
     *
     * @return the created DatacenterBroker.
     * @see #createBrokers()
     */
    private DatacenterBroker createBrokerAndAddToList() {
        DatacenterBroker broker = createBroker();
        brokerList.add(broker);
        return broker;
    }

    /**
     * Creates all the Cloudlets required by the experiment and submits them to
     * a Broker. This the entry-point for Cloudlets creation.
     *
     * @param broker broker to submit Cloudlets to
     */
    protected void createAndSubmitCloudletsInternal(final DatacenterBroker broker) {
        final List list = createCloudlets(broker);
        cloudletList.addAll(list);
        broker.submitCloudletList(list);
    }

    /**
     * Creates all the VMs required by the experiment and submits them to a
     * Broker. This is the entry-point to start creating VMs.
     *
     * @param broker broker to submit VMs to
     */
    private void createAndSubmitVmsInternal(final DatacenterBroker broker) {
        final List list = createVms(broker);
        vmList.addAll(list);
        broker.submitVmList(list);
    }

    protected final List createHosts() {
        if(hostsNumber <= 0){
            throw new IllegalStateException("The number of hosts to create was not set");
        }

        final List list = new ArrayList<>(hostsNumber);
        for (int i = 0; i < hostsNumber; i++) {
            list.add(createHost(i));
        }

        return list;
    }

    protected abstract Host createHost(int id);

    /**
     * Gets the object that is in charge to run the experiment.
     *
     * @return
     */
    public ExperimentRunner getRunner() {
        return runner;
    }

    /**
     * Gets the list of created DatacenterBrokers.
     *
     * @return
     */
    public List getBrokerList() {
        return brokerList;
    }

    /**
     * Sets a {@link Consumer} that will be called after the simulation scenario is built,
     * which is before starting the simulation.
     *
     * 

Setting a Consumer object is optional.

* @param the class of the experiment * @param afterExperimentBuild the afterExperimentBuild to set * @return */ public Experiment setAfterExperimentBuild(final Consumer afterExperimentBuild) { this.afterExperimentBuild = Objects.requireNonNull(afterExperimentBuild); return this; } private void afterExperimentBuild(final T experiment) { ((Consumer)this.afterExperimentBuild).accept(experiment); } /** * Sets a {@link Consumer} object that will receive the experiment instance * after the experiment finishes executing and performs some post-processing * tasks. These tasks are defined by the developer using the current class * and can include collecting data for statistical analysis. * *

Setting a Consumer object is optional.

* * @param the class of the experiment * @param afterExperimentFinishConsumer a {@link Consumer} instance to set. * @return */ public Experiment setAfterExperimentFinish(final Consumer afterExperimentFinishConsumer) { this.afterExperimentFinish = Objects.requireNonNull(afterExperimentFinishConsumer); return this; } private void afterExperimentFinish(final T experiment) { ((Consumer) this.afterExperimentFinish).accept(experiment); } public final CloudSim getSimulation() { return simulation; } /** * Gets the number of brokers to create. * @return */ public int getBrokersNumber() { return brokersNumber; } /** * Sets the number of brokers to create. * @param brokersNumber the value to set */ public Experiment setBrokersNumber(final int brokersNumber) { if(brokersNumber <= 0){ throw new IllegalArgumentException("The number of brokers must be greater than 0"); } this.brokersNumber = brokersNumber; return this; } public List getDatacenterList() { return datacenterList; } public long getSeed(){ return seed; } @Override public String toString() { return String.format("Experiment %d", index); } /** * Sets a {@link Function} that receives a {@link DatacenterBroker} and returns the * number of Vms to create for that broker. * If you want all brokers to have the same amount of VMs, * you can give a lambda expression such as {@code broker -> NUMBER_OF_VMS_TO_CREATE}. * @param vmsByBrokerFunction the {@link Function} to set */ public final void setVmsByBrokerFunction(final Function vmsByBrokerFunction) { this.vmsByBrokerFunction = Objects.requireNonNull(vmsByBrokerFunction); } /** * Gets a {@link Function} that receives a {@link DatacenterBroker} and returns the * number of Vms to create for that broker. */ protected Function getVmsByBrokerFunction() { return vmsByBrokerFunction; } protected final void setHostsNumber(final int hostsNumber) { if(hostsNumber <= 0){ throw new IllegalArgumentException("Number of hosts must be greater than zero."); } this.hostsNumber = hostsNumber; } public int getDatacentersNumber() { return datacentersNumber; } public void setDatacentersNumber(final int datacentersNumber) { this.datacentersNumber = datacentersNumber; } public void setVmAllocationPolicySupplier(final Supplier vmAllocationPolicySupplier) { this.vmAllocationPolicySupplier = Objects.requireNonNull(vmAllocationPolicySupplier); } private VmAllocationPolicy newVmAllocationPolicy() { return vmAllocationPolicySupplier == null ? new VmAllocationPolicySimple() : vmAllocationPolicySupplier.get(); } /** * Prints a message only if {@link #isVerbose()}. * @param msg the message to print */ public void print(final String msg){ if(verbose){ System.out.print(msg); } } /** * Prints a formatted message only if {@link #isVerbose()}. * @param format the message format * @param args the values to print */ public void print(final String format, final Object ...args){ if(verbose){ System.out.printf(format, args); } } /** * Prints a line break only if {@link #isVerbose()}. */ public void println(){ print(""); } /** * Prints a message and a line break only if {@link #isVerbose()}. * @param msg the message to print */ public void println(final String msg){ if(verbose){ System.out.println(msg); } } /** * Prints a formatted message and a line break only if {@link #isVerbose()}. * @param format the message format * @param args the values to print */ public void println(final String format, final Object ...args){ if(verbose){ System.out.printf(format + System.lineSeparator(), args); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy