From: <mar...@us...> - 2008-02-28 04:11:40
|
Revision: 137 http://gridsim.svn.sourceforge.net/gridsim/?rev=137&view=rev Author: marcos_dias Date: 2008-02-27 20:11:36 -0800 (Wed, 27 Feb 2008) Log Message: ----------- Inclusion of a parallel space shared policy with queue partitions, easy backfilling, priorities and advance reservation. Modified Paths: -------------- branches/gridsim4.0-branch3/examples/examples/WorkloadWithReservation.java branches/gridsim4.0-branch3/examples/examples/workload/parallel/TurboExampleEBMultiQueues02.java branches/gridsim4.0-branch3/source/gridsim/GridResource.java branches/gridsim4.0-branch3/source/gridsim/turbo/ARCBMultiplePartitions.java branches/gridsim4.0-branch3/source/gridsim/turbo/ARTGridResource.java branches/gridsim4.0-branch3/source/gridsim/turbo/CBMultiplePartitions.java branches/gridsim4.0-branch3/source/gridsim/turbo/EBMultiplePartitions.java branches/gridsim4.0-branch3/source/gridsim/turbo/MPAvailabilityProfile.java branches/gridsim4.0-branch3/source/gridsim/turbo/TResourceCharacteristics.java Added Paths: ----------- branches/gridsim4.0-branch3/examples/examples/workload/ar/TurboAREBMultipleQueuesExample01.java branches/gridsim4.0-branch3/source/gridsim/turbo/AREBMultiplePartitions.java Modified: branches/gridsim4.0-branch3/examples/examples/WorkloadWithReservation.java =================================================================== --- branches/gridsim4.0-branch3/examples/examples/WorkloadWithReservation.java 2008-02-27 23:37:51 UTC (rev 136) +++ branches/gridsim4.0-branch3/examples/examples/WorkloadWithReservation.java 2008-02-28 04:11:36 UTC (rev 137) @@ -63,7 +63,7 @@ * <tt>java -Xmx</tt> option when running the simulation. * <li> If you are running an experiment using the network extension, * i.e. the gridsim.net package, then you need to use - * {@link #Workload(String, double, double, int, String, String, int)} + * {@link #WorkloadWithReservation(String, double, double, int, String, String, int)} * instead. * <li> The default job file size for sending to and receiving from * a resource is {@link gridsim.net.Link#DEFAULT_MTU}. @@ -605,10 +605,12 @@ Gridlet gl = null; int counter = 1; // starts at 1, since gridletID_ starts at 1 too + int fails = 0; + int returned = 0; Sim_event ev = new Sim_event(); Object[] reservObj = null; - while ( Sim_system.running() && counter < gridletID_ ) { + while ( Sim_system.running()) { super.sim_get_next(ev); // get the next available event data = ev.get_data(); // get the event's data @@ -668,6 +670,7 @@ if(!success) { list_.add(resGl); counter++; + fails++; } } @@ -676,9 +679,16 @@ gl = (Gridlet) data; list_.add(gl); counter++; + returned++; } + + if(counter == gridletID_) + break; } +// System.out.println("gridlet ID = " + gridletID_ +// + ", fails = " + fails + ", returned = " + returned + ", counter=" + counter); + // shut down all the entities, including GridStatistics entity since // we used it to record certain events. shutdownGridStatisticsEntity(); Added: branches/gridsim4.0-branch3/examples/examples/workload/ar/TurboAREBMultipleQueuesExample01.java =================================================================== --- branches/gridsim4.0-branch3/examples/examples/workload/ar/TurboAREBMultipleQueuesExample01.java (rev 0) +++ branches/gridsim4.0-branch3/examples/examples/workload/ar/TurboAREBMultipleQueuesExample01.java 2008-02-28 04:11:36 UTC (rev 137) @@ -0,0 +1,206 @@ + +package examples.workload.ar; + +import examples.QueuePredicateExample; +import examples.WorkloadWithReservation; +import gridsim.GridResource; +import gridsim.GridSim; +import gridsim.Machine; +import gridsim.MachineList; +import gridsim.ResourceCalendar; +import gridsim.turbo.AREBMultiplePartitions; +import gridsim.turbo.ARTGridResource; +import gridsim.turbo.TResourceCharacteristics; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.LinkedList; +import java.util.Random; + + +/** + * Test Driver class for this example. This example just tests + * the same features provided by the ParallelSpaceShared policy + */ +public class TurboAREBMultipleQueuesExample01 +{ + /** + * Creates main() to run this example + */ + public static void main(String[] args) + { + long startTime = System.currentTimeMillis(); + if(args.length == 0){ + System.out.println("Please provide the location of the workload file!"); + System.exit(1); + } + + try { + + ////////////////////////////////////////// + // Get the workload to be used The format should be: + // ASCII text, gzip or zip. + + String fileName = args[0]; + ArrayList<GridResource> resources = new ArrayList<GridResource>(); + + ////////////////////////////////////////// + // Initialize the GridSim package. It should be called + // before creating any entities. We can't run this example without + // initializing GridSim first. We will get run-time exception + // error. + + // number of grid user entities + any Workload entities. + int num_user = 1; + Calendar calendar = Calendar.getInstance(); + boolean trace_flag = false; // mean trace GridSim events + + // Initialize the GridSim package without any statistical + // functionalities. Hence, no GridSim_stat.txt file is created. + System.out.println("Initializing GridSim package"); + GridSim.init(num_user, calendar, trace_flag); + + ////////////////////////////////////////// + // Creates one or more GridResource entities + int totalResource = 1; // total number of Grid resources + int rating = 377; // rating of each PE in MIPS + int totalPE = 9; // total number of PEs for each Machine + int totalMachine = 128; // total number of Machines + int i = 0; + + String[] resArray = new String[totalResource]; + for (i = 0; i < totalResource; i++) + { + String resName = "Res_" + i; + GridResource resource = createGridResource(resName, rating, totalMachine, totalPE); + resources.add(resource); + + // add a resource name into an array + resArray[i] = resName; + } + + ////////////////////////////////////////// + // Creates one Workload trace entity. + + int resID = 0; + Random r = new Random(); + resID = r.nextInt(totalResource); + WorkloadWithReservation workload = + new WorkloadWithReservation("Load_1", fileName, resArray[resID], rating); + + // sets how long in advance the reservations are made (24 hours here) + workload.setARTimeInAdvance( 24 * 60 * 60 ); + + // sets the probability of a job read from the trace file being an advance reservation + workload.setReservationProbability(0.5); + + ////////////////////////////////////////// + // Starts the simulation in debug mode +// GridSim.startGridSimulation(true); + + // Start the simulation in normal mode + GridSim.startGridSimulation(); + + ////////////////////////////////////////// + // Final step: Prints the Gridlets when simulation is over + long finishTime = System.currentTimeMillis(); + System.out.println("The simulation took " + (finishTime - startTime) + " milliseconds"); + + // prints the Gridlets inside a Workload entity + // workload.printGridletList(trace_flag); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Creates one Grid resource. A Grid resource contains one or more + * Machines. Similarly, a Machine contains one or more PEs (Processing + * Elements or CPUs). + * @param name a Grid Resource name + * @param peRating rating of each PE + * @param totalMachine total number of Machines + * @param totalPE total number of PEs for each Machine + */ + private static GridResource createGridResource(String name, int peRating, + int totalMachine, int totalPE) + { + + ////////////////////////////////////////// + // Here are the steps needed to create a Grid resource: + // 1. We need to create an object of MachineList to store one or more + // Machines + MachineList mList = new MachineList(); + + for (int i = 0; i < totalMachine; i++) + { + ////////////////////////////////////////// + // 4. Create one Machine with its id and list of PEs or CPUs + mList.add( new Machine(i, totalPE, peRating) ); + } + + ////////////////////////////////////////// + // 5. Create a ResourceCharacteristics object that stores the + // properties of a Grid resource: architecture, OS, list of + // Machines, allocation policy: time- or space-shared, time zone + // and its price (G$/PE time unit). + String arch = "Sun Ultra"; // system architecture + String os = "Solaris"; // operating system + double time_zone = 0.0; // time zone this resource located + double cost = 3.0; // the cost of using this resource + + TResourceCharacteristics resConfig = + new TResourceCharacteristics(arch, os, mList, + TResourceCharacteristics.AREB_MULTI_PARTITIONS, + time_zone, cost); + + AREBMultiplePartitions policy = null; + try { + policy = new AREBMultiplePartitions(name, "Policy", 3); + } catch (Exception e1) { + e1.printStackTrace(); + } + + // creates three partitions, one for small jobs, one for medium size jobs + // and another for long jobs + QueuePredicateExample express = new QueuePredicateExample(0, 1000, peRating); + QueuePredicateExample medium = new QueuePredicateExample(1000, 10000, peRating); + QueuePredicateExample large = new QueuePredicateExample(10000, Integer.MAX_VALUE, peRating); + + policy.createPartition(0, resConfig.getNumPE() / 3, express); + policy.createPartition(1, resConfig.getNumPE() / 3, medium); + policy.createPartition(2, resConfig.getNumPE() / 3, large); + + ////////////////////////////////////////// + // 6. Finally, we need to create a GridResource object. + double baud_rate = 10000.0; // communication speed + long seed = 11L*13*17*19*23+1; + double peakLoad = 0.0; // the resource load during peak hour + double offPeakLoad = 0.0; // the resource load during off-peak hr + double holidayLoad = 0.0; // the resource load during holiday + + // incorporates weekends so the grid resource is on 7 days a week + LinkedList weekends = new LinkedList(); + weekends.add(new Integer(Calendar.SATURDAY)); + weekends.add(new Integer(Calendar.SUNDAY)); + + // incorporates holidays. However, no holidays are set in this example + LinkedList holidays = new LinkedList(); + ResourceCalendar resCalendar = new ResourceCalendar(time_zone, + peakLoad, offPeakLoad, holidayLoad, weekends, + holidays, seed); + + ARTGridResource gridRes = null; + try { + gridRes = new ARTGridResource(name, baud_rate, resConfig, resCalendar, policy); + } + catch (Exception e) { + e.printStackTrace(); + } + + System.out.println("Creates one Grid resource with name = " + name); + return gridRes; + } +} // end class + Modified: branches/gridsim4.0-branch3/examples/examples/workload/parallel/TurboExampleEBMultiQueues02.java =================================================================== --- branches/gridsim4.0-branch3/examples/examples/workload/parallel/TurboExampleEBMultiQueues02.java 2008-02-27 23:37:51 UTC (rev 136) +++ branches/gridsim4.0-branch3/examples/examples/workload/parallel/TurboExampleEBMultiQueues02.java 2008-02-28 04:11:36 UTC (rev 137) @@ -85,10 +85,10 @@ ////////////////////////////////////////// // Starts the simulation in debug mode - GridSim.startGridSimulation(true); +// GridSim.startGridSimulation(true); // Start the simulation in normal mode -// GridSim.startGridSimulation(); + GridSim.startGridSimulation(); ////////////////////////////////////////// // Final step: Prints the Gridlets when simulation is over Modified: branches/gridsim4.0-branch3/source/gridsim/GridResource.java =================================================================== --- branches/gridsim4.0-branch3/source/gridsim/GridResource.java 2008-02-27 23:37:51 UTC (rev 136) +++ branches/gridsim4.0-branch3/source/gridsim/GridResource.java 2008-02-28 04:11:36 UTC (rev 137) @@ -11,6 +11,7 @@ import gridsim.net.*; import gridsim.turbo.ARCBMultiplePartitions; +import gridsim.turbo.AREBMultiplePartitions; import gridsim.turbo.ARParallelSpaceShared; import gridsim.turbo.CBMultiplePartitions; import gridsim.turbo.EBParallelSpaceShared; @@ -662,6 +663,11 @@ "ARCBMultipleQueues", 1); break; + case TResourceCharacteristics.AREB_MULTI_PARTITIONS: + policy_ = new AREBMultiplePartitions(super.get_name(), + "AREBMultipleQueues", 1); + break; + default: throw new Exception(super.get_name()+" : Error - supports"+ " only TimeShared or SpaceShared policy."); Modified: branches/gridsim4.0-branch3/source/gridsim/turbo/ARCBMultiplePartitions.java =================================================================== --- branches/gridsim4.0-branch3/source/gridsim/turbo/ARCBMultiplePartitions.java 2008-02-27 23:37:51 UTC (rev 136) +++ branches/gridsim4.0-branch3/source/gridsim/turbo/ARCBMultiplePartitions.java 2008-02-28 04:11:36 UTC (rev 137) @@ -29,11 +29,7 @@ * other partition. * * We use an availability profile to store the availability of processing - * elements. In order to represent the pivots (i.e. the first jobs in the - * partitions), we schedule them creating the entries in the availability - * profile. This way, we do not need to store the pivots' start times - * (or shadow times) and extra nodes in different variables. It also makes - * the search for available resources for a new pivot easier. + * elements. * <p> * <b>LIMITATIONS:</b><br> * <ul> @@ -74,9 +70,9 @@ private double lastCheckExpiryTime_; /** - * Allocates a new <tt>CBMultipleQueues</tt> object. + * Allocates a new <tt>ARCBMultipleQueues</tt> object. * If the policy is create with only one partition, it will then work as - * a normal aggressive (EASY) backfilling scheduler. + * a conservative backfilling scheduler. * * @param resourceName the <tt>GridResource</tt> entity name that will * contain this allocation policy @@ -104,9 +100,9 @@ } /** - * Allocates a new <tt>CBMultipleQueues</tt> object. + * Allocates a new <tt>ARCBMultipleQueues</tt> object. * If the policy is create with only one partition, it will then work as - * a normal aggressive (EASY) backfilling scheduler. + * a conservative backfilling scheduler. * * @param resourceName the <tt>GridResource</tt> entity name that will * contain this allocation policy @@ -591,7 +587,7 @@ int itemsStarted = 0; // finishes the advance reservations first - itemsFinished = finishReservation(currentTime); + itemsFinished = finishReservations(currentTime); // then finishes the Gridlets whose start time is smaller // or equals to the current simulation time @@ -605,11 +601,11 @@ } // starts the advance reservations - itemsStarted = startReservation(currentTime); + itemsStarted = startReservations(currentTime); // Start the execution of Gridlets that are queued and whose // potential start execution time is smaller than current time - itemsStarted += super.backfillGridlets(currentTime); + itemsStarted += super.startQueuedGridlets(currentTime); //---------------- USED FOR DEBUGGING PURPOSES ONLY -------------------- @@ -628,7 +624,7 @@ * equals to refTime will be completed * @return the number of reservations completed */ - protected int finishReservation(double refTime) { + protected int finishReservations(double refTime) { int reservationFinished = 0; Iterator<SSReservation> iterRes = reservTable_.values().iterator(); @@ -664,7 +660,7 @@ * @refTime the reservations whose start time is smaller * or equals to refTime will be started */ - protected int startReservation(double refTime) { + protected int startReservations(double refTime) { LinkedList<SSReservation> startedReservations = new LinkedList<SSReservation>(); int numStartedRes = 0; Added: branches/gridsim4.0-branch3/source/gridsim/turbo/AREBMultiplePartitions.java =================================================================== --- branches/gridsim4.0-branch3/source/gridsim/turbo/AREBMultiplePartitions.java (rev 0) +++ branches/gridsim4.0-branch3/source/gridsim/turbo/AREBMultiplePartitions.java 2008-02-28 04:11:36 UTC (rev 137) @@ -0,0 +1,1145 @@ +/* + * Title: GridSim Toolkit + * Description: GridSim (Grid Simulation) Toolkit for Modelling and Simulation + * of Parallel and Distributed Systems such as Clusters and Grids + * Licence: GPL - http://www.gnu.org/copyleft/gpl.html + */ + +package gridsim.turbo; + +import eduni.simjava.Sim_event; +import gridsim.GridSim; +import gridsim.GridSimTags; +import gridsim.Gridlet; +import gridsim.IO_data; +import gridsim.gui.AllocationAction; + +import java.util.Calendar; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; + +/** + * This class implements a non-FCFS policy to schedule parallel jobs. The + * policy is based on easy backfilling and supports advance reservation. + * This policy can use multiple partitions or queues and the jobs can be + * directed to these partitions using a partition predicate + * ({@link QueuePartitionPredicate}. A partition can borrow resources from + * another when it requires and the resources are not being used by the + * other partition. + * + * We use an availability profile to store the availability of processing + * elements. In order to represent the pivots (i.e. the first jobs in the + * partitions), we schedule them creating the entries in the availability + * profile. This way, we do not need to store the pivots' start times + * (or shadow times) and extra nodes in different variables. It also makes + * the search for available resources for a new pivot easier. + * <p> + * <b>LIMITATIONS:</b><br> + * <ul> + * <li> The list of machines comprising this resource must be + * homogeneous. + * <li> Local load is not considered. If you would like to simulate this, + * you have to model the local load as gridlets. It is more precise + * and faster. To do so, please check {@link Lublin99Workload}. + * <li> Gridlets cannot be paused nor migrated. + * </ul> + * + * @see gridsim.GridSim + * @see gridsim.ResourceCharacteristics + * @see gridsim.turbo.TAllocPolicy + * @see gridsim.turbo.EBMultiplePartitions + * @see gridsim.turbo.QueuePartitionPredicate + * @see gridsim.turbo.PERange + * @see gridsim.turbo.PERangeList + */ + +public class AREBMultiplePartitions extends + EBMultiplePartitions implements ARTPolicy { + + // a new reservation table + private LinkedHashMap<Integer, SSReservation> reservTable_; + + // a table that contains expired reservations + private LinkedHashMap<Integer, SSReservation> expiryTable_; + + // default booking/reservation commit period + private int commitPeriod_; + + // internal event tags used by this gridlet + // a tag to denote expiry time + private final int EXPIRY_TIME = 12; + + // last time the expiration of reservations was checked + private double lastCheckExpiryTime_; + + /** + * Allocates a new <tt>AREBMultiplePartitions</tt> object. + * If the policy is create with only one partition, it will then work as + * a normal aggressive (EASY) backfilling scheduler. + * + * @param resourceName the <tt>GridResource</tt> entity name that will + * contain this allocation policy + * @param entityName this object entity name + * @param numPartitions The number of partitions of the scheduling queue + * @throws Exception This happens when one of the following scenarios occur: + * <ul> + * <li> Creating this entity before initialising GridSim package + * <li> The entity name is <tt>null</tt> or empty + * <li> The entity has <tt>zero</tt> number of PEs (Processing + * Elements). <br> + * No PEs, which means that the Gridlets cannot be processed. + * A GridResource must contain one or more Machines. + * A Machine must contain one or more PEs. + * </ul> + * + * @see gridsim.GridSim#init(int, Calendar, boolean, + * String[], String[], String) + */ + public AREBMultiplePartitions(String resourceName, + String entityName, int numPartitions) throws Exception { + super(resourceName, entityName, numPartitions); + commitPeriod_ = 30*60; // set the expiration time into 30 mins + init(); + } + + /** + * Allocates a new <tt>AREBMultiplePartitions</tt> object. + * If the policy is create with only one partition, it will then work as + * a normal aggressive (EASY) backfilling scheduler. + * + * @param resourceName the <tt>GridResource</tt> entity name that will + * contain this allocation policy + * @param entityName this object entity name + * @param numPartitions The number of partitions of the scheduling queue + * @param commitPeriod a default commit period time for a user to commit + * a reservation (unit is in second). <b>NOTE:</b> once it is set, you cannot + * change the time again. + * @throws Exception This happens when one of the following scenarios occur: + * <ul> + * <li> Creating this entity before initialising GridSim package + * <li> The entity name is <tt>null</tt> or empty + * <li> The entity has <tt>zero</tt> number of PEs (Processing + * Elements). <br> + * No PEs, which means that the Gridlets cannot be processed. + * A GridResource must contain one or more Machines. + * A Machine must contain one or more PEs. + * </ul> + * + * @see gridsim.GridSim#init(int, Calendar, boolean, + * String[], String[], String) + */ + public AREBMultiplePartitions(String resourceName, + String entityName, int numPartitions, + int commitPeriod) throws Exception { + super(resourceName, entityName, numPartitions); + if (commitPeriod <= 0) { + throw new Exception(resourceName + "." + entityName + + ": Error - Invalid expiry time."); + } + commitPeriod_ = commitPeriod; + init(); + } + + /** + * Handles internal events that come to this entity. + */ + public void body() { + super.body(); + reservTable_.clear(); + expiryTable_.clear(); + lastCheckExpiryTime_ = 0.0D; + } + + // -------------------- GRIDLET RELATED METHODS --------------------- + + /** + * Schedules a new <tt>Gridlet</tt> received by the <tt>GridResource</tt> entity. + * @param gridlet a Gridlet object to be executed + * @param ack an acknowledgement, i.e. <tt>true</tt> if the + * user wants to know whether this operation is successful + * or not, <tt>false</tt> otherwise. + */ + public void gridletSubmit(Gridlet gridlet, boolean ack) { + if(!gridlet.hasReserved()) { + super.gridletSubmit(gridlet, ack); + } + else { + handleReservationGridlet(gridlet, ack); + } + } + + /** + * Schedules a new Gridlet received by the <tt>ARTGridResource</tt> + * entity and for which an advance reservation has been made. + * @param gridlet a Gridlet object to be executed + * @param ack an acknowledgement, i.e. <tt>true</tt> if the + * user wants to know whether this operation is successful + * or not, <tt>false</tt> otherwise. + */ + private void handleReservationGridlet(Gridlet gridlet, boolean ack) { + + double currentTime = GridSim.clock(); + + int freePE; + int reqPE = gridlet.getNumPE(); + // gets the advance reservation + SSReservation sRes = reservTable_.get(gridlet.getReservationID()); + + // create an SSGridlet + SSGridlet sgl = new SSGridlet(gridlet); + + // forecast the execution time of the gridlet + double executionTime = + super.forecastExecutionTime(ratingPE_, sgl.getLength()); + + /////////////// FOR DEBUGGING PURPOSES ONLY //////// + + GridSim.notifyListeners(this.get_id(), AllocationAction.ITEM_ARRIVED, true, sgl); + + ///////////////////////////////////////////////////// + + boolean success = true; + if(sRes == null) { + String userName = GridSim.getEntityName( gridlet.getUserID() ); + System.out.println(super.get_name() + ".gridletSubmit(): " + + " Gridlet #" + gridlet.getGridletID() + " from " + + userName + " cannot be accepted because the reservation #" + + gridlet.getReservationID() + " has not been found."); + success = false; + } + // check if the gridlet is requiring more PEs than what + // the reservation currently has + else if( (freePE = sRes.getNumRemainingPE()) < reqPE ) { + String userName = GridSim.getEntityName( gridlet.getUserID() ); + System.out.println(super.get_name() + ".gridletSubmit(): " + + " Gridlet #" + gridlet.getGridletID() + " from " + + userName + " cannot be accepted because the reservation #" + + sRes.getID() + " has only " + freePE + " PEs."); + success = false; + } + // check whether the gridlet is expected to run for longer than + // the time previously reserved + else if (executionTime >= sRes.getDurationTime()) { + String userName = GridSim.getEntityName( gridlet.getUserID() ); + System.out.println(super.get_name() + ".gridletSubmit(): " + + " Gridlet #" + gridlet.getGridletID() + " from " + + userName + " cannot be accepted because the reservation #" + + sRes.getID() + " is for " + sRes.getDurationTime() + + " while the gridlet is expected to run for " + + executionTime + " seconds."); + success = false; + } + + if(!success) { + try { + gridlet.setGridletStatus(Gridlet.FAILED); + super.sendFinishGridlet(gridlet); + return; + } + catch(Exception ex){ + System.out.println(super.get_name() + + ": Exception on submission of a Gridlet. Message = " + + ex.getMessage()); + return; + } + } + else { + // selects a list of ranges for the gridlet from the PEs available + // for the reservation + PERangeList selected = null; + success = ( ( selected = sRes.selectPERangeList(reqPE) ) != null ); + + sgl.setPERangeList(selected); + double resStartTime = sRes.getStartTime(); + sgl.setStartTime(resStartTime); + sgl.setActualFinishTime(resStartTime + executionTime); + sgl.setStatus(Gridlet.QUEUED); + queuedGridlets_.add(sgl); + + // if the reservation has not been committed, then commit the + // reservation + if (sRes.getStatus() == Reservation.STATUS_NOT_COMMITTED) { + sRes.setStatus(Reservation.STATUS_COMMITTED); + super.sendInternalEvent(resStartTime - currentTime, + CBParallelSpaceShared.UPDATE_SCHEDULE_TAG); + } + // if the reservation has already started, then update the + // schedule, which will force the gridlets in the queue to + // be started + else if(sRes.getStatus() == Reservation.STATUS_IN_PROGRESS) { + super.sendInternalEvent(resStartTime - currentTime, + CBParallelSpaceShared.UPDATE_SCHEDULE_TAG); + } + } + + //------------------ FOR DEBUGGING PURPOSES ONLY ---------------- + + // Notifies the listeners that a Gridlet has been either scheduled + // to run immediately or put in the waiting queue + GridSim.notifyListeners(this.get_id(), AllocationAction.ITEM_SCHEDULED, true, sgl); + + //--------------------------------------------------------------- + + // sends back an ack if required + if (ack == true) { + super.sendAck(GridSimTags.GRIDLET_SUBMIT_ACK, true, + gridlet.getGridletID(), gridlet.getUserID() + ); + } + } + + //---------------- RESERVATION RELATED PUBLIC METHODS --------------------- + + /** + * Handles an advance reservation request.<br> + * @param message the advance reservation message received + * @pre message != null + */ + public void handleCreateReservation(ARMessage message) { + double currentTime = GridSim.clock(); + + // gets the reservation object and extract some + // information from it + Reservation reservation = message.getReservation(); + double startTime = reservation.getStartTime(); + int duration = reservation.getDurationTime(); + int reqPE = reservation.getNumPE(); + + // creates a Server Side Reservation (i.e. SSReservation) + SSReservation sRes = new SSReservation(reservation); + sRes.setPartitionID(profile_.getCorrespondingPartitionID(sRes)); + double expTime = Double.NaN; + + // creates a response message to be sent to the requester + ARMessage response = message.createResponse(); + + //-------------- FOR DEBUGGING PURPOSES ONLY -------------- + + // informs the listeners that a reservation request has arrived + GridSim.notifyListeners(this.get_id(), + AllocationAction.ITEM_ARRIVED, true, sRes); + + //---------------------------------------------------------- + + if (reqPE > super.totalPE_) { + String userName = GridSim.getEntityName( message.getSourceID() ); + System.out.println(super.get_name() + ".handleCreateReservation():" + + " Reservation #" + reservation.getID() + " from " + + userName + " user requires " + reservation.getNumPE() + + " PEs from " + startTime + " to " + (startTime + duration)); + System.out.println("--> The resource has only " + + super.totalPE_ + " PEs available."); + + reservation.setStatus(Reservation.STATUS_FAILED); + response.setErrorCode(ARMessage.EC_OPERATION_FAILURE); + sendARMessage(response); + return; + } + + boolean success = true; + + // if start time is 0, then it is an immediate reservation + if(startTime == 0 || startTime == currentTime) { + success = handleImmediateReservation(sRes); + expTime = sRes.getActualFinishTime(); + } + else { + success = handleAdvanceReservation(sRes); + expTime = currentTime + commitPeriod_; + } + + if(!success) { + String userName = GridSim.getEntityName( message.getSourceID() ); + System.out.println(super.get_name() + ".handleCreateReservation():" + + " Reservation #" + reservation.getID() + " from " + + userName + " user requires " + reservation.getNumPE() + + " PEs from " + startTime + " to " + (startTime + duration)); + System.out.println("--> The resource could not handle the reservation."); + + reservation.setStatus(Reservation.STATUS_FAILED); + response.setErrorCode(ARMessage.EC_OPERATION_FAILURE); + sendARMessage(response); + return; + } + + // if the expiration time is greater than the start time of the + // reservation, then set the expiration time as the start time + if(expTime > startTime) { + expTime = startTime; + } + + // if the start time of the reservation is equals to the current + // time, meaning that it is an immediate reservation, then start + // the reservation straight away. Therefore, sets the status to + // committed and sends an internal event to start the reservation + if(currentTime == startTime) { + sRes.setStatus(Reservation.STATUS_COMMITTED); + super.sendInternalEvent(GridSimTags.SCHEDULE_NOW, + CBParallelSpaceShared.UPDATE_SCHEDULE_TAG); + } + else { + sRes.setStatus(Reservation.STATUS_NOT_COMMITTED); + } + + sRes.setExpiryTime(expTime); + + // add the reservation into the reservation table and sends the + // response message to the requester + reservTable_.put(new Integer(sRes.getID()), sRes); + sendARMessage(response); + + // then send this into itself to check for expired reservations + super.sendInternalEvent(expTime - currentTime, + EXPIRY_TIME); + + //-------------- FOR DEBUGGING PURPOSES ONLY -------------- + + // Informs the listeners about the reservation that has been created + GridSim.notifyListeners(this.get_id(), AllocationAction.ITEM_SCHEDULED, + true, sRes); + } + + /** + * Handles a commit reservation request. + * @param message the advance reservation message received + */ + public void handleCommitReservation(ARMessage message) { + + // gets the reservation id of the message + int reservationId = message.getReservationID(); + SSReservation sRes = null; + + // creates a response message to be sent to the requester + ARMessage response = message.createResponse(); + boolean success = true; + + // Tries to find the reservation in the lists + if(reservTable_.containsKey(reservationId)) { + sRes = reservTable_.get(reservationId); + } + else if(expiryTable_.containsKey(reservationId)) { + sRes = expiryTable_.get(reservationId); + switch(sRes.getStatus()) { + case Reservation.STATUS_CANCELLED: + System.out.println(super.get_name() + ".handleCommitReservation()" + + " Reservation # " + reservationId + + " cannot be committed because it has" + + " previously been cancelled by the allocation policy."); + break; + case Reservation.STATUS_FINISHED: + System.out.println(super.get_name() + ".handleCommitReservation()" + + " Reservation # " + reservationId + + " cannot be committed because it has finished."); + break; + default: + System.out.println(super.get_name() + ".handleCommitReservation()" + + " Reservation # " + reservationId + + " cannot be committed because it is in the expiry list."); + break; + } + success = false; + } + else { + System.out.println(super.get_name() + ".handleCommitReservation() " + + "Reservation # " + reservationId + " cannot be committed "+ + "because the allocation policy could not find it."); + success = false; + } + + // if there was no success, then sets the error code to failure and + // sends the message back to the requester + if(!success) { + response.setErrorCode(ARMessage.EC_OPERATION_FAILURE); + sendARMessage(response); + return; + } + + // sets the reservation to committed if it has not been set before + if(sRes.getStatus() == Reservation.STATUS_NOT_COMMITTED) { + sRes.setStatus(Reservation.STATUS_COMMITTED); + + // then send this into itself to start the reservation + super.sendInternalEvent(sRes.getStartTime() - GridSim.clock(), + CBParallelSpaceShared.UPDATE_SCHEDULE_TAG); + } + + // sends the response message with no error + sendARMessage(response); + + //-------------- FOR DEBUGGING PURPOSES ONLY -------------- + + GridSim.notifyListeners(this.get_id(), + AllocationAction.ITEM_STATUS_CHANGED, true, sRes); + + //---------------------------------------------------------- + } + + /** + * Handles a modify reservation request<br> + * (NOTE: <b>NOT SUPPORTED YET</b>). + * @param message the advance reservation message received. + */ + public void handleModifyReservation(ARMessage message) { + System.out.println(super.get_name() + + ".handleModifyReservation(): not supported at the moment."); + } + + /** + * Handles a cancel reservation request<br> + * (NOTE: <b>NOT SUPPORTED YET</b>). + * @param message the advance reservation message received. + */ + public void handleCancelReservation(ARMessage message) { + System.out.println(super.get_name() + + ".handleCancelReservation(): not supported at the moment."); + } + + /** + * Handles a query free time request. + * @param message the advance reservation message received. + */ + public void handleQueryAvailability(ARMessage message) { +// // gets the reservation id of the message +// Reservation reservation = message.getReservation(); +// +// // creates a response message to be sent to the requester +// ARMessage response = message.createResponse(); +// +// // gets the start time and finish time the user is interested in +// double startTime = reservation.getStartTime(); +// int duration = reservation.getDurationTime(); +// +// // gets the availability information from the availability profile +// AvailabilityInfo availability = getAvailabilityInfo(startTime, duration); +// +// // sets the options as the availability over the requested period +// response.getReservation().setReservationOptions(availability); +// +// // Sends the response back to the user +// sendARMessage(response); + } + + /** + * Handles a query reservation request. + * @param message the advance reservation message received. + */ + public void handleQueryReservation(ARMessage message) { + + // gets the reservation id of the message + int reservationId = message.getReservationID(); + + // creates a response message to be sent to the requester + ARMessage response = message.createResponse(); + + // Tries to find the reservation in the lists + if(!reservTable_.containsKey(reservationId) + && !expiryTable_.containsKey(reservationId) ) { + System.out.println(super.get_name() + ".handleQueryReservation()" + + " Error querying the status of reservation # " + reservationId + + " because Grid Resource #" + super.resId_ + + " could not find it."); + response.setErrorCode(ARMessage.EC_OPERATION_FAILURE); + } + + // Just sends the message because the reply has a reference to + // the reservation object, which contains the status of the reservation + sendARMessage(response); + } + + /** + * Process and event sent to this entity + * @param ev the event to be handled + */ + public void processOtherEvent(Sim_event ev) { + + // handle an internal event + double currentTime = GridSim.clock(); + + if(ev.get_src() == myId_) { + switch(ev.get_tag()) { + + // checks the expiry time for a given gridlet + case EXPIRY_TIME: + if(currentTime > lastCheckExpiryTime_) { + checkExpiryTime(); + } + lastCheckExpiryTime_ = currentTime; + break; + + default: + super.processOtherEvent(ev); + break; + } + } + else + super.processOtherEvent(ev); + } + + // --------------------- PROTECTED METHODS ----------------------- + + /** + * This method is called to update the schedule. It removes completed + * gridlets and return them to the users and verifies whether there are + * gridlets in the waiting list that should start execution. It also + * removes old entries from the availability profile. + */ + protected void updateSchedule() { + + int itemsFinished = 0; + double currentTime = GridSim.clock(); + int itemsStarted = 0; + + // finishes the advance reservations first + itemsFinished = finishReservations(currentTime); + + // then finishes the Gridlets whose start time is smaller + // or equals to the current simulation time + itemsFinished += super.finishRunningGridlets(currentTime); + + // remove past entries from the availability profile + MPProfileEntry currentStatus = profile_.removePastEntries(currentTime); + if(currentStatus != null) { + profile_.setCurrentStatus(currentStatus); + resource_.resetFreePERanges(currentStatus.getPERanges()); + } + + // starts the advance reservations + itemsStarted = startReservations(currentTime); + + // Start the execution of Gridlets that are queued and whose + // potential start execution time is smaller than current time + itemsStarted += backfillGridlets(currentTime); + + //---------------- USED FOR DEBUGGING PURPOSES ONLY -------------------- + + // If a gridlet has started execution or one has finished, + // then inform the listeners + if(itemsStarted > 0 || itemsFinished > 0){ + GridSim.notifyListeners(this.get_id(), AllocationAction.SCHEDULE_CHANGED, true); + } + } + + /** + * This method is called to finish a reservation and consequently update + * the availability profile. + * @param refTime the time reference to check what reservations should + * be finished. All reservations whose finish time is smaller or + * equals to refTime will be completed + * @return the number of reservations completed + */ + protected int finishReservations(double refTime) { + int reservationFinished = 0; + + Iterator<SSReservation> iterRes = reservTable_.values().iterator(); + while(iterRes.hasNext()) { + SSReservation sRes = iterRes.next(); + if(sRes.getActualFinishTime() <= refTime) { + // Finish the reservation and include ranges in the + // list of ranges to be released + sRes.setStatus(Reservation.STATUS_FINISHED); + reservationFinished++; + iterRes.remove(); + expiryTable_.put(sRes.getID(), sRes); + } + } + + if(reservationFinished > 0) { + + //------------- USED FOR DEBUGGING PURPOSES ONLY ------------------ + + // If a gridlet has started execution or one has finished, + // then inform the listeners + GridSim.notifyListeners(this.get_id(), AllocationAction.SCHEDULE_CHANGED, true); + + //----------------------------------------------------------------- + } + + return reservationFinished; + } + + /** + * This method is called to start a reservation and consequently update + * the availability profile. + * @refTime the reservations whose start time is smaller + * or equals to refTime will be started + */ + protected int startReservations(double refTime) { + LinkedList<SSReservation> startedReservations = new LinkedList<SSReservation>(); + int numStartedRes = 0; + + Iterator<SSReservation> iterRes = reservTable_.values().iterator(); + while(iterRes.hasNext()) { + SSReservation sRes = iterRes.next(); + + if(sRes.getStartTime() <= refTime && + sRes.getStatus() == Reservation.STATUS_COMMITTED) { + + // Start the reservation and update the ranges of + // PEs currently available + sRes.setStatus(Reservation.STATUS_IN_PROGRESS); + + startedReservations.add(sRes); + + super.sendInternalEvent(sRes.getActualFinishTime()-refTime, + CBParallelSpaceShared.UPDATE_SCHEDULE_TAG); + + numStartedRes++; + } + } + return numStartedRes; + } + + /** + * This method returns a list that corresponds to the free time slots + * in the scheduling queue managed by this scheduler or + * resource allocation policy. + * + * @param startTime the start time in which the requester is interested. + * @param duration the duration in which the requester is interested. + * @return the list of free time slots. The list is actually a list of + * entries that correspond to the availability profile between the times + * specified by the requester. + */ + protected AvailabilityInfo getAvailabilityInfo(double startTime, int duration) { + + AvailabilityInfo list = new AvailabilityInfo(); + int anchorIndex = -1; + double currentTime = GridSim.clock(); + + // if the user specified the start time as 0, it means that the + // user is interested to know the availability starting from the + // current time, or the time when the resource received this request + if(startTime == 0) { + startTime = currentTime; + } + + list.setStartTime(startTime); + + // calculate the reservation's finish time + double finishTime = startTime + duration; + list.setFinishTime(finishTime); + + // a pointer to the anchor entry (described above) + MPProfileEntry anchorEntry = null; + int length = profile_.size(); + AvailabilityInfoEntry firstEntry = null; + + anchorEntry = (startTime <= currentTime) ? null : + profile_.getPrecedingEntry(startTime); + + // if the entry is null, then it means that the reservation is + // before the first entry of the profile, so the intersection list + // has to start with the ranges of PEs currently available + if (anchorEntry == null) { + PERangeList peList = (resource_.getFreePERanges() == null) ? + new PERangeList() : resource_.getFreePERanges().clone(); + firstEntry = + new AvailabilityInfoEntry(startTime, peList); + } + else { + PERangeList newList = anchorEntry.getPERanges(); + newList = (newList != null) ? newList.clone() : new PERangeList(); + firstEntry = new AvailabilityInfoEntry(startTime, newList); + anchorIndex = profile_.indexOf(anchorEntry); + } + + list.add(firstEntry); + AvailabilityInfoEntry previousEntry = firstEntry; + + // Iterates the availability profile and adds all the entries + // whose times are between start and finish time in the list + // to be returned. It removes repeated entries. + for(int i=anchorIndex+1; i<length; i++) { + MPProfileEntry nextEntry = profile_.get(i); + if(nextEntry.getTime() <= startTime) + continue; + if(nextEntry.getTime() > finishTime){ + break; + } + else { + PERangeList peList = nextEntry.getPERanges(); + peList = (peList != null) ? peList.clone() : new PERangeList(); + + if( !previousEntry.getAvailRanges().equals(peList)) { + AvailabilityInfoEntry tsEntry = + new AvailabilityInfoEntry(nextEntry.getTime(), peList); + list.add(tsEntry); + previousEntry = tsEntry; + } + } + } + + return list; + } + + /** + * This method returns a list that corresponds to the free time slots + * in the scheduling queue managed by this scheduler or + * resource allocation policy. This returns the resources available + * for a given partition. + * @param queueId the id of the partition whose availability is to be queried. + * @param startTime the start time in which the requester is interested. + * @param duration the duration in which the requester is interested. + * @return the list of free time slots. The list is actually a list of + * entries that correspond to the availability profile between the times + * specified by the requester. + */ + protected AvailabilityInfo getAvailabilityInfo(int queueId, + double startTime, int duration) { + + AvailabilityInfo list = new AvailabilityInfo(); + int anchorIndex = -1; + double currentTime = GridSim.clock(); + QueuePartition partition = profile_.getPartition(queueId); + + // if the user specified the start time as 0, it means that the + // user is interested to know the availability starting from the + // current time, or the time when the resource received this request + if(startTime == 0) { + startTime = currentTime; + } + + list.setStartTime(startTime); + + // calculate the reservation's finish time + double finishTime = startTime + duration; + list.setFinishTime(finishTime); + + // a pointer to the anchor entry (described above) + MPProfileEntry anchorEntry = null; + int length = profile_.size(); + AvailabilityInfoEntry firstEntry = null; + + anchorEntry = (startTime <= currentTime) ? null : + profile_.getPrecedingEntry(startTime); + + // if the entry is null, then it means that the reservation is + // before the first entry of the profile, so the intersection list + // has to start with the ranges of PEs currently available + if (anchorEntry == null) { + PERangeList peList = (partition.getIdlePERanges() == null) ? + new PERangeList() : partition.getIdlePERanges().clone(); + firstEntry = + new AvailabilityInfoEntry(startTime, peList); + } + else { + PERangeList newList = anchorEntry.getPERanges(queueId); + newList = (newList != null) ? newList.clone() : new PERangeList(); + firstEntry = new AvailabilityInfoEntry(startTime, newList); + anchorIndex = profile_.indexOf(anchorEntry); + } + + list.add(firstEntry); + AvailabilityInfoEntry previousEntry = firstEntry; + + // Iterates the availability profile and adds all the entries + // whose times are between start and finish time in the list + // to be returned. It removes repeated entries. + for(int i=anchorIndex+1; i<length; i++) { + MPProfileEntry nextEntry = profile_.get(i); + if(nextEntry.getTime() <= startTime) + continue; + if(nextEntry.getTime() > finishTime){ + break; + } + else { + PERangeList peList = nextEntry.getPERanges(queueId); + peList = (peList != null) ? peList.clone() : new PERangeList(); + + if( !previousEntry.getAvailRanges().equals(peList)) { + AvailabilityInfoEntry tsEntry = + new AvailabilityInfoEntry(nextEntry.getTime(), peList); + list.add(tsEntry); + previousEntry = tsEntry; + } + } + } + + return list; + } + + /** + * Sends a reservation message. + * @param message the message to be sent + */ + protected void sendARMessage(ARMessage message) { + // send message to the destination + super.sim_schedule(super.outputPort_, GridSimTags.SCHEDULE_NOW, + message.getMessageType(), new IO_data(message, + message.getMessageSize(), message.getDestinationID())); + } + + // ------------------------- PRIVATE MTHODS ---------------------- + + /** + * Checks for expiry time of a given reservations in the list. + * @param reservation the reservation to be checked + */ + private void checkExpiryTime() { + + double currentTime = GridSim.clock(); // get current time + + // gridlets whose start time is larger than reference time + // will be shifted forwards when the compression of the + // schedule takes place + double referenceTime = Double.MAX_VALUE; + LinkedList<SSReservation> removedRes = new LinkedList<SSReservation>(); + + Iterator<SSReservation> iterRes = reservTable_.values().iterator(); + while(iterRes.hasNext()) { + SSReservation sRes = iterRes.next(); + int status = sRes.getStatus(); + + // check for expiry time + if (status == Reservation.STATUS_NOT_COMMITTED && + sRes.getExpiryTime() <= currentTime) { + System.out.println(super.get_name() + ".checkExpiryTime(): " + + "Reservation # " + sRes.getID() + " has not been " + + "committed and has hence been cancelled at time #" + currentTime); + + // update the profile (i.e. removes/updates entries at the profile) + removeReservation(sRes); + + sRes.setStatus(Reservation.STATUS_CANCELLED); + expiryTable_.put(sRes.getID(), sRes); + iterRes.remove(); + + if(sRes.getStartTime() < referenceTime) { + referenceTime = sRes.getStartTime(); + } + removedRes.add(sRes); + } + } + + if(removedRes.size() > 0) { + + //-------------- USED FOR DEBUGGING PURPOSES ONLY ----------------- + + // If a gridlet has been cancelled, then inform the listeners + GridSim.notifyListeners(this.get_id(), AllocationAction.ITEM_CANCELLED, true, removedRes); + + //----------------------------------------------------------------- + + // backfills Gridlets to fill the fragment created by the + // cancellation of the advance reservation + super.backfillGridlets(currentTime); +// super.compressSchedule(referenceTime, false); + + //---------------- USED FOR DEBUGGING PURPOSES ONLY ---------------- + + // If a gridlet has started execution or one has finished, + // then inform the listeners + GridSim.notifyListeners(this.get_id(), AllocationAction.SCHEDULE_CHANGED, true); + + //----------------------------------------------------------------- + } + } + + /** + * This method removes/updates all the entries of a reservation from + * the profile and updates the ranges of current free PEs if the + * reservation was in execution. + * @param reservation the Reservation to be removed + */ + private void removeReservation(SSReservation reservation) { + // check whether the reservation is in progress + boolean inProgress = reservation.getStatus() == Reservation.STATUS_IN_PROGRESS; + + // removes the reservation from the profile + profile_.updateEntriesAtProfile(reservation); + + // removes from the queue all gridlets that are associated to the + // advance reservation. This iterates the lists and removes the + // gridlets that have this reservation has their reservation ID + int reservationId = reservation.getID(); + LinkedList<SSGridlet> removedGridlets = new LinkedList<SSGridlet>(); + + Iterator<SSGridlet> iterGrl = + inProgress ? runningGridlets_.iterator() : queuedGridlets_.iterator(); + + while(iterGrl.hasNext()) { + SSGridlet gridlet = iterGrl.next(); + if(gridlet.getReservationID() == reservationId + && gridlet.getStatus() != Gridlet.SUCCESS + && gridlet.getStatus() != Gridlet.FAILED) { + + gridlet.setStatus(Gridlet.CANCELED); + gridlet.finalizeGridlet(); + super.sendFinishGridlet(gridlet.getGridlet()); + + removedGridlets.add(gridlet); + iterGrl.remove(); + } + } + + // notifies the listener that the gridlets have been cancelled + if(removedGridlets.size() > 0) { + + //---------------- USED FOR DEBUGGING PURPOSES ONLY ---------------- + + // If a gridlet has been cancelled, then inform the listeners + GridSim.notifyListeners(this.get_id(), AllocationAction.ITEM_CANCELLED, + false, removedGridlets); + + //------------------------------------------------------------------ + } + } + + /* + * Handles an immediate reservation + * @return true if the reservation was successful + */ + private boolean handleImmediateReservation(SSReservation res) { + double startTime = GridSim.clock(); + res.setStartTime(startTime); + + int duration = res.getDurationTime(); + int reqPE = res.getNumPE(); + int queueId = res.getPartitionID(); + + // check the start time against the availability. That is, + // check if there are enough PEs currently free and + // whether they will be available until the termination + // of the advance reservation + PERangeList ranges = profile_.getImmediateAvailability(queueId, duration); + + // if there are resource available in the queue, then allocate it + if(ranges.getNumPE() >= reqPE) { + // gets the list of PEs selected for the reservation + PERangeList selected = super.selectPERangeList(reqPE, ranges); + + // allocates the list of PEs to the reservation + res.setPERangeList(selected); + + // updates the availability profile accordingly + profile_.allocateImmediateRanges(queueId, startTime + duration, selected); + } + // Tries all the queues + else { + + // gets all available PEs during given time interval + PERangeList overallAvailPEs = + profile_.getImmediateAvailability(duration); + + if(overallAvailPEs.getNumPE() < reqPE) + return false; + + // removes PEs already obtained from selected partition + PERangeList addRanges = + PERangeList.difference(overallAvailPEs, ranges); + + // additional PEs required + int addRequired = reqPE - ranges.getNumPE(); + + if(addRanges != null && addRanges.getNumPE() >= addRequired) { + // borrows the additional PEs required from the partitions + // and adds them into the specified queue + addRanges = super.selectPERangeList(addRequired, addRanges); + profile_.transferPEs(queueId, addRanges, startTime, startTime + duration); + + // allocates the ranges to the gridlet + ranges.addAll(addRanges); + profile_.allocateImmediateRanges(queueId, startTime + duration, ranges); + res.setPERangeList(ranges); + } + else { + return false; + } + } + return true; + } + + /* + * Handles an advance reservation + * @return true if the reservation was successful + */ + private boolean handleAdvanceReservation(SSReservation res) { + + double startTime = res.getStartTime(); + int duration = res.getDurationTime(); + int reqPE = res.getNumPE(); + int queueId = res.getPartitionID(); + + // check whether there are PEs available over the time + // frame requested + Object[] availObjQueue = + ... [truncated message content] |