/* * Title: CloudSim Toolkit * Description: CloudSim (Cloud Simulation) Toolkit for Modeling and Simulation of Clouds * Licence: GPL - http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2009-2012, The University of Melbourne, Australia */ package org.cloudbus.cloudsim.network.datacenter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.cloudbus.cloudsim.Cloudlet; import org.cloudbus.cloudsim.CloudletScheduler; import org.cloudbus.cloudsim.ResCloudlet; import org.cloudbus.cloudsim.core.CloudSim; import org.cloudbus.cloudsim.core.CloudSimTags; /** * CloudletSchedulerSpaceShared implements a policy of scheduling performed by a virtual machine * to run its {@link Cloudlet Cloudlets}. * It consider that 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. * * Each VM has to have its own instance of a CloudletScheduler. * * @author Saurabh Kumar Garg * @author Saurabh Kumar Garg * @since CloudSim Toolkit 3.0 * @todo Attributes should be private */ public class NetworkCloudletSpaceSharedScheduler extends CloudletScheduler { /** The current CPUs. */ protected int currentCpus; /** The used PEs. */ protected int usedPes; /** * The map of packets to send, where each key is a destination VM * and each value is the list of packets to sent to that VM. */ public Map<Integer, List<HostPacket>> pkttosend; /** * The map of packets received, where each key is a sender VM * and each value is the list of packets sent by that VM. */ public Map<Integer, List<HostPacket>> pktrecv; /** * Creates a new CloudletSchedulerSpaceShared object. * This method must be invoked before starting the actual simulation. * * @pre $none * @post $none */ public NetworkCloudletSpaceSharedScheduler() { super(); cloudletWaitingList = new ArrayList<ResCloudlet>(); cloudletExecList = new ArrayList<ResCloudlet>(); cloudletPausedList = new ArrayList<ResCloudlet>(); cloudletFinishedList = new ArrayList<ResCloudlet>(); usedPes = 0; currentCpus = 0; pkttosend = new HashMap<Integer, List<HostPacket>>(); pktrecv = new HashMap<Integer, List<HostPacket>>(); } @Override public double updateVmProcessing(double currentTime, List<Double> mipsShare) { /*@todo Method to long. Several "extract method" refactorings may be performed.*/ setCurrentMipsShare(mipsShare); // update double capacity = 0.0; int cpus = 0; for (Double mips : mipsShare) { // count the CPUs available to the VMM capacity += mips; if (mips > 0) { cpus++; } } currentCpus = cpus; capacity /= cpus; // average capacity of each cpu for (ResCloudlet rcl : getCloudletExecList()) { // each machine in the // exec list has the // same amount of cpu NetworkCloudlet cl = (NetworkCloudlet) rcl.getCloudlet(); // check status // if execution stage // update the cloudlet finishtime // CHECK WHETHER IT IS WAITING FOR THE PACKET // if packet received change the status of job and update the time. // if ((cl.currStagenum != -1)) { if (cl.currStagenum == NetworkConstants.FINISH) { break; } TaskStage st = cl.stages.get(cl.currStagenum); if (st.type == NetworkConstants.EXECUTION) { // update the time cl.timespentInStage = Math.round(CloudSim.clock() - cl.timetostartStage); if (cl.timespentInStage >= st.time) { changetonextstage(cl, st); // change the stage } } if (st.type == NetworkConstants.WAIT_RECV) { List<HostPacket> pktlist = pktrecv.get(st.peer); List<HostPacket> pkttoremove = new ArrayList<HostPacket>(); if (pktlist != null) { Iterator<HostPacket> it = pktlist.iterator(); HostPacket pkt = null; if (it.hasNext()) { pkt = it.next(); // Asumption packet will not arrive in the same cycle if (pkt.reciever == cl.getVmId()) { pkt.recievetime = CloudSim.clock(); st.time = CloudSim.clock() - pkt.sendtime; changetonextstage(cl, st); pkttoremove.add(pkt); } } pktlist.removeAll(pkttoremove); // if(pkt!=null) // else wait for recieving the packet } } } else { cl.currStagenum = 0; cl.timetostartStage = CloudSim.clock(); if (cl.stages.get(0).type == NetworkConstants.EXECUTION) { NetDatacenterBroker.linkDC.schedule( NetDatacenterBroker.linkDC.getId(), cl.stages.get(0).time, CloudSimTags.VM_DATACENTER_EVENT); } else { NetDatacenterBroker.linkDC.schedule( NetDatacenterBroker.linkDC.getId(), 0.0001, CloudSimTags.VM_DATACENTER_EVENT); // /sendstage/// } } } if (getCloudletExecList().size() == 0 && getCloudletWaitingList().size() == 0) { // no // more cloudlets in this scheduler setPreviousTime(currentTime); return 0.0; } // update each cloudlet int finished = 0; List<ResCloudlet> toRemove = new ArrayList<ResCloudlet>(); for (ResCloudlet rcl : getCloudletExecList()) { // rounding issue... if (((NetworkCloudlet) (rcl.getCloudlet())).currStagenum == NetworkConstants.FINISH) { // stage is changed and packet to send ((NetworkCloudlet) (rcl.getCloudlet())).finishtime = CloudSim.clock(); toRemove.add(rcl); cloudletFinish(rcl); finished++; } } getCloudletExecList().removeAll(toRemove); // add all the CloudletExecList in waitingList. // sort the waitinglist // for each finished cloudlet, add a new one from the waiting list if (!getCloudletWaitingList().isEmpty()) { for (int i = 0; i < finished; i++) { toRemove.clear(); for (ResCloudlet rcl : getCloudletWaitingList()) { if ((currentCpus - usedPes) >= rcl.getNumberOfPes()) { rcl.setCloudletStatus(Cloudlet.INEXEC); for (int k = 0; k < rcl.getNumberOfPes(); k++) { rcl.setMachineAndPeId(0, i); } getCloudletExecList().add(rcl); usedPes += rcl.getNumberOfPes(); toRemove.add(rcl); break; } } getCloudletWaitingList().removeAll(toRemove); }// for(cont) } // estimate finish time of cloudlets in the execution queue double nextEvent = Double.MAX_VALUE; for (ResCloudlet rcl : getCloudletExecList()) { double remainingLength = rcl.getRemainingCloudletLength(); double estimatedFinishTime = currentTime + (remainingLength / (capacity * rcl.getNumberOfPes())); if (estimatedFinishTime - currentTime < CloudSim.getMinTimeBetweenEvents()) { estimatedFinishTime = currentTime + CloudSim.getMinTimeBetweenEvents(); } if (estimatedFinishTime < nextEvent) { nextEvent = estimatedFinishTime; } } setPreviousTime(currentTime); return nextEvent; } /** * Changes a cloudlet to the next stage. * * @todo It has to be corrected the method name case. Method too long * to understand what is its responsibility.*/ private void changetonextstage(NetworkCloudlet cl, TaskStage st) { cl.timespentInStage = 0; cl.timetostartStage = CloudSim.clock(); int currstage = cl.currStagenum; if (currstage >= (cl.stages.size() - 1)) { cl.currStagenum = NetworkConstants.FINISH; } else { cl.currStagenum = currstage + 1; int i = 0; for (i = cl.currStagenum; i < cl.stages.size(); i++) { if (cl.stages.get(i).type == NetworkConstants.WAIT_SEND) { HostPacket pkt = new HostPacket( cl.getVmId(), cl.stages.get(i).peer, cl.stages.get(i).data, CloudSim.clock(), -1, cl.getCloudletId(), cl.stages.get(i).vpeer); List<HostPacket> pktlist = pkttosend.get(cl.getVmId()); if (pktlist == null) { pktlist = new ArrayList<HostPacket>(); } pktlist.add(pkt); pkttosend.put(cl.getVmId(), pktlist); } else { break; } } NetDatacenterBroker.linkDC.schedule( NetDatacenterBroker.linkDC.getId(), 0.0001, CloudSimTags.VM_DATACENTER_EVENT); if (i == cl.stages.size()) { cl.currStagenum = NetworkConstants.FINISH; } else { cl.currStagenum = i; if (cl.stages.get(i).type == NetworkConstants.EXECUTION) { NetDatacenterBroker.linkDC.schedule( NetDatacenterBroker.linkDC.getId(), cl.stages.get(i).time, CloudSimTags.VM_DATACENTER_EVENT); } } } } @Override public Cloudlet cloudletCancel(int cloudletId) { // First, looks in the finished queue for (ResCloudlet rcl : getCloudletFinishedList()) { if (rcl.getCloudletId() == cloudletId) { getCloudletFinishedList().remove(rcl); return rcl.getCloudlet(); } } // Then searches in the exec list for (ResCloudlet rcl : getCloudletExecList()) { if (rcl.getCloudletId() == cloudletId) { getCloudletExecList().remove(rcl); if (rcl.getRemainingCloudletLength() == 0.0) { cloudletFinish(rcl); } else { rcl.setCloudletStatus(Cloudlet.CANCELED); } return rcl.getCloudlet(); } } // Now, looks in the paused queue for (ResCloudlet rcl : getCloudletPausedList()) { if (rcl.getCloudletId() == cloudletId) { getCloudletPausedList().remove(rcl); return rcl.getCloudlet(); } } // Finally, looks in the waiting list for (ResCloudlet rcl : getCloudletWaitingList()) { if (rcl.getCloudletId() == cloudletId) { rcl.setCloudletStatus(Cloudlet.CANCELED); getCloudletWaitingList().remove(rcl); return rcl.getCloudlet(); } } return null; } @Override public boolean cloudletPause(int cloudletId) { boolean found = false; int position = 0; // first, looks for the cloudlet in the exec list for (ResCloudlet rcl : getCloudletExecList()) { if (rcl.getCloudletId() == cloudletId) { found = true; break; } position++; } if (found) { // moves to the paused list ResCloudlet rgl = getCloudletExecList().remove(position); if (rgl.getRemainingCloudletLength() == 0.0) { cloudletFinish(rgl); } else { rgl.setCloudletStatus(Cloudlet.PAUSED); getCloudletPausedList().add(rgl); } return true; } // now, look for the cloudlet in the waiting list position = 0; found = false; for (ResCloudlet rcl : getCloudletWaitingList()) { if (rcl.getCloudletId() == cloudletId) { found = true; break; } position++; } if (found) { // moves to the paused list ResCloudlet rgl = getCloudletWaitingList().remove(position); if (rgl.getRemainingCloudletLength() == 0.0) { cloudletFinish(rgl); } else { rgl.setCloudletStatus(Cloudlet.PAUSED); getCloudletPausedList().add(rgl); } return true; } return false; } @Override public void cloudletFinish(ResCloudlet rcl) { rcl.setCloudletStatus(Cloudlet.SUCCESS); rcl.finalizeCloudlet(); getCloudletFinishedList().add(rcl); usedPes -= rcl.getNumberOfPes(); } @Override public double cloudletResume(int cloudletId) { boolean found = false; int position = 0; // look for the cloudlet in the paused list for (ResCloudlet rcl : getCloudletPausedList()) { if (rcl.getCloudletId() == cloudletId) { found = true; break; } position++; } if (found) { ResCloudlet rcl = getCloudletPausedList().remove(position); // it can go to the exec list if ((currentCpus - usedPes) >= rcl.getNumberOfPes()) { rcl.setCloudletStatus(Cloudlet.INEXEC); for (int i = 0; i < rcl.getNumberOfPes(); i++) { rcl.setMachineAndPeId(0, i); } long size = rcl.getRemainingCloudletLength(); size *= rcl.getNumberOfPes(); rcl.getCloudlet().setCloudletLength(size); getCloudletExecList().add(rcl); usedPes += rcl.getNumberOfPes(); // calculate the expected time for cloudlet completion double capacity = 0.0; int cpus = 0; for (Double mips : getCurrentMipsShare()) { capacity += mips; if (mips > 0) { cpus++; } } currentCpus = cpus; capacity /= cpus; long remainingLength = rcl.getRemainingCloudletLength(); double estimatedFinishTime = CloudSim.clock() + (remainingLength / (capacity * rcl.getNumberOfPes())); return estimatedFinishTime; } else {// no enough free PEs: go to the waiting queue rcl.setCloudletStatus(Cloudlet.QUEUED); long size = rcl.getRemainingCloudletLength(); size *= rcl.getNumberOfPes(); rcl.getCloudlet().setCloudletLength(size); getCloudletWaitingList().add(rcl); return 0.0; } } // not found in the paused list: either it is in in the queue, executing // or not exist return 0.0; } @Override public double cloudletSubmit(Cloudlet cloudlet, double fileTransferTime) { // it can go to the exec list if ((currentCpus - usedPes) >= cloudlet.getNumberOfPes()) { ResCloudlet rcl = new ResCloudlet(cloudlet); rcl.setCloudletStatus(Cloudlet.INEXEC); for (int i = 0; i < cloudlet.getNumberOfPes(); i++) { rcl.setMachineAndPeId(0, i); } getCloudletExecList().add(rcl); usedPes += cloudlet.getNumberOfPes(); } else {// no enough free PEs: go to the waiting queue ResCloudlet rcl = new ResCloudlet(cloudlet); rcl.setCloudletStatus(Cloudlet.QUEUED); getCloudletWaitingList().add(rcl); return 0.0; } // calculate the expected time for cloudlet completion double capacity = 0.0; int cpus = 0; for (Double mips : getCurrentMipsShare()) { capacity += mips; if (mips > 0) { cpus++; } } currentCpus = cpus; capacity /= cpus; // use the current capacity to estimate the extra amount of // time to file transferring. It must be added to the cloudlet length double extraSize = capacity * fileTransferTime; long length = cloudlet.getCloudletLength(); length += extraSize; cloudlet.setCloudletLength(length); return cloudlet.getCloudletLength() / capacity; } @Override public double cloudletSubmit(Cloudlet cloudlet) { cloudletSubmit(cloudlet, 0); return 0; } @Override public int getCloudletStatus(int cloudletId) { for (ResCloudlet rcl : getCloudletExecList()) { if (rcl.getCloudletId() == cloudletId) { return rcl.getCloudletStatus(); } } for (ResCloudlet rcl : getCloudletPausedList()) { if (rcl.getCloudletId() == cloudletId) { return rcl.getCloudletStatus(); } } for (ResCloudlet rcl : getCloudletWaitingList()) { if (rcl.getCloudletId() == cloudletId) { return rcl.getCloudletStatus(); } } return -1; } @Override public double getTotalUtilizationOfCpu(double time) { double totalUtilization = 0; for (ResCloudlet gl : getCloudletExecList()) { totalUtilization += gl.getCloudlet().getUtilizationOfCpu(time); } return totalUtilization; } @Override public boolean isFinishedCloudlets() { return getCloudletFinishedList().size() > 0; } @Override public Cloudlet getNextFinishedCloudlet() { if (getCloudletFinishedList().size() > 0) { return getCloudletFinishedList().remove(0).getCloudlet(); } return null; } @Override public int runningCloudlets() { return getCloudletExecList().size(); } @Override public Cloudlet migrateCloudlet() { ResCloudlet rcl = getCloudletExecList().remove(0); rcl.finalizeCloudlet(); Cloudlet cl = rcl.getCloudlet(); usedPes -= cl.getNumberOfPes(); return cl; } @Override public List<Double> getCurrentRequestedMips() { List<Double> mipsShare = new ArrayList<Double>(); if (getCurrentMipsShare() != null) { for (Double mips : getCurrentMipsShare()) { mipsShare.add(mips); } } return mipsShare; } @Override public double getTotalCurrentAvailableMipsForCloudlet(ResCloudlet rcl, List<Double> mipsShare) { /*@todo The param rcl is not being used.*/ double capacity = 0.0; int cpus = 0; for (Double mips : mipsShare) { // count the cpus available to the vmm capacity += mips; if (mips > 0) { cpus++; } } currentCpus = cpus; capacity /= cpus; // average capacity of each cpu return capacity; } @Override public double getTotalCurrentAllocatedMipsForCloudlet(ResCloudlet rcl, double time) { //@todo The method doesn't appear to be implemented in fact return 0.0; } @Override public double getTotalCurrentRequestedMipsForCloudlet(ResCloudlet rcl, double time) { //@todo The method doesn't appear to be implemented in fact return 0.0; } @Override public double getCurrentRequestedUtilizationOfBw() { //@todo The method doesn't appear to be implemented in fact return 0; } @Override public double getCurrentRequestedUtilizationOfRam() { //@todo The method doesn't appear to be implemented in fact return 0; } }