Unverified Commit 84f58c0a authored by Manoel Campos's avatar Manoel Campos
Browse files

Closes #130


Signed-off-by: default avatarManoel Campos <manoelcampos@gmail.com>
parent 622d1beb
......@@ -4,7 +4,7 @@
<groupId>org.cloudsimplus</groupId>
<artifactId>cloudsim-plus-benchmarks</artifactId>
<version>2.2.2</version>
<version>2.3.0</version>
<name>CloudSim Plus Benchmarks</name>
<description>A module containing benchmarks created using JMH (Java Microbenchmark Harness framework) to assess CloudSim Plus performance</description>
<url>http://cloudsimplus.org</url>
......
......@@ -4,7 +4,7 @@
<groupId>org.cloudsimplus</groupId>
<artifactId>cloudsim-plus-examples</artifactId>
<version>2.2.2</version>
<version>2.3.0</version>
<name>CloudSim Plus Examples</name>
<description>
Ready-to-run examples of how to use CloudSim Plus API.
......
......@@ -58,7 +58,7 @@ import java.util.List;
* An example showing how to create Hosts at simulation runtime,
* enabling to simulate the physical expansion of a Datacenter by
* the addition of new Hosts (PMs).
* The exemple starts by creating 2 hosts and 4 VMs (2 VMs for each Host).
* The example starts by creating 2 hosts and 4 VMs (2 VMs for each Host).
* Then it creates 4 Cloudlets (1 for each VM).
*
* <p>After the simulation starts and reaches 5 seconds (defined in {@link #SCHEDULING_INTERVAL}),
......
/*
* CloudSim Plus: A modern, highly-extensible and easier-to-use Framework for
* Modeling and Simulation of Cloud Computing Infrastructures and Services.
* http://cloudsimplus.org
*
* Copyright (C) 2015-2018 Universidade da Beira Interior (UBI, Portugal) and
* the Instituto Federal de Educação Ciência e Tecnologia do Tocantins (IFTO, Brazil).
*
* This file is part of CloudSim Plus.
*
* CloudSim Plus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CloudSim Plus is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CloudSim Plus. If not, see <http://www.gnu.org/licenses/>.
*/
package org.cloudsimplus.examples.dynamic;
import org.cloudbus.cloudsim.allocationpolicies.VmAllocationPolicySimple;
import org.cloudbus.cloudsim.brokers.DatacenterBroker;
import org.cloudbus.cloudsim.brokers.DatacenterBrokerSimple;
import org.cloudbus.cloudsim.cloudlets.Cloudlet;
import org.cloudbus.cloudsim.cloudlets.CloudletSimple;
import org.cloudbus.cloudsim.core.CloudSim;
import org.cloudbus.cloudsim.core.Simulation;
import org.cloudbus.cloudsim.datacenters.Datacenter;
import org.cloudbus.cloudsim.datacenters.DatacenterSimple;
import org.cloudbus.cloudsim.hosts.Host;
import org.cloudbus.cloudsim.hosts.HostSimple;
import org.cloudbus.cloudsim.provisioners.PeProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.ResourceProvisionerSimple;
import org.cloudbus.cloudsim.resources.Pe;
import org.cloudbus.cloudsim.resources.PeSimple;
import org.cloudbus.cloudsim.schedulers.cloudlet.CloudletSchedulerTimeShared;
import org.cloudbus.cloudsim.schedulers.vm.VmSchedulerTimeShared;
import org.cloudbus.cloudsim.util.Log;
import org.cloudbus.cloudsim.utilizationmodels.UtilizationModelFull;
import org.cloudbus.cloudsim.vms.Vm;
import org.cloudbus.cloudsim.vms.VmSimple;
import org.cloudsimplus.builders.tables.CloudletsTableBuilder;
import org.cloudsimplus.listeners.EventInfo;
import org.cloudsimplus.listeners.EventListener;
import java.util.ArrayList;
import java.util.List;
/**
* Shows how to keep the simulation running, even
* if there is no event to be processed anymore.
* It calls the {@link Simulation#terminateAt(double)} to define
* the time when the simulation must be terminated.
*
* <p>The example is useful when you want to run a simulation
* for a specific amount of time.
* For instance, if you want to run a simulation for 24 hours,
* you just need to call {@code simulation.terminateAt(60*60*24)} (realize the value is in seconds).</p>
*
* <p>The example creates 4 Cloudlets and 2 VMs statically.
* These Cloudlets will take 10 seconds to finish, but
* the simulation is set to terminate
* only after that ({@link #TIME_TO_TERMINATE_SIMULATION}).
* This way, the simulation keeps waiting for dynamically
* arrived events (such as creation of VMs and Cloudlets in runtime).
* </p>
*
* <p>The example uses the CloudSim Plus {@link EventListener} feature
* to enable monitoring the simulation and dynamically create Cloudlets and VMs at runtime.
* It relies on
* <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html">Java 8 Method References</a>
* to set a method to be called for {@link Simulation#addOnClockTickListener(EventListener) onClockTick events}.
* It enables getting notifications when the simulation clock advances, then creating and submitting new cloudlets.
* </p>
*
* <p>Since the simulation was set to keep waiting for new events
* until a defined time, the simulation clock will be updated
* even if no event arrives, to simulate time passing.
* Check the {@link Simulation#terminateAt(double)} for details.
* </p>
*
* <p>At the time defined in {@link #TIME_TO_CREATE_NEW_CLOUDLET},
* 1 Cloudlet and 1 VM is created, so the results will show 5 Cloudlets.
* The simulation will just end at the specified time.
* </p>
*
* @author Manoel Campos da Silva Filho
* @since CloudSim Plus 2.3.0
*/
public class KeepSimulationRunningExample {
private static final int TIME_TO_CREATE_NEW_CLOUDLET = 15;
private static final int TIME_TO_TERMINATE_SIMULATION = TIME_TO_CREATE_NEW_CLOUDLET*2;
/**
* @see Datacenter#getSchedulingInterval()
*/
private static final int SCHEDULING_INTERVAL = 1;
private static final int HOSTS = 1;
private static final int HOST_PES = 8;
private static final int VMS = 2;
private static final int VM_PES = 4;
private static final int CLOUDLETS = 4;
private static final int CLOUDLET_PES = 2;
private static final int CLOUDLET_LENGTH = 10000;
private final CloudSim simulation;
private DatacenterBroker broker0;
private List<Vm> vmList;
private List<Cloudlet> cloudletList;
private Datacenter datacenter0;
public static void main(String[] args) {
new KeepSimulationRunningExample();
}
public KeepSimulationRunningExample() {
simulation = new CloudSim();
simulation.terminateAt(TIME_TO_TERMINATE_SIMULATION);
datacenter0 = createDatacenter();
//Creates a broker that is a software acting on behalf a cloud customer to manage his/her VMs and Cloudlets
broker0 = new DatacenterBrokerSimple(simulation);
vmList = createVms();
cloudletList = createCloudlets();
broker0.submitVmList(vmList);
broker0.submitCloudletList(cloudletList);
simulation.addOnClockTickListener(this::createDynamicCloudletAndVm);
simulation.start();
final List<Cloudlet> finishedCloudlets = broker0.getCloudletFinishedList();
new CloudletsTableBuilder(finishedCloudlets).build();
}
/**
* Creates a Datacenter and its Hosts.
*/
private Datacenter createDatacenter() {
final List<Host> hostList = new ArrayList<>(HOSTS);
for(int i = 0; i < HOSTS; i++) {
Host host = createHost();
hostList.add(host);
}
final Datacenter dc = new DatacenterSimple(simulation, hostList, new VmAllocationPolicySimple());
dc.setSchedulingInterval(SCHEDULING_INTERVAL);
return dc;
}
private Host createHost() {
List<Pe> peList = new ArrayList<>(HOST_PES);
//List of Host's CPUs (Processing Elements, PEs)
for (int i = 0; i < HOST_PES; i++) {
peList.add(new PeSimple(1000, new PeProvisionerSimple()));
}
final long ram = 2048; //in Megabytes
final long bw = 10000; //in Megabits/s
final long storage = 1000000; //in Megabytes
Host host = new HostSimple(ram, bw, storage, peList);
host
.setRamProvisioner(new ResourceProvisionerSimple())
.setBwProvisioner(new ResourceProvisionerSimple())
.setVmScheduler(new VmSchedulerTimeShared());
return host;
}
/**
* Creates a list of VMs.
*/
private List<Vm> createVms() {
final List<Vm> list = new ArrayList<>(VMS);
for (int i = 0; i < VMS; i++) {
list.add(createVm());
}
return list;
}
private Vm createVm() {
return new VmSimple(1000, VM_PES)
.setRam(512).setBw(1000).setSize(10000)
.setCloudletScheduler(new CloudletSchedulerTimeShared());
}
/**
* Creates a list of Cloudlets.
*/
private List<Cloudlet> createCloudlets() {
final List<Cloudlet> list = new ArrayList<>(CLOUDLETS);
for (int i = 0; i < CLOUDLETS; i++) {
list.add(createCloudlet());
}
return list;
}
private Cloudlet createCloudlet() {
return new CloudletSimple(CLOUDLET_LENGTH, CLOUDLET_PES)
.setFileSize(1024)
.setOutputSize(1024)
.setUtilizationModel(new UtilizationModelFull());
}
/**
* Simulates the dynamic arrival of a Cloudlet and a VM during simulation runtime.
* @param evt
*/
private void createDynamicCloudletAndVm(EventInfo evt) {
if((int)evt.getTime() == TIME_TO_CREATE_NEW_CLOUDLET){
Log.printFormattedLine("\n# Dynamically creating 1 Cloudlet and 1 VM at time %.2f\n", evt.getTime());
Vm vm = createVm();
vmList.add(vm);
Cloudlet cloudlet = createCloudlet();
cloudletList.add(cloudlet);
broker0.submitVm(vm);
broker0.submitCloudlet(cloudlet);
}
}
}
......@@ -4,7 +4,7 @@
<groupId>org.cloudsimplus</groupId>
<artifactId>cloudsim-plus-testbeds</artifactId>
<version>2.2.2</version>
<version>2.3.0</version>
<name>CloudSim Plus Testbeds</name>
<description>
A set of more complex and comprehensive CloudSim Plus testbeds used to assess
......
......@@ -4,7 +4,7 @@
<groupId>org.cloudsimplus</groupId>
<artifactId>cloudsim-plus</artifactId>
<version>2.2.2</version>
<version>2.3.0</version>
<name>CloudSim Plus API</name>
<description>CloudSim Plus: A modern, highly extensible and easier-to-use Java 8 Framework for Modeling and Simulation of Cloud Computing Infrastructures and Services</description>
<url>http://cloudsimplus.org</url>
......
......@@ -40,7 +40,7 @@ public interface DatacenterBroker extends SimEntity {
DatacenterBroker NULL = new DatacenterBrokerNull();
/**
* A default delay value to indicate that any VM should <b>NOT</b> be
* A default delay value to indicate that <b>no</b> VM should be
* immediately destroyed after it becomes idle.
*
* <p>This is used as the default value returned by the {@link #getVmDestructionDelayFunction()}
......
......@@ -850,7 +850,7 @@ public abstract class DatacenterBrokerAbstract extends CloudSimEntity implements
@Override
public void shutdownEntity() {
println(String.format("%s is shutting down...", getName()));
println(String.format("%.2f: %s is shutting down...", getSimulation().clock(), getName()));
}
@Override
......
......@@ -85,7 +85,14 @@ public class CloudInformationService extends CloudSimEntity {
@Override
public void shutdownEntity() {
notifyAllEntity();
Log.printConcatLine(super.getName(), ": Notify all CloudSim Plus entities to shutdown.");
signalShutdown(datacenterList);
signalShutdown(cisList);
// reset the values
datacenterList.clear();
cisList.clear();
}
/**
......@@ -99,23 +106,6 @@ public class CloudInformationService extends CloudSimEntity {
return datacenterList;
}
/**
* Tells all registered entities about the end of simulation.
*
* @pre $none
* @post $none
*/
private void notifyAllEntity() {
Log.printConcatLine(super.getName(), ": Notify all CloudSim Plus entities to shutdown.");
signalShutdown(datacenterList);
signalShutdown(cisList);
// reset the values
datacenterList.clear();
cisList.clear();
}
/**
* Sends a {@link CloudSimTags#END_OF_SIMULATION} signal to all entity IDs
* mentioned in the given list.
......
......@@ -35,7 +35,7 @@ public class CloudSim implements Simulation {
/**
* CloudSim Plus current version.
*/
public static final String VERSION = "2.2.2";
public static final String VERSION = "2.3.0";
/**
* An array that works as a circular queue with capacity for just 2 elements
......@@ -79,7 +79,7 @@ public class CloudSim implements Simulation {
private final Calendar calendar;
/**
* The time the simulation should be terminated.
* The time the simulation should be terminated (in seconds).
*/
private double terminationTime = -1;
......@@ -104,9 +104,9 @@ public class CloudSim implements Simulation {
private final DeferredQueue deferred;
/**
* The current simulation clock.
* @see #clock()
*/
private double clockTime;
private double clock;
/**
* @see #isRunning()
......@@ -175,7 +175,7 @@ public class CloudSim implements Simulation {
this.deferred = new DeferredQueue();
this.waitPredicates = new HashMap<>();
this.networkTopology = NetworkTopology.NULL;
this.clockTime = 0;
this.clock = 0;
this.running = false;
this.alreadyRunOnce = false;
this.onEventProcessingListeners = new HashSet<>();
......@@ -209,22 +209,36 @@ public class CloudSim implements Simulation {
while (running) {
runClockTickAndProcessFutureEventQueue();
if(abortRequested){
printMessage("\n================== Simulation aborted under request at time "+ clock +" ==================");
return clock;
}
if (isThereRequestToTerminateSimulationAndWasItFulfilled()) {
Log.printFormattedLine(
"\nSimulation finished at time %.2f, before completing, in reason of an explicit request to terminate() or terminateAt().\n", clockTime);
if (terminateSimulationUnderRequest()) {
break;
}
checkIfThereIsRequestToPauseSimulation();
checkIfSimulationPauseRequested();
}
final double lastSimulationTime = clock();
finishSimulation();
printMessage("Simulation completed.");
printSimulationFinished();
return clock;
}
private void printSimulationFinished() {
final String msg1 = "Simulation finished at time "+ clock;
final String extra = future.isEmpty() ? "" : ", before completing,";
final String msg2 = isTimeToTerminateSimulationUnderRequest()
? extra + " in reason of an explicit request to terminate() or terminateAt()"
: "";
Log.printFormattedLine("\n================== %s%s ==================\n", msg1, msg2);
}
return lastSimulationTime;
private boolean isTimeToTerminateSimulationUnderRequest() {
return isTerminationTimeSet() && clock >= terminationTime;
}
@Override
......@@ -239,7 +253,7 @@ public class CloudSim implements Simulation {
@Override
public boolean terminateAt(final double time) {
if (time <= clockTime) {
if (time <= clock) {
return false;
}
......@@ -269,7 +283,7 @@ public class CloudSim implements Simulation {
@Override
public double clock() {
return clockTime;
return clock;
}
@Override
......@@ -283,13 +297,18 @@ public class CloudSim implements Simulation {
}
/**
* Updates the simulation clock
* Updates the simulation clock and notify listeners
* if the clock has changed.
* @param newTime simulation time to set
* @return the old simulation time
*
* @see #onClockTickListeners
*/
private double setClock(final double newTime){
final double oldTime = clockTime;
this.clockTime = newTime;
final double oldTime = clock;
this.clock = newTime;
notifyOnClockTickListenersIfClockChanged();
return oldTime;
}
......@@ -307,7 +326,7 @@ public class CloudSim implements Simulation {
public void addEntity(final CloudSimEntity e) {
if (running) {
//@todo src 1, dest 0? What did it mean? Probably nothing.
final SimEvent evt = new CloudSimEvent(this, SimEvent.Type.CREATE, clockTime, e);
final SimEvent evt = new CloudSimEvent(this, SimEvent.Type.CREATE, clock, e);
future.addEvent(evt);
}
......@@ -323,16 +342,46 @@ public class CloudSim implements Simulation {
*/
private void runClockTickAndProcessFutureEventQueue() {
executeRunnableEntities();
if (future.isEmpty()) {
if (!future.isEmpty()) {
future.stream().findFirst().ifPresent(this::processFutureEventsHappeningAtSameTimeOfTheFirstOne);
return;
}
if(isTerminationTimeSet()){
Log.printFormattedLine(
"%.2f: Simulation: Waiting more events or the clock to reach %.2f (the termination time set).",
clock, terminationTime);
final double increment = minDatacentersSchedulingInterval();
final String info = increment == minTimeBetweenEvents
? "using getMinTimeBetweenEvents() since a Datacenter schedulingInterval was not set"
: "Datacenter.getSchedulingInterval()";
Log.printFormattedLine(" Checking new events in %.2f seconds (%s)", increment, info);
setClock(clock + increment);
}
else {
running = false;
printMessage("Simulation: No more future events");
} else {
// If there are more future events, then deal with them
future.stream().findFirst().ifPresent(this::processAllFutureEventsHappeningAtSameTimeOfTheFirstOne);
}
}
private void processAllFutureEventsHappeningAtSameTimeOfTheFirstOne(final SimEvent firstEvent) {
/**
* Gets the minimum {@link Datacenter#getSchedulingInterval()} defined
* among all existing Datacenters.
*
* @return the minimum {@link Datacenter#getSchedulingInterval()}
* between all Datacenters or {@link #getMinTimeBetweenEvents()}
* in case no Datacenter has its scheduling interval set
*/
private double minDatacentersSchedulingInterval() {
return cis
.getDatacenterList()
.stream()
.mapToDouble(Datacenter::getSchedulingInterval)
.filter(interval -> interval > 0)
.min().orElse(minTimeBetweenEvents);
}
private void processFutureEventsHappeningAtSameTimeOfTheFirstOne(final SimEvent firstEvent) {
processEvent(firstEvent);
future.remove(firstEvent);
......@@ -366,14 +415,14 @@ public class CloudSim implements Simulation {
@Override
public void send(final SimEntity src, final SimEntity dest, final double delay, final int tag, final Object data) {
validateDelay(delay);
final SimEvent evt = new CloudSimEvent(this, SimEvent.Type.SEND, clockTime + delay, src, dest, tag, data);
final SimEvent evt = new CloudSimEvent(this, SimEvent.Type.SEND, clock + delay, src, dest, tag, data);
future.addEvent(evt);
}
@Override
public void sendFirst(final SimEntity src, final SimEntity dest, final double delay, final int tag, final Object data) {
validateDelay(delay);
final SimEvent evt = new CloudSimEvent(this, SimEvent.Type.SEND, clockTime + delay, src, dest, tag, data);
final SimEvent evt = new CloudSimEvent(this, SimEvent.Type.SEND, clock + delay, src, dest, tag, data);
future.addEventFirst(evt);
}
......@@ -467,14 +516,12 @@ public class CloudSim implements Simulation {
* @param e the event to be processed
*/
private void processEvent(final SimEvent e) {
// Update the system's clock
if (e.eventTime() < clockTime) {
if (e.eventTime() < clock) {
throw new IllegalArgumentException("Past event detected.");
}
setClock(e.eventTime());
processEventByType(e);
notifyOnClockTickListenersIfClockChanged();
notifyOnEventProcessingListeners(e);
}
......@@ -487,7 +534,7 @@ public class CloudSim implements Simulation {
* the Listeners will have access to the most updated simulation state.
*/
private void notifyOnClockTickListenersIfClockChanged() {
if(clockTime > lastTimeClockTickListenersUpdated) {
if(clock > lastTimeClockTickListenersUpdated) {
addCurrentTimeToCircularQueue();
if (circularClockTimeQueue[0] < circularClockTimeQueue[1])
{
......@@ -503,7 +550,7 @@ public class CloudSim implements Simulation {
*/
private void addCurrentTimeToCircularQueue() {
circularClockTimeQueue[0] = circularClockTimeQueue[1];
circularClockTimeQueue[1] = clockTime;
circularClockTimeQueue[1] = clock;
}
private void processEventByType(final SimEvent e) {
......@@ -534,7 +581,7 @@ public class CloudSim implements Simulation {
*
* @param e The new entity
*/
protected void addEntityDynamically(final SimEntity e) {
private void addEntityDynamically(final SimEntity e) {
Objects.requireNonNull(e);
printMessage("Adding: " + e.getName());