AbstractScheduler scheduler;
switch (schedulerType) {
case A:
- scheduler = new SchedulerA(schedulerLog,schedulerType,scenario);
+ scheduler = new SchedulerA(schedulerLog, schedulerType, scenario, numPMs, numCloudPartners);
case B:
- scheduler = new SchedulerB(schedulerLog,schedulerType,scenario);
+ scheduler = new SchedulerB(schedulerLog, schedulerType, scenario, numPMs, numCloudPartners);
default:
- scheduler = new SchedulerC(schedulerLog,schedulerType,scenario);
+ scheduler = new SchedulerC(schedulerLog, schedulerType, scenario, numPMs, numCloudPartners);
}
ScenarioData data = scheduler.initAndStart(apps);
CSVLogger logger = new CSVLogger(generalLog);
--- /dev/null
+package at.ac.tuwien.lsdc.exception;
+
+public class ActiveApplicationsException extends Exception {
+
+ public ActiveApplicationsException(String msg) {
+ super(msg);
+ }
+}
--- /dev/null
+package at.ac.tuwien.lsdc.exception;
+
+public class VMsRunningException extends Exception {
+
+ public VMsRunningException(String message) {
+ super(message);
+ }
+}
package at.ac.tuwien.lsdc.management;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
+import at.ac.tuwien.lsdc.exception.VMsRunningException;
import at.ac.tuwien.lsdc.types.PhysicalMachine;
+/**
+ * This class is responsible to start and stop PMs & VMs
+ * also it will be used to put an application on a VM
+ * move an application and get utilization data
+ *
+ */
public class MachineManager {
- // this class is responsible to start and stop PMs & VMs
- // also it will be used to put an application on a VM
- // move an application and get utilization data
private HashMap<Integer, PhysicalMachine> PMs = new HashMap<Integer, PhysicalMachine>();
+
+ private int maxPMs;
+
+ public MachineManager(int maxPMs) {
+ this.maxPMs = maxPMs;
+ }
+
+
+ /**
+ * Start a physical machine
+ * @return the PM that was started, null if all machines already running
+ */
+ public PhysicalMachine startPhysicalMachine() {
+ if(PMs.size() < maxPMs) {
+ PhysicalMachine pm = new PhysicalMachine();
+ PMs.put(pm.getId(), pm);
+ pm.start();
+ return pm;
+ }
+ return null;
+ }
+
+ /**
+ * Stops a physical machine with the given id
+ * @param id the id of the PM to stop
+ * @throws VMsRunningException is thrown when there are still VMs running on this PM
+ */
+ public void stopPhysicalMachine(int id) throws VMsRunningException {
+ if(PMs.containsKey(id)) {
+ PMs.get(id).stop();
+ PMs.remove(id);
+ }
+ }
+
+ /**
+ * Returns all running physical machines
+ * @return the currently active PMs
+ */
+ public Collection<PhysicalMachine> getPMs () {
+ return PMs.values();
+ }
+
+ /**
+ * Returns the maximum number of available physical machines
+ * @return the maximum number of PMs
+ */
+ public int getMaxPMs() {
+ return maxPMs;
+ }
+ /**
+ * Gets the total power consumption summed up from each PM
+ * @return the total power consumption
+ */
public double getTotalConsumption() {
double consumption = 0;
for (PhysicalMachine pm : PMs.values()) {
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import at.ac.tuwien.lsdc.federation.Federation;
+import at.ac.tuwien.lsdc.management.MachineManager;
import at.ac.tuwien.lsdc.types.Application;
import at.ac.tuwien.lsdc.types.ScenarioData;
import at.ac.tuwien.lsdc.types.ScenarioType;
import at.ac.tuwien.lsdc.types.SchedulerData;
import at.ac.tuwien.lsdc.types.SchedulerEvent;
+import at.ac.tuwien.lsdc.types.SchedulerEvent.EventType;
import at.ac.tuwien.lsdc.types.SchedulerType;
+import at.ac.tuwien.lsdc.types.VirtualMachine.VMType;
import at.ac.tuwien.lsdc.util.CSVLogger;
public abstract class AbstractScheduler {
protected int numCurrInSourced;
protected int numCurrOutSourced;
- File schedulerLog;
- CSVLogger logger;
+ protected MachineManager machineManager;
+ protected Federation federation;
+ protected File schedulerLog;
+ protected CSVLogger logger;
+ protected VMType VMType;
// this map saves the following Type of Events:
// start of an Application, end of an Application
// (start outSourced, end outSourced, start inSourced, end inSourced)
protected HashMap<Long, LinkedList<SchedulerEvent>> eventMap;
+
+// // this map saves the following Type of Events:
+// // start of an Application, end of an Application
+// // (start outSourced, end outSourced, start inSourced, end inSourced)
+// protected HashMap<Long, LinkedList<SchedulerEvent>> endEventMap;
// Scheduler has an internal Time "Abstraction"
// at every point in time it checks for Events in his "EventList"
// it is updated with every added "EndEvent"
protected long endTime;
- public AbstractScheduler(File schedulerLog, SchedulerType schedulerType, ScenarioType scenario) throws IOException {
+ public AbstractScheduler(File schedulerLog, SchedulerType schedulerType, ScenarioType scenario, int numPMs, int numCloudPartners) throws IOException {
this.schedulerLog = schedulerLog;
this.schedulerType = schedulerType;
this.scenario = scenario;
+ this.machineManager = new MachineManager(numPMs);
+ this.federation = new Federation(numCloudPartners);
this.eventMap = new HashMap<Long,LinkedList<SchedulerEvent>>();
this.logger = new CSVLogger(schedulerLog);
}
// Initialize Scheduler with Data from CSV
// CSV will be parsed and sent as List<Application> to Scheduler
public ScenarioData initAndStart(LinkedList<Application> apps) {
- for (Application a : apps) {
- //System.out.println(a);
- // read start timestamp
- // save event in map
+ for (Application app : apps) {
+ insertStartEvent(app.getTimestamp(), app);
+ insertStopEvent(app.getTimestamp() + app.getDuration(), app);
}
startScheduling();
try {
}
return doEndLogging();
}
+
+ /**
+ * Insert a start event into the map, at timestamp when the application should start
+ * @param timestamp the timestamp when the application should start
+ * @param app the application to start
+ */
+ private void insertStartEvent(long timestamp, Application app) {
+ SchedulerEvent evt = new SchedulerEvent(timestamp, EventType.startApplication, app);
+ if(!eventMap.containsKey(timestamp)) {
+ LinkedList<SchedulerEvent> list = new LinkedList<SchedulerEvent>();
+ list.add(evt);
+ eventMap.put(timestamp, list);
+ } else {
+ LinkedList<SchedulerEvent> list = eventMap.get(timestamp);
+ list.add(evt);
+ }
+ }
+
+ /**
+ * Insert a stop event into the map, at timestamp when the application should stop
+ * @param timestamp the timestamp when the application should stop
+ * @param app the application to stop
+ */
+ private void insertStopEvent(long timestamp, Application app) {
+ SchedulerEvent evt = new SchedulerEvent(timestamp, EventType.endApplication, app);
+ if(!eventMap.containsKey(timestamp)) {
+ LinkedList<SchedulerEvent> list = new LinkedList<SchedulerEvent>();
+ list.add(evt);
+ eventMap.put(timestamp, list);
+ } else {
+ LinkedList<SchedulerEvent> list = eventMap.get(timestamp);
+ list.add(evt);
+ }
+ if(endTime < timestamp) {
+ endTime = timestamp;
+ }
+ }
protected void startScheduling() {
while (true) {
handleEvents(events);
doStateLogging();
//advance Time to next Event
+ currTime++;
if (currTime == endTime) {
// reached last Event, Scheduler will shut down
break;
import java.io.File;
import java.io.IOException;
+import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import edu.emory.mathcs.backport.java.util.Collections;
+
+import at.ac.tuwien.lsdc.exception.ActiveApplicationsException;
+import at.ac.tuwien.lsdc.types.Application;
+import at.ac.tuwien.lsdc.types.PhysicalMachine;
import at.ac.tuwien.lsdc.types.ScenarioType;
import at.ac.tuwien.lsdc.types.SchedulerEvent;
+import at.ac.tuwien.lsdc.types.SchedulerEvent.EventType;
import at.ac.tuwien.lsdc.types.SchedulerType;
+import at.ac.tuwien.lsdc.types.SortedApplication;
+import at.ac.tuwien.lsdc.types.SortedPhysicalMachine;
+import at.ac.tuwien.lsdc.types.VirtualMachine;
public class SchedulerA extends AbstractScheduler {
- public SchedulerA(File logFile, SchedulerType schedulerType, ScenarioType scenario) throws IOException {
- super(logFile, schedulerType, scenario);
+ private static final Logger log = LoggerFactory.getLogger(SchedulerA.class);
+
+ public SchedulerA(File logFile, SchedulerType schedulerType, ScenarioType scenario, int numPMs, int numCloudPartners) throws IOException {
+ super(logFile, schedulerType, scenario, numPMs, numCloudPartners);
+ this.VMType = VMType.NonResizable;
}
@Override
protected void handleEvents(LinkedList<SchedulerEvent> events) {
- // TODO Auto-generated method stub
+ for(SchedulerEvent evt : events) {
+ if(evt.getType() == EventType.endApplication) {
+ VirtualMachine vm = evt.getApp().getRunningOn();
+ vm.stopApplication(evt.getApp());
+ PhysicalMachine pm = vm.getRunningOn();
+ try {
+ pm.stopVirtualMachine(vm);
+ } catch (ActiveApplicationsException e) {
+ log.warn("VM "+vm.getId()+"could not be stopped, "+e.getMessage());
+ }
+ }
+ }
+
+ // sorting applications by amount of resources (descending)
+ List<SortedApplication> sortedApps = sortApps(events);
+
+ for(Iterator<SortedApplication> iter = sortedApps.iterator(); iter.hasNext(); ) {
+ boolean appDeployed = false;
+ Application app = iter.next().getApp();
+
+ if(machineManager.getPMs().size() == 0) {
+ PhysicalMachine pm = machineManager.startPhysicalMachine();
+ boolean enoughResources = pm.checkVM(app.getSize(), app.getRam(), app.getCpu());
+
+ if(enoughResources) {
+ pm.startVirtualMachine(app.getSize(), app.getRam(), app.getCpu(), VMType);
+ appDeployed = true;
+ log.debug("Application "+app.toString()+" started on new pm "+pm.getId());
+ }
+ else {
+ log.warn("Application "+app.toString()+" cannot be run on empty pm "+pm.getId());
+ }
+ }
+ else {
+ // sorting physical machines by resource utilization (descending)
+ List<SortedPhysicalMachine> sortedPMs = sortPMs();
+
+ for(Iterator<SortedPhysicalMachine> it = sortedPMs.iterator(); iter.hasNext(); ) {
+ PhysicalMachine pm = it.next().getPm();
+ boolean enoughResources = pm.checkVM(app.getSize(), app.getRam(), app.getCpu());
+
+ if(enoughResources) {
+ VirtualMachine vm = pm.startVirtualMachine(app.getSize(), app.getRam(), app.getCpu(), VMType);
+ vm.startApplication(app);
+ appDeployed = true;
+ log.debug("Application "+app.toString()+" started on new pm "+pm.getId());
+ break;
+ }
+ }
+ if(!appDeployed && (machineManager.getPMs().size() < machineManager.getMaxPMs())) {
+
+ PhysicalMachine pm = machineManager.startPhysicalMachine();
+ boolean enoughResources = pm.checkVM(app.getSize(), app.getRam(), app.getCpu());
+
+ if(enoughResources) {
+ VirtualMachine vm = pm.startVirtualMachine(app.getSize(), app.getRam(), app.getCpu(), VMType);
+ vm.startApplication(app);
+ appDeployed = true;
+ log.debug("Application "+app.toString()+" started on new pm "+pm.getId());
+ }
+ else {
+ log.warn("Application "+app.toString()+" cannot be run on empty pm "+pm.getId());
+ }
+ }
+ }
+ if(!appDeployed)
+ log.warn("Application "+app.toString()+" could not be deployed on any pm");
+ }
+ }
+
+ // sorting applications by amount of resources (descending)
+ private List<SortedApplication> sortApps(LinkedList<SchedulerEvent> events) {
+ List<SortedApplication> sortedApps = new LinkedList<SortedApplication>();
+ for(SchedulerEvent evt : events) {
+ if(evt.getType() == EventType.startApplication)
+ sortedApps.add(new SortedApplication(evt.getApp()));
+ }
+ Collections.sort(sortedApps);
+ Collections.reverse(sortedApps);
+ return sortedApps;
+ }
+
+ // sorting physical machines by resource utilization (descending)
+ private List<SortedPhysicalMachine> sortPMs() {
+ List<SortedPhysicalMachine> sortedPMs = new LinkedList<SortedPhysicalMachine>();
+ for(PhysicalMachine pm : machineManager.getPMs())
+ sortedPMs.add(new SortedPhysicalMachine(pm));
+
+ Collections.sort(sortedPMs);
+ Collections.reverse(sortedPMs);
+ return sortedPMs;
}
}
public class SchedulerB extends AbstractScheduler {
- public SchedulerB(File logFile, SchedulerType schedulerType, ScenarioType scenario) throws IOException {
- super(logFile, schedulerType, scenario);
+ public SchedulerB(File logFile, SchedulerType schedulerType, ScenarioType scenario, int numPMs, int numCloudPartners) throws IOException {
+ super(logFile, schedulerType, scenario, numPMs, numCloudPartners);
}
@Override
public class SchedulerC extends AbstractScheduler {
- public SchedulerC(File logFile, SchedulerType schedulerType, ScenarioType scenario) throws IOException {
- super(logFile,schedulerType,scenario);
+ public SchedulerC(File logFile, SchedulerType schedulerType, ScenarioType scenario, int numPMs, int numCloudPartners) throws IOException {
+ super(logFile, schedulerType, scenario, numPMs, numCloudPartners);
}
@Override
import java.util.HashMap;
+import at.ac.tuwien.lsdc.exception.ActiveApplicationsException;
+import at.ac.tuwien.lsdc.exception.VMsRunningException;
+import at.ac.tuwien.lsdc.types.VirtualMachine.VMType;
+
public class PhysicalMachine {
private static int count = 0;
running = true;
}
- public void stop() {
- // TODO: anything else we need to do? maybe implement a stop method in
- // VirtualMachine and call it on every VM
+ public void stop() throws VMsRunningException {
+ if(VMs.size() > 0)
+ throw new VMsRunningException("PM cannot be stopped. Some VMs still running");
+
VMs = new HashMap<Integer, VirtualMachine>();
size = 0;
RAM = 0;
}
public double getConsumption() {
- return 200 + 0.3 * CPU;
+ return 200 + 0.3 * (CPU - initialCPU);
}
- public int startVirtualMachine(int size, int RAM, int CPU) {
- if (checkVM(size, RAM, CPU)) {
- VirtualMachine vm = new VirtualMachine(size, RAM, CPU, this);
+ public VirtualMachine startVirtualMachine(int sz, int ram, int cpu, VMType type) {
+ if (checkVM(sz, ram, cpu)) {
+ VirtualMachine vm = new VirtualMachine(sz, ram, cpu, this, type);
VMs.put(vm.getId(), vm);
size = size + vm.getSize();
RAM = RAM + vm.getRAM();
CPU = CPU + vm.getCPU();
- return vm.getId();
+ return vm;
} else
- return -1;
+ return null;
}
- public boolean stopVirtualMachine(VirtualMachine vm) {
+ public void stopVirtualMachine(VirtualMachine vm) throws ActiveApplicationsException {
if (VMs.containsKey(vm.getId())) {
if (vm.getApplications().size() != 0) {
- // apps must be migrated before stopping a VM
- return false;
+ throw new ActiveApplicationsException("Applications must be migrated before stopping a vm, vm id "+vm.getId());
} else {
VMs.remove(vm.getId());
size = size - vm.getSize();
RAM = RAM - vm.getRAM();
CPU = CPU - vm.getCPU();
- return true;
}
- } else
- return false;
+ }
}
- private boolean checkVM(int size, int RAM, int CPU) {
+ public boolean checkVM(int size, int RAM, int CPU) {
return (size <= availableSize()) && (RAM <= availableRAM())
&& (CPU <= availableCPU());
}
private int availableCPU() {
return maxCPU - CPU;
}
+
+ public double getSizeUtilization() {
+ return ((double)(size - initialSize) / (maxSize - initialSize)) * 100;
+ }
+
+ public double getRamUtilization() {
+ return ((double)(RAM - initialRAM) / (maxRAM - initialRAM)) * 100;
+ }
+
+ public double getCpuUtilization() {
+ return ((double)(CPU - initialCPU) / (maxCPU - initialCPU)) * 100;
+ }
+
+ public double getAverageUtilization() {
+ return (getSizeUtilization() + getRamUtilization() + getCpuUtilization()) / 3.0;
+ }
public int getId() {
return id;
--- /dev/null
+package at.ac.tuwien.lsdc.types;
+
+public class SortedApplication implements Comparable<SortedApplication> {
+
+
+ private Application app;
+ final int BEFORE = -1;
+ final int EQUAL = 0;
+ final int AFTER = 1;
+
+ public SortedApplication(Application app) {
+ this.app = app;
+ }
+
+ @Override
+ public int compareTo(SortedApplication other) {
+ if (this == other)
+ return EQUAL;
+
+ if(getResourceDifference(other) < 0)
+ return BEFORE;
+ else if(getResourceDifference(other) > 0)
+ return AFTER;
+ else
+ return EQUAL;
+ }
+
+ public Application getApp() {
+ return app;
+ }
+
+ public int getResourceDifference(SortedApplication other) {
+ return app.getSize() - other.getApp().getSize() +
+ app.getRam() - other.getApp().getRam() +
+ app.getCpu() - other.getApp().getCpu();
+ }
+
+}
--- /dev/null
+package at.ac.tuwien.lsdc.types;
+
+public class SortedPhysicalMachine implements Comparable<SortedPhysicalMachine> {
+
+ private PhysicalMachine pm;
+ final int BEFORE = -1;
+ final int EQUAL = 0;
+ final int AFTER = 1;
+
+ public SortedPhysicalMachine(PhysicalMachine pm) {
+ this.pm = pm;
+ }
+
+ @Override
+ public int compareTo(SortedPhysicalMachine other) {
+ if(this == other)
+ return EQUAL;
+
+ if(pm.getAverageUtilization() < other.getPm().getAverageUtilization())
+ return BEFORE;
+ else if(pm.getAverageUtilization() > other.getPm().getAverageUtilization())
+ return AFTER;
+ else
+ return EQUAL;
+ }
+
+
+ public PhysicalMachine getPm() {
+ return pm;
+ }
+
+}
public class VirtualMachine {
+ public enum VMType {
+ Resizable, NonResizable
+ }
+
+
private static int count = 0;
private PhysicalMachine runningOn;
private int size;
private int RAM;
private int CPU;
+
+ private VMType type;
- public VirtualMachine(int size, int RAM, int CPU, PhysicalMachine pm) {
+ public VirtualMachine(int size, int RAM, int CPU, PhysicalMachine pm, VMType type) {
this.id = count;
count++;
this.size = size + initialSize;
this.RAM = RAM + initialRAM;
this.CPU = CPU + initialCPU;
this.runningOn = pm;
+ this.type = type;
}
public boolean startApplication(Application app) {
- if (checkApp(app)) {
+ if (enoughResources(app)) {
+ applications.put(app.getID(), app);
+ return true;
+ } else if (type == VMType.Resizable && runningOn.checkVM(app.getSize(), app.getRam(), app.getCpu())) {
applications.put(app.getID(), app);
size = size + app.getSize();
RAM = RAM + app.getRam();
return false;
}
- private boolean checkApp(Application app) {
+ private boolean enoughResources(Application app) {
return (app.getSize() <= availableSize())
&& (app.getRam() <= availableRAM())
&& (app.getCpu() <= availableCPU());