/** * Copyright 2012-2013 University Of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.workflowsim; import java.util.HashMap; import java.util.List; import org.cloudbus.cloudsim.Cloudlet; import org.cloudbus.cloudsim.DatacenterBroker; import org.cloudbus.cloudsim.Log; import org.cloudbus.cloudsim.core.CloudSim; import org.cloudbus.cloudsim.core.CloudSimTags; import org.cloudbus.cloudsim.core.SimEvent; import org.cloudbus.cloudsim.lists.VmList; import org.workflowsim.failure.FailureGenerator; import org.workflowsim.scheduling.DataAwareSchedulingAlgorithm; import org.workflowsim.scheduling.BaseSchedulingAlgorithm; import org.workflowsim.scheduling.FCFSSchedulingAlgorithm; import org.workflowsim.scheduling.MCTSchedulingAlgorithm; import org.workflowsim.scheduling.MaxMinSchedulingAlgorithm; import org.workflowsim.scheduling.MinMinSchedulingAlgorithm; import org.workflowsim.scheduling.RoundRobinSchedulingAlgorithm; import org.workflowsim.scheduling.StaticSchedulingAlgorithm; import org.workflowsim.utils.Parameters; import org.workflowsim.utils.Parameters.SchedulingAlgorithm; /** * WorkflowScheduler represents a algorithm acting on behalf of a user. It hides * VM management, as vm creation, sumbission of jobs to this VMs and destruction * of VMs. It picks up a scheduling algorithm based on the configuration * * @author Weiwei Chen * @since WorkflowSim Toolkit 1.0 * @date Apr 9, 2013 */ public class WorkflowScheduler extends DatacenterBroker { /** * The workflow engine id associated with this workflow algorithm. */ private int workflowEngineId; /** * Created a new WorkflowScheduler object. * * @param name name to be associated with this entity (as required by * Sim_entity class from simjava package) * @throws Exception the exception * @pre name != null * @post $none */ public WorkflowScheduler(String name) throws Exception { super(name); } /** * Binds this scheduler to a datacenter * * @param datacenterId data center id */ public void bindSchedulerDatacenter(int datacenterId) { if (datacenterId <= 0) { Log.printLine("Error in data center id"); return; } this.datacenterIdsList.add(datacenterId); } /** * Sets the workflow engine id * * @param workflowEngineId the workflow engine id */ public void setWorkflowEngineId(int workflowEngineId) { this.workflowEngineId = workflowEngineId; } /** * Process an event * * @param ev a simEvent obj */ @Override public void processEvent(SimEvent ev) { switch (ev.getTag()) { // Resource characteristics request case CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST: processResourceCharacteristicsRequest(ev); break; // Resource characteristics answer case CloudSimTags.RESOURCE_CHARACTERISTICS: processResourceCharacteristics(ev); break; // VM Creation answer case CloudSimTags.VM_CREATE_ACK: processVmCreate(ev); break; // A finished cloudlet returned case WorkflowSimTags.CLOUDLET_CHECK: processCloudletReturn(ev); break; case CloudSimTags.CLOUDLET_RETURN: processCloudletReturn(ev); break; case CloudSimTags.END_OF_SIMULATION: shutdownEntity(); break; case CloudSimTags.CLOUDLET_SUBMIT: processCloudletSubmit(ev); break; case WorkflowSimTags.CLOUDLET_UPDATE: processCloudletUpdate(ev); break; default: processOtherEvent(ev); break; } } /** * Switch between multiple schedulers. Based on algorithm.method * * @param name the SchedulingAlgorithm name * @return the algorithm that extends BaseSchedulingAlgorithm */ private BaseSchedulingAlgorithm getScheduler(SchedulingAlgorithm name) { BaseSchedulingAlgorithm algorithm; // choose which algorithm to use. Make sure you have add related enum in //Parameters.java switch (name) { //by default it is Static case FCFS: algorithm = new FCFSSchedulingAlgorithm(); break; case MINMIN: algorithm = new MinMinSchedulingAlgorithm(); break; case MAXMIN: algorithm = new MaxMinSchedulingAlgorithm(); break; case MCT: algorithm = new MCTSchedulingAlgorithm(); break; case DATA: algorithm = new DataAwareSchedulingAlgorithm(); break; case STATIC: algorithm = new StaticSchedulingAlgorithm(); break; case ROUNDROBIN: algorithm = new RoundRobinSchedulingAlgorithm(); break; default: algorithm = new StaticSchedulingAlgorithm(); break; } return algorithm; } /** * Process the ack received due to a request for VM creation. * * @param ev a SimEvent object * @pre ev != null * @post $none */ @Override protected void processVmCreate(SimEvent ev) { int[] data = (int[]) ev.getData(); int datacenterId = data[0]; int vmId = data[1]; int result = data[2]; if (result == CloudSimTags.TRUE) { getVmsToDatacentersMap().put(vmId, datacenterId); /** * Fix a bug of cloudsim Don't add a null to getVmsCreatedList() * June 15, 2013 */ if (VmList.getById(getVmList(), vmId) != null) { getVmsCreatedList().add(VmList.getById(getVmList(), vmId)); Log.printLine(CloudSim.clock() + ": " + getName() + ": VM #" + vmId + " has been created in Datacenter #" + datacenterId + ", Host #" + VmList.getById(getVmsCreatedList(), vmId).getHost().getId()); } } else { Log.printLine(CloudSim.clock() + ": " + getName() + ": Creation of VM #" + vmId + " failed in Datacenter #" + datacenterId); } incrementVmsAcks(); // all the requested VMs have been created if (getVmsCreatedList().size() == getVmList().size() - getVmsDestroyed()) { submitCloudlets(); } else { // all the acks received, but some VMs were not created if (getVmsRequested() == getVmsAcks()) { // find id of the next datacenter that has not been tried for (int nextDatacenterId : getDatacenterIdsList()) { if (!getDatacenterRequestedIdsList().contains(nextDatacenterId)) { createVmsInDatacenter(nextDatacenterId); return; } } // all datacenters already queried if (getVmsCreatedList().size() > 0) { // if some vm were created submitCloudlets(); } else { // no vms created. abort Log.printLine(CloudSim.clock() + ": " + getName() + ": none of the required VMs could be created. Aborting"); finishExecution(); } } } } /** * Update a cloudlet (job) * * @param ev a simEvent object */ protected void processCloudletUpdate(SimEvent ev) { BaseSchedulingAlgorithm scheduler = getScheduler(Parameters.getSchedulingAlgorithm()); scheduler.setCloudletList(getCloudletList()); scheduler.setVmList(getVmsCreatedList()); try { scheduler.run(); } catch (Exception e) { Log.printLine("Error in configuring scheduler_method"); e.printStackTrace(); } List<Cloudlet> scheduledList = scheduler.getScheduledList(); for (Cloudlet cloudlet : scheduledList) { int vmId = cloudlet.getVmId(); double delay = 0.0; if (Parameters.getOverheadParams().getQueueDelay() != null) { delay = Parameters.getOverheadParams().getQueueDelay(cloudlet); } schedule(getVmsToDatacentersMap().get(vmId), delay, CloudSimTags.CLOUDLET_SUBMIT, cloudlet); } getCloudletList().removeAll(scheduledList); getCloudletSubmittedList().addAll(scheduledList); cloudletsSubmitted += scheduledList.size(); } /** * Process a cloudlet (job) return event. * * @param ev a SimEvent object * @pre ev != $null * @post $none */ @Override protected void processCloudletReturn(SimEvent ev) { Cloudlet cloudlet = (Cloudlet) ev.getData(); Job job = (Job) cloudlet; /** * Generate a failure if failure rate is not zeros. */ FailureGenerator.generate(job); getCloudletReceivedList().add(cloudlet); getCloudletSubmittedList().remove(cloudlet); CondorVM vm = (CondorVM) getVmsCreatedList().get(cloudlet.getVmId()); //so that this resource is released vm.setState(WorkflowSimTags.VM_STATUS_IDLE); double delay = 0.0; if (Parameters.getOverheadParams().getPostDelay() != null) { delay = Parameters.getOverheadParams().getPostDelay(job); } schedule(this.workflowEngineId, delay, CloudSimTags.CLOUDLET_RETURN, cloudlet); cloudletsSubmitted--; //not really update right now, should wait 1 s until many jobs have returned schedule(this.getId(), 0.0, WorkflowSimTags.CLOUDLET_UPDATE); } /** * Start this entity (WorkflowScheduler) */ @Override public void startEntity() { Log.printLine(getName() + " is starting..."); // this resource should register to regional GIS. // However, if not specified, then register to system GIS (the // default CloudInformationService) entity. //int gisID = CloudSim.getEntityId(regionalCisName); int gisID = -1; if (gisID == -1) { gisID = CloudSim.getCloudInfoServiceEntityId(); } // send the registration to GIS sendNow(gisID, CloudSimTags.REGISTER_RESOURCE, getId()); } /** * Terminate this entity (WorkflowScheduler) */ @Override public void shutdownEntity() { clearDatacenters(); Log.printLine(getName() + " is shutting down..."); } /** * Submit cloudlets (jobs) to the created VMs. Scheduling is here */ @Override protected void submitCloudlets() { sendNow(this.workflowEngineId, CloudSimTags.CLOUDLET_SUBMIT, null); } /** * A trick here. Assure that we just submit it once */ private boolean processCloudletSubmitHasShown = false; /** * Submits cloudlet (job) list * * @param ev a simEvent object */ protected void processCloudletSubmit(SimEvent ev) { List<Job> list = (List) ev.getData(); getCloudletList().addAll(list); sendNow(this.getId(), WorkflowSimTags.CLOUDLET_UPDATE); if (!processCloudletSubmitHasShown) { processCloudletSubmitHasShown = true; } } /** * Process a request for the characteristics of a PowerDatacenter. * * @param ev a SimEvent object * @pre ev != $null * @post $none */ @Override protected void processResourceCharacteristicsRequest(SimEvent ev) { setDatacenterCharacteristicsList(new HashMap<>()); Log.printLine(CloudSim.clock() + ": " + getName() + ": Cloud Resource List received with " + getDatacenterIdsList().size() + " resource(s)"); for (Integer datacenterId : getDatacenterIdsList()) { sendNow(datacenterId, CloudSimTags.RESOURCE_CHARACTERISTICS, getId()); } } }