From d5768cdbad4e6295192e58441d6f656f22592683 Mon Sep 17 00:00:00 2001 From: Manoel Campos Date: Wed, 9 Nov 2016 16:52:18 +0000 Subject: [PATCH] - Finished the first version of the CloudletSchedulerCompletelyFair, the most used scheduler in recent versions of Linux Kernel. - Included new testbeds in the cloudsim-plus-testbeds module to compare the new scheduler with the CloudletSchedulerTimeShared - Included the LinuxCompletelyFairSchedulerExample example for the new scheduler in the cloudsim-plus-examples module --- .../LinuxCompletelyFairSchedulerExample.java | 79 ++---- .../testbeds/ExperimentRunner.java | 78 ++++-- .../testbeds/SimulationExperiment.java | 253 ++++++++---------- .../DynamicCloudletsArrivalExperiment.java | 28 +- .../DynamicCloudletsArrivalRunner.java | 9 +- .../DatacenterBrokerHeuristicExperiment.java | 161 ++++++++++- .../DatacenterBrokerHeuristicRunner.java | 64 +++-- .../CloudletSchedulerExperiment.java | 174 ++++++++++++ .../CloudletSchedulerRunner.java | 112 ++++++++ ...CloudletSchedulerTimeSharedExperiment.java | 44 +++ .../CloudletSchedulerTimeSharedRunner.java | 33 +++ .../CompletelyFairSchedulerExperiment.java | 48 ++++ .../CompletelyFairSchedulerRunner.java | 38 +++ .../testbeds/linuxscheduler/package-info.java | 15 ++ .../java/org/cloudbus/cloudsim/Cloudlet.java | 9 +- .../cloudsim/CloudletExecutionInfo.java | 4 +- .../brokers/DatacenterBrokerHeuristic.java | 4 +- .../cloudsim/distributions/UniformDistr.java | 2 +- .../schedulers/CloudletScheduler.java | 21 +- .../schedulers/CloudletSchedulerAbstract.java | 51 ++-- .../CloudletSchedulerCompletelyFair.java | 250 ++++++++--------- .../CloudletSchedulerSpaceShared.java | 14 +- .../CloudletSchedulerTimeShared.java | 62 ++--- .../CloudletsTableBuilderHelper.java | 16 +- .../PriorityCloudletsTableBuilderHelper.java | 28 ++ .../CloudletSchedulerSpaceSharedTest.java | 5 +- .../CloudletSchedulerTimeSharedTest.java | 8 +- 27 files changed, 1113 insertions(+), 497 deletions(-) rename cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/{ => dynamiccloudlets}/DynamicCloudletsArrivalExperiment.java (71%) rename cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/{ => dynamiccloudlets}/DynamicCloudletsArrivalRunner.java (61%) create mode 100644 cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerExperiment.java create mode 100644 cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerRunner.java create mode 100644 cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedExperiment.java create mode 100644 cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedRunner.java create mode 100644 cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerExperiment.java create mode 100644 cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerRunner.java create mode 100644 cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/package-info.java create mode 100644 cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/PriorityCloudletsTableBuilderHelper.java diff --git a/cloudsim-plus-examples/src/main/java/org/cloudsimplus/examples/LinuxCompletelyFairSchedulerExample.java b/cloudsim-plus-examples/src/main/java/org/cloudsimplus/examples/LinuxCompletelyFairSchedulerExample.java index c72e7f71e..77660a5d2 100644 --- a/cloudsim-plus-examples/src/main/java/org/cloudsimplus/examples/LinuxCompletelyFairSchedulerExample.java +++ b/cloudsim-plus-examples/src/main/java/org/cloudsimplus/examples/LinuxCompletelyFairSchedulerExample.java @@ -1,6 +1,5 @@ package org.cloudsimplus.examples; -import org.cloudsimplus.util.tablebuilder.CloudletsTableBuilderHelper; import java.util.ArrayList; import java.util.Calendar; import java.util.LinkedList; @@ -32,14 +31,15 @@ import org.cloudbus.cloudsim.provisioners.ResourceProvisionerSimple; import org.cloudbus.cloudsim.resources.Ram; import org.cloudbus.cloudsim.schedulers.CloudletSchedulerCompletelyFair; +import org.cloudsimplus.util.tablebuilder.PriorityCloudletsTableBuilderHelper; /** * An example that uses an implementation of the {@link CloudletSchedulerCompletelyFair Completely Fair Scheduler} * used in the Linux Kernel for scheduling of Cloudlets execution inside a Vm. - * + * * @author Manoel Campos da Silva Filho * @see Completely Fair Scheduler (CFS) - * + * */ public class LinuxCompletelyFairSchedulerExample { private static final int HOSTS_NUMBER = 1; @@ -51,21 +51,21 @@ public class LinuxCompletelyFairSchedulerExample { private static final int CLOUDLETS_NUMBER = HOST_PES*2; private static final int CLOUDLET_PES = 1; private static final int CLOUDLET_LEN = 10000; //in MI - + /** * Virtual Machine Monitor name. */ - private static final String VMM = "Xen"; + private static final String VMM = "Xen"; private List cloudletList; private List vmList; - + private int numberOfCreatedCloudlets = 0; private int numberOfCreatedVms = 0; private int numberOfCreatedHosts = 0; /** * Starts the simulation. - * @param args + * @param args */ public static void main(String[] args) { new LinuxCompletelyFairSchedulerExample(); @@ -78,9 +78,9 @@ public LinuxCompletelyFairSchedulerExample() { Log.printFormattedLine("Starting %s...", getClass().getSimpleName()); try { //Number of cloud customers - int numberOfCloudUsers = 1; + int numberOfCloudUsers = 1; boolean traceEvents = false; - + CloudSim.init(numberOfCloudUsers, Calendar.getInstance(), traceEvents); Datacenter datacenter0 = createDatacenter("Datacenter0"); @@ -90,12 +90,12 @@ public LinuxCompletelyFairSchedulerExample() { createAndSubmitVms(broker0); createAndSubmitCloudlets(broker0); for(int i = 0; i < CLOUDLETS_NUMBER/2; i++){ - cloudletList.get(i).setPriority(10); + cloudletList.get(i).setPriority(4); } CloudSim.startSimulation(); CloudSim.stopSimulation(); - + List finishedCloudlets = broker0.getCloudletsFinishedList(); new PriorityCloudletsTableBuilderHelper(finishedCloudlets).build(); Log.printFormattedLine("%s finished!", getClass().getSimpleName()); @@ -117,13 +117,13 @@ private void createAndSubmitVms(DatacenterBroker broker0) { for(int i = 0; i < VMS_NUMBER; i++){ this.vmList.add(createVm(broker0)); } - broker0.submitVmList(vmList); + broker0.submitVmList(vmList); } private DatacenterSimple createDatacenter(String name) { List hostList = new ArrayList<>(HOSTS_NUMBER); for(int i = 0; i < HOSTS_NUMBER; i++){ - hostList.add(createHost()); + hostList.add(createHost()); } //Defines the characteristics of the data center @@ -140,17 +140,17 @@ private DatacenterSimple createDatacenter(String name) { arch, os, VMM, hostList, time_zone, cost, costPerMem, costPerStorage, costPerBw); - return new DatacenterSimple(name, characteristics, + return new DatacenterSimple(name, characteristics, new VmAllocationPolicySimple(hostList), storageList, 0); - } + } private Host createHost() { final int ram = 2048; // host memory (MB) final long storage = 1000000; // host storage final long bw = 10000; - + List cpuCoresList = createHostPesList(HOST_MIPS); - + return new HostSimple(numberOfCreatedHosts++, new ResourceProvisionerSimple<>(new Ram(ram)), new ResourceProvisionerSimple<>(new Bandwidth(bw)), @@ -163,59 +163,36 @@ private List createHostPesList(double mips) { for(int i = 0; i < HOST_PES; i++){ cpuCoresList.add(new PeSimple(i, new PeProvisionerSimple(mips))); } - + return cpuCoresList; } private Vm createVm(DatacenterBroker broker) { final long storage = 10000; // vm image size (MB) final int ram = 512; // vm memory (MB) - final long bw = 1000; // vm bandwidth - - return new VmSimple(numberOfCreatedVms++, - broker.getId(), VM_MIPS, VM_PES, ram, bw, storage, - VMM, new CloudletSchedulerCompletelyFair()); + final long bw = 1000; // vm bandwidth + + return new VmSimple(numberOfCreatedVms++, + broker.getId(), VM_MIPS, VM_PES, ram, bw, storage, VMM, + new CloudletSchedulerCompletelyFair()); } private Cloudlet createCloudlet(DatacenterBroker broker) { final long fileSize = 300; //Size (in bytes) before execution final long outputSize = 300; //Size (in bytes) after execution - + //Defines how CPU, RAM and Bandwidth resources are used //Sets the same utilization model for all these resources. UtilizationModel utilization = new UtilizationModelFull(); - + Cloudlet cloudlet = new CloudletSimple( - numberOfCreatedCloudlets++, CLOUDLET_LEN, CLOUDLET_PES, - fileSize, outputSize, + numberOfCreatedCloudlets++, CLOUDLET_LEN, CLOUDLET_PES, + fileSize, outputSize, utilization, utilization, utilization); cloudlet.setUserId(broker.getId()); - + return cloudlet; } } -/** - * A helper class to print cloudlets results as a table that includes - * the Cloudlet priority as a table field. - * - * @author Manoel Campos da Silva Filho - */ -class PriorityCloudletsTableBuilderHelper extends CloudletsTableBuilderHelper { - public PriorityCloudletsTableBuilderHelper(List list) { - super(list); - } - - @Override - protected void createTableColumns() { - super.createTableColumns(); - getPrinter().addColumn("Priority"); - } - - @Override - protected void addDataToRow(Cloudlet cloudlet, List row) { - super.addDataToRow(cloudlet, row); - row.add(cloudlet.getPriority()); - } -} diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/ExperimentRunner.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/ExperimentRunner.java index 60706caa6..2efb804f4 100644 --- a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/ExperimentRunner.java +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/ExperimentRunner.java @@ -11,7 +11,9 @@ /** * A base class to run a given experiment a defined number of times - * and collect statistics about the execution. + * and collect statistics about the execution. The runner represents a testbed + * compounded of a set of experiments that it runs. + * * @param the class of experiment the runner will execute * @author Manoel Campos da Silva Filho */ @@ -324,33 +326,40 @@ public long getBaseSeed() { /** * Gets the seeds used to run each experiment. * - * @see #createRandomGen(int) + * @see #createRandomGenAndAddSeedToList(int, double, double) */ public List getSeeds() { return seeds; } /** - * Creates a pseudo random number generator (PRNG) for a experiment run. - * If it is to apply the {@link #isApplyAntitheticVariatesTechnique() "Antithetic Variates Technique"} to reduce + * Creates a pseudo random number generator (PRNG) for a experiment run that generates + * uniform values between [min and max[. Adds the PRNG seed to the {@link #getSeeds()} list. + * If it is to apply the {@link #isApplyAntitheticVariatesTechnique() "Antithetic Variates Technique"} to reduce * results variance, the second half of experiments will used * the seeds from the first half. * + * @param minValue the minimum value that generator will return (inclusive) + * @param maxValue the minimum value that generator will return (exclusive) * @return the created PRNG * * @see UniformDistr#isApplyAntitheticVariatesTechnique() */ - protected UniformDistr createRandomGen(int experimentIndex) { - if (isApplyAntitheticVariatesTechnique() && experimentIndex >= halfSimulationRuns()) { + protected UniformDistr createRandomGenAndAddSeedToList(int experimentIndex, double minValue, double maxValue) { + UniformDistr prng; + if (isApplyAntitheticVariatesTechnique() && + numberOfSimulationRuns > 1 && experimentIndex >= halfSimulationRuns()) { int previousExperiment = experimentIndex - halfSimulationRuns(); - return new UniformDistr(0, 1, seeds.get(previousExperiment)) + prng = new UniformDistr(minValue, maxValue, seeds.get(previousExperiment)) .setApplyAntitheticVariatesTechnique(true); } final long experimentSeed = getBaseSeed() + experimentIndex + 1; - return new UniformDistr(0, 1, experimentSeed); - } + prng = new UniformDistr(minValue, maxValue, experimentSeed); + addSeed(prng.getSeed()); + return prng; + } /** * Adds a seed to the list of seeds used for each experiment. @@ -390,19 +399,23 @@ public void run() { setupInternal(); printSimulationParameters(); - Log.disable(); - experimentsStartTime = System.currentTimeMillis(); - for(int i = 0; i < getNumberOfSimulationRuns(); i++){ - if(isVerbose()) { - System.out.print(((i+1) % 100 == 0 ? String.format(". Run #%d\n", i+1) : ".")); - } - createExperiment(i).run(); - } - System.out.println(); - experimentsFinishTime = (System.currentTimeMillis() - experimentsStartTime)/1000; - - printResults(computeStatistics()); + Log.disable(); + try { + experimentsStartTime = System.currentTimeMillis(); + for(int i = 0; i < getNumberOfSimulationRuns(); i++){ + if(isVerbose()) { + System.out.print(((i+1) % 100 == 0 ? String.format(". Run #%d\n", i+1) : ".")); + } + createExperiment(i).run(); + } + System.out.println(); + experimentsFinishTime = (System.currentTimeMillis() - experimentsStartTime)/1000; + } finally { + Log.enable(); + } + + printFinalResults(computeFinalStatistics()); } /** @@ -431,7 +444,7 @@ public void run() { * if the "Antithetic Variates Technique" is to be applied, * otherwise return the same given samples list. * - * @see #createRandomGen(int) + * @see #createRandomGenAndAddSeedToList(int, double, double) */ protected List computeAntitheticMeans(List samples) { if(!isApplyAntitheticVariatesTechnique()) @@ -451,15 +464,22 @@ protected List computeAntitheticMeans(List samples) { } protected abstract void printSimulationParameters(); - protected abstract SummaryStatistics computeStatistics(); + + /** + * Computes the final statistics for all experiment runs. + * + * @return + */ + protected abstract SummaryStatistics computeFinalStatistics(); /** * Prints final simulation results such as means, standard deviations * and confidence intervals. * - * @param stats the {@link SummaryStatistics} object to compute the statistics + * @param stats the {@link SummaryStatistics} containing means of each experiment run + * that will be used to computed an overall mean and other statistics */ - protected abstract void printResults(SummaryStatistics stats); + protected abstract void printFinalResults(SummaryStatistics stats); public ExperimentRunner setBaseSeed(long baseSeed) { this.baseSeed = baseSeed; @@ -468,11 +488,19 @@ public ExperimentRunner setBaseSeed(long baseSeed) { /** * Indicates if the runner will output execution logs or not. + * This doesn't affect the verbosity of individual experiments executed. + * Each {@link SimulationExperiment} has its own verbose attribute. */ public boolean isVerbose() { return verbose; } + /** + * Defines if the runner will output execution logs or not. + * This doesn't affect the verbosity of individual experiments executed. + * Each {@link SimulationExperiment} has its own verbose attribute. + * @param verbose true if the results have to be output, falser otherwise + */ public ExperimentRunner setVerbose(boolean verbose) { this.verbose = verbose; return this; diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/SimulationExperiment.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/SimulationExperiment.java index 88b8922a6..073c0ec6e 100644 --- a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/SimulationExperiment.java +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/SimulationExperiment.java @@ -11,13 +11,13 @@ import org.cloudbus.cloudsim.schedulers.VmSchedulerTimeShared; import org.cloudbus.cloudsim.utilizationmodels.UtilizationModel; import org.cloudbus.cloudsim.utilizationmodels.UtilizationModelFull; -import org.cloudsimplus.testbeds.heuristics.DatacenterBrokerHeuristicRunner; import java.util.ArrayList; import java.util.Calendar; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; /** * A base class to implement simulation experiments. @@ -25,9 +25,11 @@ * @author Manoel Campos da Silva Filho */ public abstract class SimulationExperiment implements Runnable { - public static final String VMM = "Xen"; - protected final DatacenterBrokerHeuristicRunner runner; + public static final String VMM = "Xen"; + protected final ExperimentRunner runner; private final List cloudletList; + private List vmList; + private List hostList; /** * @see #getIndex() */ @@ -38,18 +40,12 @@ public abstract class SimulationExperiment implements Runnable { */ private Consumer afterExperimentFinish; - private List vmList; - private int numberOfCreatedCloudlets = 0; - private int numberOfCreatedVms = 0; private int numberOfCreatedHosts = 0; + private int numberOfCreatedCloudlets = 0; + private int numberOfCreatedVms = 0; private boolean verbose; - /** - * @see #getHostsToCreate() - */ - private int hostsToCreate; - - /** + /** * Creates a simulation experiment. * * @param index the index that identifies the current experiment run. @@ -57,14 +53,17 @@ public abstract class SimulationExperiment implements Runnable { * of executing this experiment a defined number of times and to collect * data for statistical analysis. */ - public SimulationExperiment(int index, DatacenterBrokerHeuristicRunner runner) { + public SimulationExperiment(int index, ExperimentRunner runner) { this.verbose = false; this.vmList = new ArrayList<>(); this.index = index; this.cloudletList = new ArrayList<>(); this.brokerList = new ArrayList<>(); + this.hostList = new ArrayList<>(); this.runner = runner; - afterExperimentFinish = exp->{}; + + //Defines an empty Consumer to avoid NullPointerException if an actual one is not set + afterExperimentFinish = exp -> {}; } public List getCloudletList() { @@ -78,33 +77,14 @@ public List getVmList() { protected void setVmList(List vmList) { this.vmList = vmList; } - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - /** - * @return the number of hosts to create - */ - public int getHostsToCreate() { - return hostsToCreate; - } - public final void setHostsToCreate(int hostsToCreate) { - this.hostsToCreate = hostsToCreate; - } - - /** - * Number of cloudlets created so far. - */ - public int getNumberOfCreatedCloudlets() { - return numberOfCreatedCloudlets; - } - - /** - * Number of VMs created so far. - */ - public int getNumberOfCreatedVms() { - return numberOfCreatedVms; + /** + * Defines if simulation results of the experiment have to be output or not. + * @param verbose true if the results have to be output, falser otherwise + */ + public SimulationExperiment setVerbose(boolean verbose) { + this.verbose = verbose; + return this; } /** @@ -122,7 +102,7 @@ public int getIndex() { } /** - * Indicates if simulation results have to be output or not. + * Indicates if simulation results of the experiment have to be output or not. */ public boolean isVerbose() { return verbose; @@ -133,46 +113,30 @@ public boolean isVerbose() { */ private List brokerList; - protected Host createHost() { - int mips = 1000; // capacity of each CPU core (in Million Instructions per Second) - int ram = 2048; // host memory (MB) - long storage = 1000000; // host storage - long bw = 10000; - List cpuCoresList = new ArrayList<>(); - /*Creates the Host's CPU cores and defines the provisioner - used to allocate each core for requesting VMs.*/ - for (int i = 0; i < 8; i++) { - cpuCoresList.add(new PeSimple(i, new PeProvisionerSimple(mips))); - } - - return new HostSimple(numberOfCreatedHosts++, - new ResourceProvisionerSimple<>(new Ram(ram)), - new ResourceProvisionerSimple<>(new Bandwidth(bw)), storage, cpuCoresList, - new VmSchedulerTimeShared(cpuCoresList)); - } - - protected Vm createVm(DatacenterBroker broker, int pesNumber) { - double mips = 1000; - long storage = 10000; // vm image size (MB) - int ram = 512; // vm memory (MB) - long bw = 1000; // vm bandwidth - return new VmSimple(numberOfCreatedVms++, broker.getId(), mips, - pesNumber, ram, bw, storage, VMM, - new CloudletSchedulerTimeShared()); + /** + * Adds a Vm created by a {@link Supplier} function to the list of created Vms. + * + * @param vmSupplier a {@link Supplier} function that is able to create a Vm + * @return the created Vm + */ + protected Vm addNewVmToList(Supplier vmSupplier) { + Vm vm = vmSupplier.get(); + getVmList().add(vm); + numberOfCreatedVms++; + return vm; } - protected Cloudlet createCloudlet(DatacenterBroker broker, int numberOfPes) { - long length = 400000; //in Million Structions (MI) - long fileSize = 300; //Size (in bytes) before execution - long outputSize = 300; //Size (in bytes) after execution - //Defines how CPU, RAM and Bandwidth resources are used - //Sets the same utilization model for all these resources. - UtilizationModel utilization = new UtilizationModelFull(); - Cloudlet cloudlet = new CloudletSimple(numberOfCreatedCloudlets++, - length, numberOfPes, fileSize, outputSize, - utilization, utilization, utilization); - cloudlet.setUserId(broker.getId()); - return cloudlet; + /** + * Adds a Cloudlet created by a {@link Supplier} function to the list of created Cloudlets. + * + * @param cloudletSupplier a {@link Supplier} function that is able to create a Cloudlet + * @return the created Cloudlet + */ + protected Cloudlet addNewCloudletToList(Supplier cloudletSupplier) { + Cloudlet cloudlet = cloudletSupplier.get(); + getCloudletList().add(cloudlet); + numberOfCreatedCloudlets++; + return cloudlet; } /** @@ -217,15 +181,18 @@ private void printResultsInternal(){ */ public abstract void printResults(); - private void buildScenario() { + /** + * Creates the simulation scenario to run the experiment. + */ + protected void buildScenario() { int numberOfCloudUsers = 1; boolean traceEvents = false; CloudSim.init(numberOfCloudUsers, Calendar.getInstance(), traceEvents); Datacenter datacenter0 = createDatacenter("Datacenter0"); DatacenterBroker broker0 = createBrokerAndAddToList(); - createAndSubmitVms(broker0); - createAndSubmitCloudlets(broker0); + createAndSubmitVmsInternal(broker0); + createAndSubmitCloudletsInternal(broker0); } /** @@ -234,6 +201,18 @@ private void buildScenario() { */ protected abstract DatacenterBroker createBroker(); + /** + * Creates the Cloudlets to be used by the experiment. + * @param broker broker that the Cloudlets belong to + */ + protected abstract void createCloudlets(DatacenterBroker broker); + + /** + * Creates the Vms to be used by the experiment. + * @param broker broker that the Vms belong to + */ + protected abstract void createVms(DatacenterBroker broker); + /** * Creates a DatacenterBroker and adds it to the {@link #getBrokerList() DatacenterBroker list}. * @return the created DatacenterBroker. @@ -244,36 +223,26 @@ private DatacenterBroker createBrokerAndAddToList(){ return broker; } - /** - * @see #setVmPesArray(int[]) - */ - private int vmPesArray[]; - - /** - * @see #setCloudletPesArray(int[]) - */ - private int cloudletPesArray[]; - - protected void createAndSubmitCloudlets(DatacenterBroker broker0) { - for (int pes: cloudletPesArray) { - getCloudletList().add(createCloudlet(broker0, pes)); - } - broker0.submitCloudletList(getCloudletList()); - } - - protected void createAndSubmitVms(DatacenterBroker broker0) { - setVmList(new ArrayList<>(vmPesArray.length)); - for (int pes : vmPesArray) { - getVmList().add(createVm(broker0, pes)); - } - broker0.submitVmList(getVmList()); - } - - protected DatacenterSimple createDatacenter(String name) { - List hostList = new ArrayList<>(); - for (int i = 0; i < getHostsToCreate(); i++) { - hostList.add(createHost()); - } + /** + * Creates all the Cloudlets required by the experiment and submits them to a Broker. + * @param broker broker to submit Cloudlets to + */ + protected void createAndSubmitCloudletsInternal(DatacenterBroker broker) { + createCloudlets(broker); + broker.submitCloudletList(getCloudletList()); + } + + /** + * Creates all the VMs required by the experiment and submits them to a Broker. + * @param broker broker to submit VMs to + */ + private void createAndSubmitVmsInternal(DatacenterBroker broker){ + createVms(broker); + broker.submitVmList(getVmList()); + } + + private DatacenterSimple createDatacenter(String name) { + createHosts(); //Defines the characteristics of the data center String arch = "x86"; // system architecture of datacenter hosts String os = "Linux"; // operating system of datacenter hosts @@ -290,32 +259,33 @@ protected DatacenterSimple createDatacenter(String name) { new VmAllocationPolicySimple(hostList), storageList, 0); } - /** - * Sets the array with Number of PEs for each VM to create. - * The length of the array defines the number of VMs to create. - * @param vmPesArray VMs PEs array to set - */ - public SimulationExperiment setVmPesArray(int vmPesArray[]) { - this.vmPesArray = vmPesArray; - return this; - } - - /** - * Sets the array with Number of PEs for each Cloudlet to create. - * The length of the array defines the number of Cloudlets to create. - * @param cloudletPesArray Cloudlets PEs array to set - */ - public SimulationExperiment setCloudletPesArray(int[] cloudletPesArray) { - this.cloudletPesArray = cloudletPesArray; - return this; - } - - public DatacenterBrokerHeuristicRunner getRunner() { + protected abstract void createHosts(); + + /** + * Adds a Host created by a {@link Supplier} function to the list of created Hosts. + * + * @param hostSupplier a {@link Supplier} function that is able to create a Host + * @return the created Host + */ + protected Host addNewHostToList(Supplier hostSupplier) { + Host host = hostSupplier.get(); + hostList.add(host); + numberOfCreatedHosts++; + return host; + } + + + /** + * Gets the object that is in charge to run the experiment. + * @return + */ + public ExperimentRunner getRunner() { return runner; } /** - * @return list of created DatacenterBrokers. + * Gets the list of created DatacenterBrokers. + * @return */ public List getBrokerList() { return brokerList; @@ -335,19 +305,28 @@ public List getBrokerList() { * it will receive an object of the exact type of the {@link SimulationExperiment} * instance that the Consumer is being associated to. */ - public void setAfterExperimentFinish(Consumer afterExperimentFinishConsumer){ + public SimulationExperiment setAfterExperimentFinish(Consumer afterExperimentFinishConsumer){ this.afterExperimentFinish = afterExperimentFinishConsumer; + return this; } /** - *

Gets a {@link Consumer} object that will receive the experiment instance after the experiment + * Gets 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.

+ * and can include collecting data for statistical analysis. + * @return * */ private Consumer getAfterExperimentFinish() { return (Consumer) afterExperimentFinish; } + public int getNumberOfCreatedCloudlets() { + return numberOfCreatedCloudlets; + } + + public int getNumberOfCreatedVms() { + return numberOfCreatedVms; + } } diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/DynamicCloudletsArrivalExperiment.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/dynamiccloudlets/DynamicCloudletsArrivalExperiment.java similarity index 71% rename from cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/DynamicCloudletsArrivalExperiment.java rename to cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/dynamiccloudlets/DynamicCloudletsArrivalExperiment.java index 008aba1e5..7a92c2f34 100644 --- a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/DynamicCloudletsArrivalExperiment.java +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/dynamiccloudlets/DynamicCloudletsArrivalExperiment.java @@ -1,10 +1,11 @@ -package org.cloudsimplus.testbeds; +package org.cloudsimplus.testbeds.dynamiccloudlets; import org.cloudbus.cloudsim.Cloudlet; import org.cloudbus.cloudsim.brokers.DatacenterBroker; import org.cloudbus.cloudsim.brokers.DatacenterBrokerSimple; +import org.cloudsimplus.testbeds.ExperimentRunner; +import org.cloudsimplus.testbeds.SimulationExperiment; import org.cloudsimplus.util.tablebuilder.CloudletsTableBuilderHelper; -import org.cloudsimplus.testbeds.heuristics.DatacenterBrokerHeuristicRunner; import java.util.List; @@ -14,7 +15,7 @@ * * @author Manoel Campos da Silva Filho */ -public class DynamicCloudletsArrivalExperiment extends SimulationExperiment { +final class DynamicCloudletsArrivalExperiment extends SimulationExperiment { public static final int HOSTS_TO_CREATE = 100; /** @@ -25,9 +26,8 @@ public class DynamicCloudletsArrivalExperiment extends SimulationExperiment { * of executing this experiment a defined number of times and to collect * data for statistical analysis. */ - public DynamicCloudletsArrivalExperiment(int index, DatacenterBrokerHeuristicRunner runner) { + public DynamicCloudletsArrivalExperiment(int index, DynamicCloudletsArrivalRunner runner) { super(index, runner); - setHostsToCreate(HOSTS_TO_CREATE); } @Override @@ -42,14 +42,28 @@ protected DatacenterBroker createBroker() { return new DatacenterBrokerSimple("broker0"); } - /** + @Override + protected void createCloudlets(DatacenterBroker broker) { + + } + + @Override + protected void createVms(DatacenterBroker broker) { + + } + + @Override + protected void createHosts() { + + } + + /** * Just a method to try a single run of the experiment. * * @param args */ public static void main(String[] args) { DynamicCloudletsArrivalExperiment exp = new DynamicCloudletsArrivalExperiment(0, null); - exp.setVmPesArray(new int[]{2, 4, 6, 8}).setCloudletPesArray(new int[]{2, 4, 6, 8}); exp.run(); } diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/DynamicCloudletsArrivalRunner.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/dynamiccloudlets/DynamicCloudletsArrivalRunner.java similarity index 61% rename from cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/DynamicCloudletsArrivalRunner.java rename to cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/dynamiccloudlets/DynamicCloudletsArrivalRunner.java index ff6cdd0c4..1b1b2ca54 100644 --- a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/DynamicCloudletsArrivalRunner.java +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/dynamiccloudlets/DynamicCloudletsArrivalRunner.java @@ -1,6 +1,7 @@ -package org.cloudsimplus.testbeds; +package org.cloudsimplus.testbeds.dynamiccloudlets; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; +import org.cloudsimplus.testbeds.ExperimentRunner; /** * Runs the {@link DynamicCloudletsArrivalExperiment} @@ -9,7 +10,7 @@ * * @author Manoel Campos da Silva Filho */ -public class DynamicCloudletsArrivalRunner extends ExperimentRunner { +final class DynamicCloudletsArrivalRunner extends ExperimentRunner { @Override protected void setup() { @@ -26,12 +27,12 @@ protected void printSimulationParameters() { } @Override - protected SummaryStatistics computeStatistics() { + protected SummaryStatistics computeFinalStatistics() { return null; } @Override - protected void printResults(SummaryStatistics stats) { + protected void printFinalResults(SummaryStatistics stats) { } } diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicExperiment.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicExperiment.java index 6c92cacbc..cfb66deb9 100644 --- a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicExperiment.java +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicExperiment.java @@ -1,13 +1,28 @@ package org.cloudsimplus.testbeds.heuristics; +import org.cloudbus.cloudsim.*; +import org.cloudbus.cloudsim.brokers.DatacenterBroker; import org.cloudbus.cloudsim.brokers.DatacenterBrokerHeuristic; import org.cloudbus.cloudsim.distributions.UniformDistr; +import org.cloudbus.cloudsim.provisioners.PeProvisionerSimple; +import org.cloudbus.cloudsim.provisioners.ResourceProvisionerSimple; +import org.cloudbus.cloudsim.resources.Bandwidth; import org.cloudbus.cloudsim.resources.Pe; +import org.cloudbus.cloudsim.resources.PeSimple; +import org.cloudbus.cloudsim.resources.Ram; +import org.cloudbus.cloudsim.schedulers.CloudletSchedulerTimeShared; +import org.cloudbus.cloudsim.schedulers.VmSchedulerTimeShared; +import org.cloudbus.cloudsim.utilizationmodels.UtilizationModel; +import org.cloudbus.cloudsim.utilizationmodels.UtilizationModelFull; import org.cloudsimplus.heuristics.CloudletToVmMappingHeuristic; import org.cloudsimplus.heuristics.CloudletToVmMappingSimulatedAnnealing; import org.cloudsimplus.heuristics.HeuristicSolution; import org.cloudsimplus.testbeds.SimulationExperiment; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + /** *

An experiment that uses a * Simulated Annealing @@ -26,10 +41,10 @@ * * @author Manoel Campos da Silva Filho */ -public class DatacenterBrokerHeuristicExperiment extends SimulationExperiment { +final class DatacenterBrokerHeuristicExperiment extends SimulationExperiment { public static final int HOSTS_TO_CREATE = 100; - /** + /** * Simulated Annealing (SA) parameters. */ public static final double SA_INITIAL_TEMPERATURE = 1.0; @@ -37,22 +52,46 @@ public class DatacenterBrokerHeuristicExperiment extends SimulationExperiment { public static final double SA_COOLING_RATE = 0.003; public static final int SA_NUMBER_OF_NEIGHBORHOOD_SEARCHES = 50; + + /** + * Sets the array with Number of PEs for each VM to create. + * The length of the array defines the number of VMs to create. + * @param vmPesArray VMs PEs array to set + */ + private int vmPesArray[]; + + /** + * Sets the array with Number of PEs for each Cloudlet to create. + * The length of the array defines the number of Cloudlets to create. + * @param cloudletPesArray Cloudlets PEs array to set + */ + private int cloudletPesArray[]; + + /** + * Pseudo random number generator used in the experiment. + */ + private UniformDistr randomGen; + private CloudletToVmMappingSimulatedAnnealing heuristic; /** * Instantiates the simulation experiment. * * @param runner the runner that will be in charge to setup and run the experiment - * @param randomGen pseudo random number generator used in the experiment * @param index a number the identifies the current experiment being run */ - public DatacenterBrokerHeuristicExperiment(DatacenterBrokerHeuristicRunner runner, UniformDistr randomGen, int index) { + public DatacenterBrokerHeuristicExperiment(DatacenterBrokerHeuristicRunner runner, int index) { super(index, runner); - setHostsToCreate(HOSTS_TO_CREATE); - createSimulatedAnnealingHeuristic(randomGen); + this.randomGen = new UniformDistr(0, 1); + } + + @Override + protected void buildScenario() { + createSimulatedAnnealingHeuristic(); + super.buildScenario(); } - private void createSimulatedAnnealingHeuristic(UniformDistr randomGen) { + private void createSimulatedAnnealingHeuristic() { heuristic = new CloudletToVmMappingSimulatedAnnealing(SA_INITIAL_TEMPERATURE, randomGen); heuristic.setColdTemperature(SA_COLD_TEMPERATURE); heuristic.setCoolingRate(SA_COOLING_RATE); @@ -61,12 +100,91 @@ private void createSimulatedAnnealingHeuristic(UniformDistr randomGen) { @Override protected DatacenterBrokerHeuristic createBroker() { - DatacenterBrokerHeuristic broker0 = new DatacenterBrokerHeuristic("Broker0"); - broker0.setHeuristic(heuristic); - return broker0; + return new DatacenterBrokerHeuristic("Broker0").setHeuristic(heuristic); } - @Override + @Override + protected void createCloudlets(DatacenterBroker broker) { + for (int pes: cloudletPesArray) { + addNewCloudletToList(getCloudletSupplier(broker, pes)); + } + } + + /** + * Gets a {@link Supplier} function that is able to create a Cloudlet. + * + * @param broker broker that the Cloudlet to be created by the Supplier function will belong to + * @param cloudletPes number of PEs for the Cloudlet to be created by the Supplier function + * @return the Supplier function that can create a Cloudlet when requested + */ + private Supplier getCloudletSupplier(DatacenterBroker broker, int cloudletPes) { + return () -> { + long length = 400000; //in Million Instructions (MI) + long fileSize = 300; //Size (in bytes) before execution + long outputSize = 300; //Size (in bytes) after execution + //Defines how CPU, RAM and Bandwidth resources are used + //Sets the same utilization model for all these resources. + UtilizationModel utilization = new UtilizationModelFull(); + Cloudlet cloudlet = new CloudletSimple(getNumberOfCreatedCloudlets(), + length, cloudletPes, fileSize, outputSize, + utilization, utilization, utilization); + cloudlet.setUserId(broker.getId()); + return cloudlet; + }; + } + + @Override + protected void createVms(DatacenterBroker broker) { + setVmList(new ArrayList<>(vmPesArray.length)); + for (int pes: vmPesArray) { + addNewVmToList(getVmSupplier(broker, pes)); + } + + } + + /** + * Gets a {@link Supplier} function that is able to create a Vm. + * + * @param broker broker that the Vm to be created by the Supplier function will belong to + * @param vmPes number of PEs for the Vm to be created by the Supplier function + * @return the Supplier function that can create a Vm when requested + */ + private Supplier getVmSupplier(DatacenterBroker broker, int vmPes) { + return () -> { + double mips = 1000; + long storage = 10000; // vm image size (MB) + int ram = 512; // vm memory (MB) + long bw = 1000; // vm bandwidth + return new VmSimple(getNumberOfCreatedVms(), broker.getId(), mips, + vmPes, ram, bw, storage, VMM, + new CloudletSchedulerTimeShared()); + }; + } + + @Override + protected void createHosts() { + for (int i = 0; i < HOSTS_TO_CREATE; i++) { + addNewHostToList(this::createHost); + } + } + + private Host createHost() { + int mips = 1000; + int ram = 2048; // MB + long storage = 1000000; + long bw = 10000; + List cpuCoresList = new ArrayList<>(); + for (int i = 0; i < 8; i++) { + cpuCoresList.add(new PeSimple(i, new PeProvisionerSimple(mips))); + } + + return new HostSimple(getNumberOfCreatedHosts(), + new ResourceProvisionerSimple<>(new Ram(ram)), + new ResourceProvisionerSimple<>(new Bandwidth(bw)), storage, cpuCoresList, + new VmSchedulerTimeShared(cpuCoresList)); + } + + @Override public void printResults() { System.out.printf( "Experiment %d > Heuristic solution for mapping cloudlets to Vm's: ", getIndex()); @@ -82,4 +200,25 @@ public CloudletToVmMappingSimulatedAnnealing getHeuristic() { return heuristic; } + /** + * Sets the pseudo random number generator (PRNG) used internally in the experiment + * by the {@link CloudletToVmMappingSimulatedAnnealing} to try finding a suboptimal solution + * for mapping Cloudlets to VMs. + * + * @param randomGen the PRNG to set + */ + public DatacenterBrokerHeuristicExperiment setRandomGen(UniformDistr randomGen) { + this.randomGen = randomGen; + return this; + } + + public DatacenterBrokerHeuristicExperiment setVmPesArray(int[] vmPesArray) { + this.vmPesArray = vmPesArray; + return this; + } + + public DatacenterBrokerHeuristicExperiment setCloudletPesArray(int[] cloudletPesArray) { + this.cloudletPesArray = cloudletPesArray; + return this; + } } diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicRunner.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicRunner.java index a9787bbd0..eded46058 100644 --- a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicRunner.java +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/heuristics/DatacenterBrokerHeuristicRunner.java @@ -22,7 +22,12 @@ * * @author Manoel Campos da Silva Filho */ -public class DatacenterBrokerHeuristicRunner extends ExperimentRunner { +final class DatacenterBrokerHeuristicRunner extends ExperimentRunner { + /** + * 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, @@ -35,11 +40,6 @@ public class DatacenterBrokerHeuristicRunner extends ExperimentRunner experimentCosts; /** - * An object that compute statistics about experiment run time. + * An object that compute statistics about experiment execution time of all executed experiment runs. */ private final SummaryStatistics runtimeStats; @@ -117,15 +117,15 @@ public static void main(String[] args) { * @return the created cloudlet PEs array */ private int[] createCloudletPesArray() { - int[] array = new int[CLOUDLETS_TO_CREATE]; + 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++){ - array[i] = (int) random.sample()+1; - totalNumberOfPes += array[i]; + pesArray[i] = (int) random.sample()+1; + totalNumberOfPes += pesArray[i]; } - return array; + return pesArray; } /** @@ -137,14 +137,14 @@ private int[] createCloudletPesArray() { */ private int[] createVmPesArray() { UniformDistr random = new UniformDistr(0, VM_PES_NUMBERS.length, getBaseSeed()); - int[] array = new int[VMS_TO_CREATE]; + int[] pesArray = new int[VMS_TO_CREATE]; int totalNumberOfPes = 0; for(int i = 0; i < VMS_TO_CREATE; i++){ - array[i] = VM_PES_NUMBERS[(int)random.sample()]; - totalNumberOfPes += array[i]; + pesArray[i] = VM_PES_NUMBERS[(int)random.sample()]; + totalNumberOfPes += pesArray[i]; } - return array; + return pesArray; } /** @@ -170,20 +170,25 @@ public void addSimulatedAnnealingRuntime(double runTime){ @Override protected DatacenterBrokerHeuristicExperiment createExperiment(int i) { - UniformDistr prng = createRandomGen(i); - addSeed(prng.getSeed()); + UniformDistr prng = createRandomGenAndAddSeedToList(i, 0, 1); DatacenterBrokerHeuristicExperiment exp = - new DatacenterBrokerHeuristicExperiment(this, prng, i); - - exp.setVerbose(experimentVerbose); - exp.setVmPesArray(vmPesArray); - exp.setCloudletPesArray(cloudletPesArray); - exp.setAfterExperimentFinish(this::afterExperimentFinish); + 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. @@ -217,15 +222,8 @@ protected void printSimulationParameters() { DatacenterBrokerHeuristicExperiment.SA_NUMBER_OF_NEIGHBORHOOD_SEARCHES); } - @Override - protected void setup() { - experimentCosts = new ArrayList<>(getNumberOfSimulationRuns()); - vmPesArray = createVmPesArray(); - cloudletPesArray = createCloudletPesArray(); - } - @Override - protected void printResults(SummaryStatistics stats) { + protected void printFinalResults(SummaryStatistics stats) { System.out.printf("\n# Results for %d simulation runs\n", 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."); @@ -276,7 +274,7 @@ private double heuristicSolutionCostPercentageOfRoundRobinSolution(double heuris * to allow get mean, standard deviation and confidence interval */ @Override - protected SummaryStatistics computeStatistics() { + protected SummaryStatistics computeFinalStatistics() { SummaryStatistics costsStats = new SummaryStatistics(); List costs = experimentCosts; diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerExperiment.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerExperiment.java new file mode 100644 index 000000000..a29038003 --- /dev/null +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerExperiment.java @@ -0,0 +1,174 @@ +package org.cloudsimplus.testbeds.linuxscheduler; + +import org.cloudbus.cloudsim.*; +import org.cloudbus.cloudsim.brokers.DatacenterBroker; +import org.cloudbus.cloudsim.brokers.DatacenterBrokerSimple; +import org.cloudbus.cloudsim.distributions.ContinuousDistribution; +import org.cloudbus.cloudsim.distributions.UniformDistr; +import org.cloudbus.cloudsim.provisioners.PeProvisionerSimple; +import org.cloudbus.cloudsim.provisioners.ResourceProvisionerSimple; +import org.cloudbus.cloudsim.resources.Bandwidth; +import org.cloudbus.cloudsim.resources.Pe; +import org.cloudbus.cloudsim.resources.PeSimple; +import org.cloudbus.cloudsim.resources.Ram; +import org.cloudbus.cloudsim.schedulers.CloudletScheduler; +import org.cloudbus.cloudsim.schedulers.CloudletSchedulerTimeShared; +import org.cloudbus.cloudsim.schedulers.VmSchedulerTimeShared; +import org.cloudbus.cloudsim.utilizationmodels.UtilizationModel; +import org.cloudbus.cloudsim.utilizationmodels.UtilizationModelFull; +import org.cloudsimplus.testbeds.ExperimentRunner; +import org.cloudsimplus.testbeds.SimulationExperiment; +import org.cloudsimplus.util.tablebuilder.PriorityCloudletsTableBuilderHelper; +import org.cloudbus.cloudsim.schedulers.CloudletSchedulerCompletelyFair; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + + +/** + * An abstract class to provide the basic features for the classes that implement + * the experiments to assess the {@link CloudletSchedulerCompletelyFair} + * against the {@link CloudletSchedulerTimeShared}. + * + *

All the extending experiment classes will create the exact same simulation scenario + * once all seeds and configurations are shared among them. Such experiments will create + * the number of Hosts and Vms defined by {@link #HOSTS_TO_CREATE} and {@link #VMS_TO_CREATE}. + * The number of Cloudlets is defined randomly for each experiment. The {@link CloudletSchedulerRunner} is in charge + * to instantiate the experiments and set the general parameters (such as the number of Cloudlets). + * All Cloudlets will have the same length defined by {@link #CLOUDLET_LENGHT_MI}, but the number + * of PEs is defined randomly using the {@link CloudletSchedulerExperiment#getCloudletPesPrng()}, + * that in turn is set by each {@link CloudletSchedulerRunner} extending class. + *

+ * + *

All these configurations, including the number of Cloudlets and PEs of each one, that are + * defined randomly, are shared between all sub-classes of this one. Each sub-class just + * uses the same scenario with a different {@link CloudletScheduler} implementation + * to compare results.

+ * + * @author Manoel Campos da Silva Filho + * @see CloudletSchedulerTimeSharedExperiment + * @see CompletelyFairSchedulerExperiment + */ +abstract class CloudletSchedulerExperiment extends SimulationExperiment { + public static final int HOST_PES = 32; + public static final int VM_PES = HOST_PES; + public static final double VM_MIPS = 1000; + public static final long VM_STORAGE = 10000; // vm image size (MB) + public static final int VM_RAM = 512; // vm memory (MB) + public static final long VM_BW = 1000; // vm bandwidth + public static final int MAX_CLOUDLET_PES = VM_PES/8 + 1; + public static final int HOSTS_TO_CREATE = 1; + public static final int VMS_TO_CREATE = 1; + public static final long CLOUDLET_LENGHT_MI = 10000; //in Million Instructions (MI) + + private ContinuousDistribution cloudletPesPrng; + private int numberOfCloudletsToCreate; + + public CloudletSchedulerExperiment(int index, ExperimentRunner runner) { + super(index, runner); + this.cloudletPesPrng = new UniformDistr(0, 1); + } + + @Override + public void printResults() { + Log.enable(); + try { + System.out.printf("\nCloudlets: %d\n", numberOfCloudletsToCreate); + DatacenterBroker broker = getBrokerList().stream().findFirst().orElse(DatacenterBroker.NULL); + new PriorityCloudletsTableBuilderHelper(broker.getCloudletsFinishedList()).build(); + } finally { + Log.disable(); + } + } + + @Override + protected DatacenterBroker createBroker() { + return new DatacenterBrokerSimple("broker0"); + } + + @Override + protected void createHosts() { + for (int i = 0; i < HOSTS_TO_CREATE; i++) { + addNewHostToList(this::getHostSupplier); + } + } + + private Host getHostSupplier() { + int mips = 1000; // capacity of each CPU core (in Million Instructions per Second) + int ram = 2048; // host memory (MB) + long storage = 1000000; // host storage + long bw = 10000; + List cpuCoresList = new ArrayList<>(); + for (int i = 0; i < HOST_PES; i++) { + cpuCoresList.add(new PeSimple(i, new PeProvisionerSimple(mips))); + } + + return new HostSimple(getNumberOfCreatedHosts(), + new ResourceProvisionerSimple<>(new Ram(ram)), + new ResourceProvisionerSimple<>(new Bandwidth(bw)), storage, cpuCoresList, + new VmSchedulerTimeShared(cpuCoresList)); + } + + @Override + protected void createVms(DatacenterBroker broker) { + for(int i = 0; i < VMS_TO_CREATE; i++) { + addNewVmToList(getVmSupplier(broker)); + } + } + + /** + * Gets a {@link Supplier} function that is able to create a new Vm. + * + * @param broker broker that the Vm to be created by the Supplier function will belong to + * @return the Supplier function that can create a Vm when requested + */ + protected abstract Supplier getVmSupplier(DatacenterBroker broker); + + @Override + protected void createCloudlets(DatacenterBroker broker) { + for(int i = 0; i < numberOfCloudletsToCreate; i++) { + addNewCloudletToList(getCloudletSupplier(broker)); + } + } + + /** + * Gets a {@link Supplier} function that is able to create a Cloudlet. + * + * @param broker broker that the Cloudlet to be created by the Supplier function will belong to + * @return the Supplier function that can create a Cloudlet when requested + */ + private Supplier getCloudletSupplier(DatacenterBroker broker) { + return () -> { + long fileSize = 300; //Size (in bytes) before execution + long outputSize = 300; //Size (in bytes) after execution + final int cloudletPes = (int)cloudletPesPrng.sample(); + //Defines how CPU, RAM and Bandwidth resources are used + //Sets the same utilization model for all these resources. + UtilizationModel utilization = new UtilizationModelFull(); + Cloudlet cloudlet = new CloudletSimple(getNumberOfCreatedCloudlets(), + CLOUDLET_LENGHT_MI, cloudletPes, fileSize, outputSize, + utilization, utilization, utilization); + cloudlet.setUserId(broker.getId()); + return cloudlet; + }; + } + + public ContinuousDistribution getCloudletPesPrng() { + return cloudletPesPrng; + } + + public CloudletSchedulerExperiment setCloudletPesPrng(ContinuousDistribution cloudletPesPrng) { + this.cloudletPesPrng = cloudletPesPrng; + return this; + } + + public CloudletSchedulerExperiment setNumberOfCloudletsToCreate(int numberOfCloudletsToCreate) { + this.numberOfCloudletsToCreate = numberOfCloudletsToCreate; + return this; + } + + public int getNumberOfCloudletsToCreate() { + return numberOfCloudletsToCreate; + } +} diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerRunner.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerRunner.java new file mode 100644 index 000000000..51ddbce13 --- /dev/null +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerRunner.java @@ -0,0 +1,112 @@ +package org.cloudsimplus.testbeds.linuxscheduler; + +import org.apache.commons.math3.stat.descriptive.SummaryStatistics; +import org.cloudbus.cloudsim.Cloudlet; +import org.cloudbus.cloudsim.brokers.DatacenterBroker; +import org.cloudbus.cloudsim.distributions.ContinuousDistribution; +import org.cloudbus.cloudsim.distributions.UniformDistr; +import org.cloudsimplus.testbeds.ExperimentRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import static org.cloudsimplus.testbeds.linuxscheduler.CloudletSchedulerExperiment.*; + +/** + * An abstract runner for {@link CloudletSchedulerExperiment}. + * + * @author Manoel Campos da Silva Filho + * @param the type of experiments the runner will execute + */ +abstract class CloudletSchedulerRunner extends ExperimentRunner { + /** + * A Pseudo Random Number Generator (PRNG) used to generate the number of Cloudlets to be + * created for each experiment run. + */ + protected ContinuousDistribution numberOfCloudletsPRNG; + + /** + * A list of Cloudlets' completion time mean for each experiment run. + */ + private List cloudletsCompletionTimeMeans; + + /** + * Number of cloudlets in each experiment run. + */ + private List cloudletsNumber; + + /** + * Instantiates a runner and sets all parameters required to run + * the experiments. Such parameters are shared among all runners + * that extends this class. + */ + public CloudletSchedulerRunner(){ + /* + Values used for CloudSim Plus Paper: + NumberOfSimulationRuns: 1200 + ApplyAntitheticVariatesTechnique: true + NumberOfBatches: 6 + BaseSeed: 1475098589732L + */ + this.setNumberOfSimulationRuns(1200) + .setApplyAntitheticVariatesTechnique(false) + //.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); + } + + @Override + protected void setup() { + cloudletsCompletionTimeMeans = new ArrayList<>(getNumberOfSimulationRuns()); + cloudletsNumber = new ArrayList<>(getNumberOfSimulationRuns()); + numberOfCloudletsPRNG = new UniformDistr(VM_PES/2, VM_PES, getBaseSeed()); + } + + @Override + protected void printSimulationParameters() { + System.out.printf("\n----------------------------------%s----------------------------------\n", getClass().getSimpleName()); + System.out.printf("Hosts: %5d | PEs: %2d | VMs: %d | PEs: %d\n", HOSTS_TO_CREATE, HOST_PES, VMS_TO_CREATE, VM_PES); + System.out.printf("Experiment Runs: %5d | Max Cloudlets PES: %2d\n", + getNumberOfSimulationRuns(), (MAX_CLOUDLET_PES-1)); + + } + + @Override + protected void printFinalResults(SummaryStatistics stats) { + System.out.printf("Mean Number of Cloudlets: %.2f\n", cloudletsNumber.stream().mapToInt(n -> n).average().orElse(0.0)); + System.out.printf("Cloudlet Completion Time Avg: %.2f | Std dev: %.2f\n", stats.getMean(), stats.getStandardDeviation()); + System.out.printf("Cloudlet Completion Min Avg Time: %.2f | Max avg time: %.2f\n", stats.getMin(), stats.getMax()); + System.out.println(); + } + + @Override + protected SummaryStatistics computeFinalStatistics() { + SummaryStatistics stats = new SummaryStatistics(); + for(double cloudletExecutionTimeMean: cloudletsCompletionTimeMeans) { + stats.addValue(cloudletExecutionTimeMean); + } + return stats; + } + + /** + * 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 + */ + protected void afterExperimentFinish(T experiment){ + Consumer addExperimentStatisticsToLists = broker -> { + Double average = broker.getCloudletsFinishedList().stream() + .mapToDouble(Cloudlet::getActualCPUTime) + .average() + .orElse(0.0); + cloudletsCompletionTimeMeans.add(average); + cloudletsNumber.add(broker.getCloudletsFinishedList().size()); + }; + + experiment.getBrokerList().stream().findFirst().ifPresent(addExperimentStatisticsToLists); + } + +} diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedExperiment.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedExperiment.java new file mode 100644 index 000000000..2011ea05a --- /dev/null +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedExperiment.java @@ -0,0 +1,44 @@ +package org.cloudsimplus.testbeds.linuxscheduler; + +import org.cloudbus.cloudsim.Vm; +import org.cloudbus.cloudsim.VmSimple; +import org.cloudbus.cloudsim.brokers.DatacenterBroker; +import org.cloudbus.cloudsim.schedulers.CloudletSchedulerCompletelyFair; +import org.cloudbus.cloudsim.schedulers.CloudletSchedulerTimeShared; +import org.cloudsimplus.testbeds.ExperimentRunner; + +import java.util.function.Supplier; + + +/** + * An experiment runs Cloudlets using a {@link CloudletSchedulerTimeShared} to get results + * to compare to the {@link CloudletSchedulerCompletelyFair} scheduler experiment + * implemented in {@link CloudletSchedulerExperiment}. + * + *

Check the super class {@link CloudletSchedulerExperiment}

to see the general + * experiment configuration and goals. + * + * @author Manoel Campos da Silva Filho + * @see CloudletSchedulerExperiment + */ +final class CloudletSchedulerTimeSharedExperiment extends CloudletSchedulerExperiment { + /** + * Creates a simulation experiment. + * + * @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 + */ + public CloudletSchedulerTimeSharedExperiment(int index, CloudletSchedulerTimeSharedRunner runner) { + super(index, runner); + } + + @Override + protected Supplier getVmSupplier(DatacenterBroker broker) { + return () -> { + return new VmSimple(getNumberOfCreatedVms(), broker.getId(), + VM_MIPS, VM_PES, VM_RAM, VM_BW, VM_STORAGE, VMM, + new CloudletSchedulerTimeShared()); + }; + } +} diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedRunner.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedRunner.java new file mode 100644 index 000000000..646fd4712 --- /dev/null +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CloudletSchedulerTimeSharedRunner.java @@ -0,0 +1,33 @@ +package org.cloudsimplus.testbeds.linuxscheduler; + +import org.cloudbus.cloudsim.distributions.ContinuousDistribution; + +import static org.cloudsimplus.testbeds.linuxscheduler.CloudletSchedulerExperiment.MAX_CLOUDLET_PES; + +/** + * @author Manoel Campos da Silva Filho + */ +public class CloudletSchedulerTimeSharedRunner extends CloudletSchedulerRunner { + /** + * Starts the execution of the experiments + * the number of times defines in {@link #numberOfSimulationRuns}. + * @param args + */ + public static void main(String[] args) { + new CloudletSchedulerTimeSharedRunner().run(); + } + + @Override + protected CloudletSchedulerTimeSharedExperiment createExperiment(int i) { + ContinuousDistribution cloudletPesPrng = createRandomGenAndAddSeedToList(i, 1, MAX_CLOUDLET_PES); + CloudletSchedulerTimeSharedExperiment exp = new CloudletSchedulerTimeSharedExperiment(i, this); + + exp + .setCloudletPesPrng(cloudletPesPrng) + .setNumberOfCloudletsToCreate((int) numberOfCloudletsPRNG.sample()) + .setAfterExperimentFinish(this::afterExperimentFinish) + .setVerbose(false); + + return exp; + } +} diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerExperiment.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerExperiment.java new file mode 100644 index 000000000..7df8695d4 --- /dev/null +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerExperiment.java @@ -0,0 +1,48 @@ +package org.cloudsimplus.testbeds.linuxscheduler; + +import org.cloudbus.cloudsim.*; +import org.cloudbus.cloudsim.brokers.DatacenterBroker; +import org.cloudbus.cloudsim.schedulers.CloudletSchedulerCompletelyFair; +import org.cloudbus.cloudsim.schedulers.CloudletSchedulerTimeShared; +import org.cloudsimplus.testbeds.ExperimentRunner; + +import java.util.function.Supplier; + +/** + * An experiment that shows how the oversimplied time-shared CloudletScheduler implementation provided by + * the {@link CloudletSchedulerTimeShared} CloudSim class increases task completion time + * of all Cloudlets and ignores Cloudlets priorities. + * + *

It also shows how a more realistic scheduler such as the {@link CloudletSchedulerCompletelyFair} + * provided by CloudSim Plus is concerned in Cloudlets priorities and gets overall reduction of + * task completion time. This scheduler is an simplified implementation of the + * Completely Fair Scheduler (CFS) used by Linux Kernel.

+ * + *

Check the super class {@link CloudletSchedulerExperiment}

to see the general + * experiment configuration and goals. + * + * @author Manoel Campos da Silva Filho + */ +final class CompletelyFairSchedulerExperiment extends CloudletSchedulerExperiment { + + /** + * Creates a simulation experiment. + * + * @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 + */ + public CompletelyFairSchedulerExperiment(int index, CompletelyFairSchedulerRunner runner) { + super(index, runner); + } + + @Override + protected Supplier getVmSupplier(DatacenterBroker broker) { + return () -> { + return new VmSimple(getNumberOfCreatedVms(), broker.getId(), + VM_MIPS, VM_PES, VM_RAM, VM_BW, VM_STORAGE, VMM, + new CloudletSchedulerCompletelyFair()); + }; + } + +} diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerRunner.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerRunner.java new file mode 100644 index 000000000..671996343 --- /dev/null +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/CompletelyFairSchedulerRunner.java @@ -0,0 +1,38 @@ +package org.cloudsimplus.testbeds.linuxscheduler; + +import org.cloudbus.cloudsim.distributions.ContinuousDistribution; + +import static org.cloudsimplus.testbeds.linuxscheduler.CloudletSchedulerExperiment.MAX_CLOUDLET_PES; + + +/** + * Runs the {@link CompletelyFairSchedulerExperiment} a defined number of times + * and computes statistics. + * + * @author Manoel Campos da Silva Filho + */ +class CompletelyFairSchedulerRunner extends CloudletSchedulerRunner { + /** + * Starts the execution of the experiments + * the number of times defines in {@link #numberOfSimulationRuns}. + * @param args + */ + public static void main(String[] args) { + new CompletelyFairSchedulerRunner().run(); + } + + @Override + protected CompletelyFairSchedulerExperiment createExperiment(int i) { + ContinuousDistribution cloudletPesPrng = createRandomGenAndAddSeedToList(i, 1, MAX_CLOUDLET_PES); + CompletelyFairSchedulerExperiment exp = new CompletelyFairSchedulerExperiment(i, this); + + exp + .setCloudletPesPrng(cloudletPesPrng) + .setNumberOfCloudletsToCreate((int) numberOfCloudletsPRNG.sample()) + .setAfterExperimentFinish(this::afterExperimentFinish) + .setVerbose(false); + + return exp; + } + +} diff --git a/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/package-info.java b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/package-info.java new file mode 100644 index 000000000..b0f27bbbd --- /dev/null +++ b/cloudsim-plus-testbeds/src/main/java/org/cloudsimplus/testbeds/linuxscheduler/package-info.java @@ -0,0 +1,15 @@ +/** + * The package contains a set of experiments to compare the {@link org.cloudbus.cloudsim.schedulers.CloudletSchedulerTimeShared}, + * that has an oversimplified implementation of a time-shared scheduler, and the new CloudSim Plus + * {@link org.cloudbus.cloudsim.schedulers.CloudletSchedulerCompletelyFair} class that provides + * a basic implementation of the + * Completely Fair Scheduler (CFS) used by Linux Kernel. + * + *

The package provides two {@link org.cloudsimplus.testbeds.ExperimentRunner}, + * one for each of the experiments. Each runner has a main method + * that allows to start a specific testbed. A testbed is a set of experiments executed + * a given number of times defined by the runner class.

+ * + * @author Manoel Campos da Silva Filho + */ +package org.cloudsimplus.testbeds.linuxscheduler; diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/Cloudlet.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/Cloudlet.java index b4c1938da..5bb9792a8 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/Cloudlet.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/Cloudlet.java @@ -352,8 +352,9 @@ enum Status { /** * Gets the priority of this Cloudlet for scheduling inside a Vm. * Each {@link CloudletScheduler} implementation can define if it will - * use this Cloudlet attribute to impose execution priorities or - * not. + * use this attribute to impose execution priorities or not. + * How the priority is interpreted and what is the range of values it accepts depends on the {@link CloudletScheduler} + * that is being used by the Vm running the Cloudlet. * * @return priority of this cloudlet * @pre $none @@ -363,7 +364,9 @@ enum Status { /** * Sets the {@link #getPriority() priority} of this Cloudlet for scheduling inside a Vm. - * How the priority is interpreted depends on the {@link CloudletScheduler} + * Each {@link CloudletScheduler} implementation can define if it will + * use this attribute to impose execution priorities or not. + * How the priority is interpreted and what is the range of values it accepts depends on the {@link CloudletScheduler} * that is being used by the Vm running the Cloudlet. * * @param priority priority of this Cloudlet diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/CloudletExecutionInfo.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/CloudletExecutionInfo.java index 8270feee5..82df7b514 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/CloudletExecutionInfo.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/CloudletExecutionInfo.java @@ -333,7 +333,9 @@ public boolean setCloudletStatus(Status status) { // if a Cloudlet is now in execution if (status == Status.INEXEC || (prevStatus == Status.PAUSED && status == Status.RESUMED)) { startExecTime = clock; - cloudlet.setExecStartTime(startExecTime); + if(cloudlet.getExecStartTime() == 0) { + cloudlet.setExecStartTime(startExecTime); + } } } catch (Exception e) { success = false; diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/brokers/DatacenterBrokerHeuristic.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/brokers/DatacenterBrokerHeuristic.java index 032668efa..5468a2ead 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/brokers/DatacenterBrokerHeuristic.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/brokers/DatacenterBrokerHeuristic.java @@ -109,9 +109,11 @@ public Heuristic getHeuristic() { * depends on the heuristic parameters that have to be set carefully.

* * @param heuristic the heuristic to be set + * @return the DatacenterBrokerHeuristic instance */ - public void setHeuristic(CloudletToVmMappingHeuristic heuristic) { + public DatacenterBrokerHeuristic setHeuristic(CloudletToVmMappingHeuristic heuristic) { this.heuristic = heuristic; + return this; } } diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/distributions/UniformDistr.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/distributions/UniformDistr.java index 37fff8bf9..b2170df58 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/distributions/UniformDistr.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/distributions/UniformDistr.java @@ -70,7 +70,7 @@ public static double sample(Random rd, double min, double max) { * of experiments using this PRNG. * * This technique doesn't work for all the cases. However, - * in the cases it can be applied, in order to it work one have to + * in the cases it can be applied, in order to it work, one have to * perform some actions. Consider an experiment that has to run "n" times. * The first half of these experiments has to use the seeds the developer * want. However, the second half of the experiments have to diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletScheduler.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletScheduler.java index 1d584b2cd..ede119154 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletScheduler.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletScheduler.java @@ -172,7 +172,7 @@ public interface CloudletScheduler extends Serializable { * @param rcl the rcl * @param mipsShare the mips share * @return the total current mips available for each Cloudlet PE - * + * * @todo In fact, this method is returning different data depending * of the subclass. It is expected that the way the method use to compute * the resulting value can be different in every subclass, @@ -271,6 +271,19 @@ public interface CloudletScheduler extends Serializable { */ void setVm(Vm vm) ; + /** + * Gets the number of currently used {@link Pe}'s. + * @return + */ + int getUsedPes(); + + /** + * Gets the number of PEs currently not being used. + * @return + */ + int getFreePes(); + + /** * Checks if a Cloudlet can be added to the execution list or not. * Each CloudletScheduler can define a different policy to @@ -293,7 +306,7 @@ public interface CloudletScheduler extends Serializable { * @param cloudlet Cloudlet to check if it can be added to the execution list * @return true if the Cloudlet can be added to the execution list, false otherwise */ - boolean canAddCloudletToExecutionList(CloudletExecutionInfo cloudlet); + boolean canAddCloudletToExecutionList(CloudletExecutionInfo cloudlet); /** * A property that implements the Null Object Design Pattern for {@link CloudletScheduler} @@ -323,6 +336,10 @@ public interface CloudletScheduler extends Serializable { @Override public double updateVmProcessing(double currentTime, List mipsShare) { return 0.0; } @Override public Vm getVm() { return Vm.NULL; } @Override public void setVm(Vm vm) {} + + @Override public int getUsedPes() { return 0; } + @Override public int getFreePes() { return 0; } + @Override public boolean canAddCloudletToExecutionList(CloudletExecutionInfo cloudlet) { return false; } @Override public List getCloudletFinishedList() { return Collections.EMPTY_LIST; } }; diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerAbstract.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerAbstract.java index 7272e9d9f..8bbefe30e 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerAbstract.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerAbstract.java @@ -54,7 +54,7 @@ public abstract class CloudletSchedulerAbstract implements CloudletScheduler { /** * @see #getCloudletExecList() */ - private Collection cloudletExecList; + private List cloudletExecList; /** * @see #getCloudletPausedList() @@ -74,7 +74,7 @@ public abstract class CloudletSchedulerAbstract implements CloudletScheduler { /** * @see #getCloudletWaitingList() */ - private Collection cloudletWaitingList; + private List cloudletWaitingList; /** * @see #getVm() @@ -134,24 +134,21 @@ public List getCurrentMipsShare() { } /** - * Gets a Collection of cloudlets being executed on the VM. - * It is used a Collection instead of List in order to enable different - * schedulers to define what implementation has to be used for such - * Collection (if a ordered Set as the TreeSet or a regular List as the ArrayList). + * Gets a List of cloudlets being executed on the VM. * - * @return the cloudlet exec collection + * @return the cloudlet execution list * @see #addCloudletToExecList(CloudletExecutionInfo) * @see #removeCloudletFromExecListAndSetFinishTime(org.cloudbus.cloudsim.CloudletExecutionInfo) */ - protected Collection getCloudletExecList() { + protected List getCloudletExecList() { return cloudletExecList; } - protected final void setCloudletWaitingList(Collection cloudletWaitingList){ + protected final void setCloudletWaitingList(List cloudletWaitingList){ this.cloudletWaitingList = cloudletWaitingList; } - protected final void setCloudletExecList(Collection cloudletExecList){ + protected final void setCloudletExecList(List cloudletExecList){ this.cloudletExecList = cloudletExecList; } @@ -192,14 +189,11 @@ protected List getCloudletFailedList() { } /** - * Gets a Collection of cloudlet waiting to be executed on the VM. - * It is used a Collection instead of List in order to enable different - * schedulers to define what implementation has to be used for such - * Collection (if a ordered Set as the TreeSet or a regular List as the ArrayList). + * Gets a List of cloudlet waiting to be executed on the VM. * * @return the cloudlet waiting list */ - protected Collection getCloudletWaitingList() { + protected List getCloudletWaitingList() { return cloudletWaitingList; } @@ -228,7 +222,6 @@ protected double processCloudletSubmit(CloudletExecutionInfo rcl, double fileTra if(canAddCloudletToExecutionList(rcl)){ rcl.setCloudletStatus(Status.INEXEC); rcl.setFileTransferTime(fileTransferTime); - rcl.setLastProcessingTime(CloudSim.clock()); addCloudletToExecList(rcl); return fileTransferTime + (rcl.getCloudletLength() / getProcessor().getCapacity()); } @@ -245,6 +238,7 @@ protected double processCloudletSubmit(CloudletExecutionInfo rcl, double fileTra */ protected void addCloudletToExecList(CloudletExecutionInfo cloudlet) { cloudlet.setCloudletStatus(Cloudlet.Status.INEXEC); + cloudlet.setLastProcessingTime(CloudSim.clock()); cloudletExecList.add(cloudlet); addUsedPes(cloudlet.getNumberOfPes()); } @@ -537,10 +531,7 @@ protected long cloudletExecutionTotalLengthForElapsedTime(CloudletExecutionInfo double executedInstructions = (processor.getAvailableMipsByPe() * rcl.getNumberOfPes() * actualProcessingTime * Consts.MILLION); - Log.println(Log.Level.DEBUG, getClass(), currentTime, - "Cloudlet: %d Processing time: %.2f Last processed time: %.2f Actual process time: %.2f MI so far: %d", - rcl.getCloudletId(), currentTime, rcl.getLastProcessingTime(), - actualProcessingTime, rcl.getCloudlet().getCloudletFinishedSoFar()); + //Log.println(Log.Level.DEBUG, getClass(), currentTime, "Cloudlet: %d Processing time: %.2f Last processed time: %.2f Actual process time: %.2f MI so far: %d", rcl.getCloudletId(), currentTime, rcl.getLastProcessingTime(), actualProcessingTime, rcl.getCloudlet().getCloudletFinishedSoFar()); return (long)executedInstructions; } @@ -751,16 +742,15 @@ public void setVm(Vm vm) { this.vm = vm; } - /** - * Gets the number of currently used {@link Pe}'s. - * @return - * - * @todo The number of free and used PEs should be inside the Processor class. - * However, a new instance of the class is created every time the - * updateVmProcessing is called, what will make the information about the - * number of usedPes to be lost. - */ + @Override public int getUsedPes() { + /** + * + * @todo The number of free and used PEs should be inside the Processor class. + * However, a new instance of the class is created every time the + * updateVmProcessing is called, what will make the information about the + * number of usedPes to be lost. + */ return usedPes; } @@ -768,7 +758,8 @@ public int getUsedPes() { * Gets the number of PEs currently not being used. * @return */ - protected int getFreePes() { + @Override + public int getFreePes() { return getProcessor().getNumberOfPes() - getUsedPes(); } diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerCompletelyFair.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerCompletelyFair.java index 89c803ca1..6f5e1a1a2 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerCompletelyFair.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerCompletelyFair.java @@ -1,14 +1,12 @@ package org.cloudbus.cloudsim.schedulers; -import java.util.Collection; +import java.util.*; + import org.cloudbus.cloudsim.Cloudlet; import org.cloudbus.cloudsim.CloudletExecutionInfo; import org.cloudbus.cloudsim.core.CloudSim; import org.cloudbus.cloudsim.resources.Pe; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; @@ -17,22 +15,30 @@ import org.cloudbus.cloudsim.Log; /** - * A Completely Fair Scheduler (CFS) + * A simplified implementation of the Completely Fair Scheduler (CFS) * that is the default scheduler used for most tasks on recent Linux Kernel. It is a time-shared * scheduler that shares CPU cores between running applications by preempting * them after a time period (timeslice) to allow other ones to start executing * during their timeslices. * + *

This scheduler supposes that Cloudlets priorities are in the range from [-20 to 19], + * as used in Linux Kernel. Despite setting + * Cloudlets priorities with values outside this interval will work as well, one has to + * realize that lower priorities are defined by negative values. + *

+ * *

- * It is a basic implementation that covers that covers the following features: + * It is a basic implementation that covers the following features: *

    - *
  • Defines a general runqueue for all CPU cores ({@link Pe}) instead + *
  • Defines a general runqueue (the waiting list which defines which Cloudlets to run next) for all CPU cores ({@link Pe}) instead * of one for each core. More details in the listing below.
  • *
  • Computes process ({@link Cloudlet}) niceness based on its priority: {@code niceness = -priority}. * The nice value (niceness) defines how nice a process is to the other ones. - * Lower niceness (negative values) represents higher priority and consequently higher weight.
  • + * Lower niceness (negative values) represents higher priority and consequently higher weight, while + * higher niceness (positive values) represent lower priority and lower weight. *
  • Computes process timeslice based on its weight, that in turn is computed based on its niceness. - * The timeslice is the amount of time that a process is allowed to use the CPU. + * The timeslice is the amount of time that a process is allowed to use the CPU before be preempted to make + * room for other process to run. * The CFS scheduler uses a dynamic defined timeslice.
  • *
* @@ -43,69 +49,41 @@ * to allow another one to start executing. This is the task preemption * process that allows a core to be shared between several applications. * - *

Since this scheduler does not consider + *

  • Since this scheduler does not consider * context switch - * overhead, there is only one runqueue for all CPU cores because + * overhead, there is only one runqueue (waiting list) for all CPU cores because * each application is not in fact assigned to a specific CPU core. * The scheduler just computes how much computing power (in MIPS) * and number of cores each application can use and that MIPS capacity * is multiplied by the number of cores the application requires. - * This approach then enable the application to execute that number of instructions + * Such an approach then enables the application to execute that number of instructions * per second. Once the {@link Pe PEs} do not in fact run the application, - * (application running is simulated just computing the amount of instructions - * that can be executed), it doesn't matter which PEs are "running" the application. - *

    + * (application execution is simulated just computing the amount of instructions + * that can be run), it doesn't matter which PEs are "running" the application. + *
  • * + *
  • It doesn't use a Red-Black tree (such as the TreeSet), as in real implementations of CFS, to accendingly sort + * Cloudlets in the waiting list (runqueue) based on their virtual runtime + * (placing the Cloudlets that have run the least at the top of the tree) because + * the use of such a data structure added some complexity to the implementation. And once different Cloudlets + * may have the same virtual runtime, this introduced some issues when adding or + * removing elements in a structure such as the TreeSet, that requires + * each value (the virtual runtime in this case) used to sort the Set to be unique.
  • * * * The implementation was based on the book of Robert Love: Linux Kernel Development, 3rd ed. Addison-Wesley, 2010 * and some other references listed below. *

    - * - *

    - * O scheduler é baseado no time-shared mas deve funcionar de maneira diferente. - *

      - *
    • - * - * A getCloudletExecutionList deve representar - * apenas as cloudlets que estão executando de fato no momento atual. - * A diferença é que no construtor, tal lista deve ser instanciada como um - * {@link Set} para manter a ordem dos elementos de acordo com o vruntime. - * - *
    • - * - *
    • - * Adicionar vruntime ao CloudletExecutionInfo para permitir - * ordenar a execution list por ele. Isso vai facilitar remover uma cloudlet - * desta lista, considerando aquela que tiver o maior vruntime (que já rodou mais - * que as outras). - * - *
    • - * - *
    • A lista pode ser ordenada de forma descrescente para - * permitir usar stream pra pegar o primeiro elemento.
    • - * - *
    • A waiting list é que será de fato a runqueue, contendo - * a lista de cloudlets que devem rodar em seguida (conforme definição da wikipedia).
    • - * - *
    • Ela, diferente do CloudletSchedulerTimeShared, - * deve sim ter cloudlets. O CFS deve de fato implementar a preempção, - * removendo processos na execution list para dar a vez - * (mesmo que tais processos não tenhma terminado) para outros processos - * na runqueue (waiting list).
    • - * - *
    • A waiting list sim é que deve ser implementada como uma Red-Black tree.
    • - *
    - *

    - * * * @author Manoel Campos da Silva Filho + * @since CloudSim Plus 1.0 * * @see Inside the Linux 2.6 Completely Fair Scheduler * @see Learn Linux, 101: Process execution priorities * @see Towards achieving fairness in the Linux scheduler * @see The Linux scheduler - * @see kernel.org: CFS Design + * @see kernel.org: CFS Scheduler Design + * @see Linux Scheduler FAQ */ public final class CloudletSchedulerCompletelyFair extends CloudletSchedulerTimeShared { /** @@ -120,14 +98,12 @@ public final class CloudletSchedulerCompletelyFair extends CloudletSchedulerTime public CloudletSchedulerCompletelyFair(){ super(); - setCloudletExecList(new TreeSet<>(this::executingCloudletsComparator)); - setCloudletWaitingList(new TreeSet<>(this::waitingCloudletsComparator)); } /** * A comparator used to ascendingly sort Cloudlets into the waiting list * based on their virtual runtime. By this way, the Cloudlets in the beginning - * of this list will be that ones which have run the least and have to be + * of such a list will be that ones which have run the least and have to be * prioritized when getting Cloudlets from this list to add to the execution * list. * @@ -137,16 +113,8 @@ public CloudletSchedulerCompletelyFair(){ * a positive value if c1 is greater than c2 */ private int waitingCloudletsComparator(CloudletExecutionInfo c1, CloudletExecutionInfo c2){ - if(c1.equals(c2)) - return 0; - double diff = c1.getVirtualRuntime() - c2.getVirtualRuntime(); - /*If the difference between the virtual runtime is equal to zero, the comparator considers - * that the objects are the same and this causes issues when adding or removing - * elements into a TreeSet that accepts just unique objects. - * By this way, if the diff is zero, uses the priorities difference. - * If the diff is yet zero, uses the IDs difference.*/ if(diff == 0) diff = c1.getCloudlet().getPriority()-c2.getCloudlet().getPriority(); if(diff == 0) @@ -155,23 +123,6 @@ private int waitingCloudletsComparator(CloudletExecutionInfo c1, CloudletExecuti return (int)diff; } - /** - * A comparator used to descendingly sort running Cloudlets into the execution list - * based on their virtual runtime. By this way, the Cloudlets in the beginning - * of this list will be that ones which have run the most and thus, are the - * first to be preempted to allow Cloudlets in the waiting list to run. - * - * @param c1 first Cloudlet to compare - * @param c2 second Cloudlet to compare - * @return a negative value if c2 is lower than c1, zero if they are equals, - * a positive value if c2 is greater than c1 - */ - private int executingCloudletsComparator(CloudletExecutionInfo c1, CloudletExecutionInfo c2){ - /*Calling the other comparator just inverting the parameters order will change the sorting - order.*/ - return waitingCloudletsComparator(c2, c1); - } - /** * Gets the latency, that is the amount of time (in seconds) * the scheduler will allow the execution of waiting Cloudlets @@ -197,9 +148,14 @@ public int getLatency() { /** * Sets the latency time (in seconds) * @param latency the latency to set + * @throws IllegalArgumentException when latency is lower than minimum granularity */ public void setLatency(int latency) { - this.latency = latency; + if(latency < mininumGranularity){ + throw new IllegalArgumentException("Latency cannot be lower than the mininum granularity."); + } + + this.latency = latency; } /** @@ -222,19 +178,36 @@ protected double computeCloudletTimeSlice(CloudletExecutionInfo cloudlet){ return Math.min(timeslice, getMininumGranularity()); } - /** - * Gets the nice value from a Cloudlet based on its priority. - * The nice value is the opposite of the priority. - * - *

    As "niceness" is a terminology defined by specific schedulers - * (such as Linux Schedulers), it is not defined inside the Cloudlet.

    - * - * @param cloudlet Cloudlet to get the nice value - * @return the cloudlet niceness - */ - protected double getCloudletNiceness(CloudletExecutionInfo cloudlet){ - return -cloudlet.getCloudlet().getPriority(); - } + /** + * Gets a list of Cloudlets that are waiting to run, the so called + * run queue. + * + *

    + * NOTE: Different from real implementations, this scheduler uses just one run queue + * for all processor cores (PEs). Since CPU context switch is not concerned, + * there is no point in using different run queues. + *

    + * + * @return + */ + @Override + protected List getCloudletWaitingList() { + return super.getCloudletWaitingList(); + } + + /** + * {@inheritDoc} + * The cloudlet waiting list (runqueue) is sorted according to the virtual runtime (vruntime), + * which indicates the amount of time the Cloudlet has run. + * This runtime increases as the Cloudlet executes. + * + * @return {@inheritDoc} + */ + @Override + protected Optional findSuitableWaitingCloudletToStartExecutingAndRemoveIt() { + getCloudletWaitingList().sort(this::waitingCloudletsComparator); + return super.findSuitableWaitingCloudletToStartExecutingAndRemoveIt(); + } /** * Gets the weight of the Cloudlet to use the CPU, that is @@ -255,7 +228,22 @@ protected double getCloudletWeight(CloudletExecutionInfo cloudlet){ return 1024.0/(Math.pow(1.25, getCloudletNiceness(cloudlet))); } - /** + /** + * Gets the nice value from a Cloudlet based on its priority. + * The nice value is the opposite of the priority. + * + *

    As "niceness" is a terminology defined by specific schedulers + * (such as Linux Schedulers), it is not defined inside the Cloudlet.

    + * + * @param cloudlet Cloudlet to get the nice value + * @return the cloudlet niceness + * @see Man Pages: Nice values for Linux processes + */ + protected double getCloudletNiceness(CloudletExecutionInfo cloudlet){ + return -cloudlet.getCloudlet().getPriority(); + } + + /** * Gets the percentage (in scale from [0 to 1]) that the weight of a Cloudlet * represents compared to the weight sum of all Cloudlets in the execution list. * @@ -299,8 +287,12 @@ public int getMininumGranularity() { * Cloudlet to execute. * * @param mininumGranularity the minimum granularity to set + * @throws IllegalArgumentException when minimum granularity is greater than latency */ public void setMininumGranularity(int mininumGranularity) { + if(mininumGranularity > latency){ + throw new IllegalArgumentException("Mininum granularity cannot be greater than latency."); + } this.mininumGranularity = mininumGranularity; } @@ -320,6 +312,9 @@ public void setMininumGranularity(int mininumGranularity) { public double processCloudletSubmit(CloudletExecutionInfo rcl, double fileTransferTime) { rcl.setVirtualRuntime(computeCloudletInitialVirtualRuntime(rcl)); rcl.setTimeSlice(computeCloudletTimeSlice(rcl)); + + /* + //Code just for debug purposes (can be deleted) if(rcl.getCloudletId() == 5) { System.out.println("\tCloudlets submitted:"); Stream.concat(getCloudletExecList().stream(), getCloudletWaitingList().stream()) @@ -327,6 +322,9 @@ public double processCloudletSubmit(CloudletExecutionInfo rcl, double fileTransf c.getCloudletId(), c.getVirtualRuntime(), c.getTimeSlice())); } + //---------------------------------------------- + */ + double result = super.processCloudletSubmit(rcl, fileTransferTime); return result; } @@ -343,7 +341,7 @@ public double updateVmProcessing(double currentTime, List mipsShare) { double nextExpiringTimeSlice = getCloudletExecList().stream() .mapToDouble(CloudletExecutionInfo::getTimeSlice) .min().orElse(Double.MAX_VALUE); - System.out.printf("\tTime %.2f updateVmProcessing - Next expiring timeslice: %.2f\n", currentTime, nextExpiringTimeSlice); + //System.out.printf("\tTime %.2f updateVmProcessing - Next expiring timeslice: %.2f\n", currentTime, nextExpiringTimeSlice); return nextExpiringTimeSlice; } @@ -416,20 +414,15 @@ public boolean canAddCloudletToExecutionList(CloudletExecutionInfo cloudlet) { return isThereEnoughFreePesForCloudlet(cloudlet); } - @Override - protected boolean removeCloudletFromWaitingList(CloudletExecutionInfo cloudlet) { - return super.removeCloudletFromWaitingList(cloudlet); - } - /** * {@inheritDoc} * - *

    Prior to start executing, a Cloudlet is added to this Collection. + *

    Prior to start executing, a Cloudlet is added to this list. * When the Cloudlet vruntime reaches its timeslice (the amount of time - * it can use the CPU), it is removed from this Collection and added + * it can use the CPU), it is removed from this list and added * back to the {@link #getCloudletWaitingList()}.

    * - *

    The sum of the PEs of Cloudlets into this Collection cannot exceeds + *

    The sum of the PEs of Cloudlets into this list cannot exceeds * the number of PEs available for the scheduler. If the sum of PEs of such Cloudlets * is less than the number of existing PEs, there are * idle PEs. Since the CPU context switch overhead is not regarded @@ -447,38 +440,13 @@ protected boolean removeCloudletFromWaitingList(CloudletExecutionInfo cloudlet) * @return */ @Override - public Collection getCloudletExecList() { + public List getCloudletExecList() { return super.getCloudletExecList(); } - /** - * Gets a read-only {@link TreeSet} (a implementation of a Red-Black Tree) that stores the list of Cloudlets - * that are waiting to run, the so called - * run queue. - * Each key in this map is the virtual runtime (vruntime), - * which indicates the amount of time the Cloudlet has run. - * This runtime increases as the Cloudlet executes, what makes - * it to change its position inside the map. - * Each value represents a Cloudlet - * running into a group of PE (defined by the number of - * PEs the Cloudlet requires). - * - *

    - * NOTE: Different from real implementations, this scheduler uses just one run queue - * for all processor cores (PEs). Since CPU context switch is not concerned, - * there is no point in using different run queues. - *

    - * - * @return - */ - @Override - public Collection getCloudletWaitingList() { - return super.getCloudletWaitingList(); - } - /** * Checks which Cloudlets in the execution list has the virtual runtime - * equals to its allocated time slice and preempt them and gets + * equals to its allocated time slice and preempt them, getting * the most priority Cloudlets in the waiting list (that is those ones * in the beginning of the list). * @@ -501,8 +469,8 @@ protected void moveNextCloudletsFromWaitingToExecList() { /** * Checks which Cloudlets in the execution list have an expired virtual - * runtime (that have reached the execution time slice) and move - * preempt its execution, moving them to the waiting list. + * runtime (that have reached the execution time slice) and + * preempts its execution, moving them to the waiting list. * * @return The list of preempted Cloudlets, that were removed from the execution list * and must have their virtual runtime reseted after the next cloudlets are put into @@ -513,14 +481,16 @@ private List preemptExecCloudletsWithExpiredVRuntimeAndMo Predicate cloudletThatVirtualRuntimeHasReachedItsTimeSlice = c -> c.getVirtualRuntime() >= c.getTimeSlice(); - Consumer printCloudlet = - c->System.out.printf("\t\tid %d vruntime %.2f timeslice: %.2f\n", - c.getCloudletId(), c.getVirtualRuntime(), c.getTimeSlice()); List expiredVRuntimeCloudlets = getCloudletExecList().stream() .filter(cloudletThatVirtualRuntimeHasReachedItsTimeSlice) .collect(toList()); + /* + //Code just for debug purposes (can be erased)-------------------------------------- + Consumer printCloudlet = + c->System.out.printf("\t\tid %d priority %d vruntime %.2f timeslice: %.2f finished so far %d\n", + c.getCloudletId(), c.getCloudlet().getPriority(), c.getVirtualRuntime(), c.getTimeSlice(), c.getCloudlet().getCloudletFinishedSoFar()); if(!getCloudletExecList().isEmpty()){ System.out.printf("\tTime %.2f - Running cloudlets: \n", CloudSim.clock()); getCloudletExecList().stream().forEach(printCloudlet); @@ -532,11 +502,11 @@ private List preemptExecCloudletsWithExpiredVRuntimeAndMo expiredVRuntimeCloudlets.stream().forEach(printCloudlet); System.out.println(); } + //---------------------------------------------------------------------------------- + */ for(CloudletExecutionInfo c: expiredVRuntimeCloudlets) { - if(!removeCloudletFromExecList(c)){ - System.out.printf("Cloudlet %d was not removed from exec list\n", c.getCloudletId()); - } + removeCloudletFromExecList(c); addCloudletToWaitingList(c); } diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceShared.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceShared.java index 0b4a60f19..187a1574a 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceShared.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceShared.java @@ -17,11 +17,15 @@ /** * CloudletSchedulerSpaceShared implements a policy of scheduling performed by a - * virtual machine to run its {@link Cloudlet Cloudlets}. It consider there will - * be only one cloudlet per VM. Other cloudlets will be in a waiting list. We - * consider that file transfer from cloudlets waiting happens before cloudlet - * execution. I.e., even though cloudlets must wait for CPU, data transfer - * happens as soon as cloudlets are submitted. + * virtual machine to run its {@link Cloudlet Cloudlets}. It considers there will + * be only one Cloudlet per VM. Other Cloudlets will be in a waiting list. It also + * considers that the time to transfer Cloudlets to the Vm happens before Cloudlet + * starts executing. I.e., even though Cloudlets must wait for CPU, data transfer + * happens as soon as Cloudlets are submitted. + * + *

    This scheduler does not consider Cloudlets priorities to + * define execution order. If actual priorities are defined for Cloudlets, they + * are just ignored by the scheduler.

    * * @author Rodrigo N. Calheiros * @author Anton Beloglazov diff --git a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeShared.java b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeShared.java index 3a883e421..775d472e4 100644 --- a/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeShared.java +++ b/cloudsim-plus/src/main/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeShared.java @@ -19,29 +19,29 @@ * CloudletSchedulerTimeShared implements a policy of scheduling performed by a * virtual machine to run its {@link Cloudlet Cloudlets}. Cloudlets execute in * time-shared manner in VM. Each VM has to have its own instance of a - * CloudletScheduler. - * - *

    CPU context switch is the process of removing an application (Cloudlets) that is using - * a CPU core ({@link Pe}) from the {@link #getCloudletExecList() run queue}, - * to allow other one in the {@link #getCloudletWaitingList() waiting queue} - * to start executing in the same CPU. - * This process enables sharing the CPU time between different applications. - *

    - * + * CloudletScheduler. This scheduler does not consider Cloudlets priorities to + * define execution order. If actual priorities are defined for Cloudlets, they + * are just ignored by the scheduler. + * *

    - * NOTE: This implementation simplifies the context switch process, not - * in fact switching cloudlets between the run queue and the waiting queue. - * It just considers there is not waiting Cloudlet, oversimplifying the - * problem as if for a simulation second t, the total processing capacity + * It also does not perform a preemption process in order to move running + * Cloudlets to the waiting list in order to make room for other already waiting + * Cloudlets to run. + * It just considers there is not waiting Cloudlet, oversimplifying the + * problem considering that for a given simulation second t, the total processing capacity * of the processor cores (in MIPS) is equally divided by the applications that are using them. - * This in fact is not possible, once just one application can use - * a CPU core at a time.

    - * - *

    However, since the basic CloudletScheduler implementations - * do not account the context switch overhead, the only impact of this oversimplification + * This in fact is not possible, once just one application can use + * a CPU core at a time. + * + * However, since this CloudletScheduler implementation + * do not account for the context switch overhead, + * the only impact of this oversimplification * is that if there are Cloudlets of the same length running in the same PEs, - * they will finish exactly at the same time, while a real time-shared scheduler + * they will finish exactly at the same time. On the other hand, on a real time-shared scheduler * these Cloudlets will finish almost in the same time. + *

    + * + *

    * As an example, consider a scheduler that has 1 PE that is able to execute * 1000 MI/S (MIPS) and is running Cloudlet 0 and Cloudlet 1, each of having 5000 MI * of length. @@ -49,19 +49,21 @@ * the time slice allocated to each Cloudlet to execute is 1 second. * As at every 1 second a different Cloudlet is allowed to run, the execution * path will be as follows:
    - * + * * Time (second): 00 01 02 03 04 05
    * Cloudlet (id): C0 C1 C0 C1 C0 C1
    - * + * * As one can see, in a real time-shared scheduler that do not define * priorities for applications, the 2 Cloudlets will in fact finish in different times. * In this example, one Cloudlet will finish 1 second after the other. *

    - * + * + * * @author Rodrigo N. Calheiros * @author Anton Beloglazov * @author Manoel Campos da Silva Filho * @since CloudSim Toolkit 1.0 + * @see CloudletSchedulerCompletelyFair */ public class CloudletSchedulerTimeShared extends CloudletSchedulerAbstract { @@ -87,10 +89,10 @@ public CloudletSchedulerTimeShared() { * @return {@inheritDoc} */ @Override - public Collection getCloudletWaitingList() { + protected List getCloudletWaitingList() { return super.getCloudletWaitingList(); } - + /** * Moves a Cloudlet that was paused and has just been resumed * to the Cloudlet execution list. @@ -123,11 +125,11 @@ public double cloudletResume(int cloudletId) { /** * {@inheritDoc} - * + * * @todo If the method always return an empty list (that is created locally), * it doesn't make sense to exist. See other implementations such as * {@link CloudletSchedulerSpaceShared#getCurrentRequestedMips()} - * + * * @return {@inheritDoc} */ @Override @@ -141,12 +143,12 @@ public List getCurrentRequestedMips() { * because in the Time Shared Scheduler, the * CPU capacity from the VM that is managed by the scheduler * is shared between all running cloudlets. - * + * * @todo if there is 2 cloudlets requiring 1 PE and there is just 1 * PE, the MIPS capacity of this PE is splited between the 2 cloudlets, * but the method seen to always return the entire capacity. * New test cases have to be created to check this. - * + * * @param rcl {@inheritDoc} * @param mipsShare {@inheritDoc} * @return {@inheritDoc} @@ -194,7 +196,7 @@ public double getCurrentRequestedUtilizationOfBw() { * It always allow any submitted Cloudlets to be immediately added to the execution list. * By this way, it doesn't matter what Cloudlet is being submitted, since it will * always include it in the execution list. - * + * * @param cloudlet the Cloudlet that will be added to the execution list. * @return always true to indicate that any submitted Cloudlet can be immediately added to the execution list */ @@ -202,5 +204,5 @@ public double getCurrentRequestedUtilizationOfBw() { public boolean canAddCloudletToExecutionList(CloudletExecutionInfo cloudlet) { return true; } - + } diff --git a/cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/CloudletsTableBuilderHelper.java b/cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/CloudletsTableBuilderHelper.java index f011cf404..4ab75f278 100644 --- a/cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/CloudletsTableBuilderHelper.java +++ b/cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/CloudletsTableBuilderHelper.java @@ -5,25 +5,25 @@ /** * A class to help printing simulation results for a list of cloudlets. - * + * * @author Manoel Campos da Silva Filho */ public class CloudletsTableBuilderHelper { - private TableBuilder printer; + private TableBuilder printer; private List cloudletList; /** * Creates new helper object to print the list of cloudlets using the a * default {@link TextTableBuilder}. * To use a different {@link TableBuilder}, use the - * {@link #setPrinter(org.cloudbus.cloudsim.util.TableBuilder)} method. - * + * {@link #setPrinter(TableBuilder)} method. + * * @param list the list of Cloudlets that the data will be included into the table to be printed - */ + */ public CloudletsTableBuilderHelper(final List list){ - this.setPrinter(new TextTableBuilder()).setCloudletList(list); + this.setPrinter(new TextTableBuilder()).setCloudletList(list); } - + /** * Builds the table with the data of the Cloudlet list and shows the results. */ @@ -31,7 +31,7 @@ public void build(){ if(printer.getTitle().isEmpty()){ printer.setTitle("SIMULATION RESULTS"); } - + createTableColumns(); cloudletList.stream().forEach(cloudlet -> addDataToRow(cloudlet, printer.newRow())); printer.print(); diff --git a/cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/PriorityCloudletsTableBuilderHelper.java b/cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/PriorityCloudletsTableBuilderHelper.java new file mode 100644 index 000000000..bd90533f9 --- /dev/null +++ b/cloudsim-plus/src/main/java/org/cloudsimplus/util/tablebuilder/PriorityCloudletsTableBuilderHelper.java @@ -0,0 +1,28 @@ +package org.cloudsimplus.util.tablebuilder; + +import org.cloudbus.cloudsim.Cloudlet; + +import java.util.List; + +/** + * A helper class to print cloudlets results as a table, including the Cloudlet priority value. + * + * @author Manoel Campos da Silva Filho + */ +public class PriorityCloudletsTableBuilderHelper extends CloudletsTableBuilderHelper { + public PriorityCloudletsTableBuilderHelper(List list) { + super(list); + } + + @Override + protected void createTableColumns() { + super.createTableColumns(); + getPrinter().addColumn("Priority"); + } + + @Override + protected void addDataToRow(Cloudlet cloudlet, List row) { + super.addDataToRow(cloudlet, row); + row.add(cloudlet.getPriority()); + } +} diff --git a/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceSharedTest.java b/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceSharedTest.java index c3999cb9f..bd75b5158 100644 --- a/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceSharedTest.java +++ b/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerSpaceSharedTest.java @@ -1,6 +1,5 @@ package org.cloudbus.cloudsim.schedulers; -import java.util.Collection; import java.util.List; import org.cloudbus.cloudsim.Cloudlet; import org.cloudbus.cloudsim.CloudletExecutionInfo; @@ -295,7 +294,7 @@ public void testGetCurrentRequestedMips_TryToChangeReturnedListThrowsException() @Test public void testGetCloudletExecList_ReturnEmptyList() { CloudletSchedulerSpaceShared instance = new CloudletSchedulerSpaceShared(); - Collection result = instance.getCloudletExecList(); + List result = instance.getCloudletExecList(); assertTrue(instance.getCloudletExecList().isEmpty()); } @@ -306,7 +305,7 @@ public void testGetCloudletExecList_SubmitedCloudletIsInExecList() { instance.setCurrentMipsShare(CloudletSchedulerUtil.createMipsList(schedulerPes, SCHEDULER_MIPS)); Cloudlet cloudlet = CloudletSimpleTest.createCloudletWithOnePe(0); instance.cloudletSubmit(cloudlet); - Collection result = instance.getCloudletExecList(); + List result = instance.getCloudletExecList(); assertTrue( instance.getCloudletExecList() diff --git a/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeSharedTest.java b/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeSharedTest.java index f680f497f..eaea2f933 100644 --- a/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeSharedTest.java +++ b/cloudsim-plus/src/test/java/org/cloudbus/cloudsim/schedulers/CloudletSchedulerTimeSharedTest.java @@ -1,8 +1,6 @@ package org.cloudbus.cloudsim.schedulers; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; import org.cloudbus.cloudsim.Cloudlet; import org.cloudbus.cloudsim.CloudletExecutionInfo; @@ -52,7 +50,7 @@ private CloudletExecutionInfo createCloudletExecInfo(int id){ @Test public void testGetCloudletWaitingList_Empty() { CloudletSchedulerTimeShared instance = new CloudletSchedulerTimeShared(); - Collection result = instance.getCloudletWaitingList(); + List result = instance.getCloudletWaitingList(); assertTrue(result.isEmpty()); } @@ -64,7 +62,7 @@ public void testGetCloudletWaitingList_EmptyAfterResumingCloudlet() { final int cloudletId = 0; createCloudletAndAddItToPausedList(instance, cloudletId, cloudletLength); instance.cloudletResume(cloudletId); - Collection result = instance.getCloudletWaitingList(); + List result = instance.getCloudletWaitingList(); assertTrue(result.isEmpty()); } @@ -230,7 +228,7 @@ private CloudletSchedulerTimeShared createCloudletSchedulerWithListOfExecCloudle @Test public void testGetCloudletExecList_Empty() { CloudletSchedulerTimeShared instance = new CloudletSchedulerTimeShared(); - Collection result = instance.getCloudletExecList(); + List result = instance.getCloudletExecList(); assertTrue(result.isEmpty()); }