/src/cws/core/algorithms/SPSS.java

https://github.com/malawski/cloudworkflowsimulator · Java · 261 lines · 176 code · 42 blank · 43 comment · 39 complexity · be14ef191ba9ee1af06c6d529f4d791e MD5 · raw file

  1. package cws.core.algorithms;
  2. import java.util.Collections;
  3. import java.util.Comparator;
  4. import java.util.HashMap;
  5. import java.util.LinkedList;
  6. import java.util.List;
  7. import cws.core.cloudsim.CloudSimWrapper;
  8. import cws.core.core.VMType;
  9. import cws.core.dag.DAG;
  10. import cws.core.dag.Task;
  11. import cws.core.dag.algorithms.TopologicalOrder;
  12. import cws.core.engine.Environment;
  13. /**
  14. * @author Gideon Juve <juve@usc.edu>
  15. */
  16. public class SPSS extends StaticAlgorithm {
  17. /** Tuning parameter for deadline distribution (low alpha = runtime, high alpha = tasks) */
  18. private double alpha;
  19. public SPSS(double budget, double deadline, List<DAG> dags, double alpha, AlgorithmStatistics ensembleStatistics,
  20. Environment environment, CloudSimWrapper cloudsim) {
  21. super(budget, deadline, dags, ensembleStatistics, environment, cloudsim);
  22. this.alpha = alpha;
  23. }
  24. /**
  25. * Develop a plan for a single DAG
  26. */
  27. @Override
  28. Plan planDAG(DAG dag, Plan currentPlan) throws NoFeasiblePlan {
  29. HashMap<Task, Double> runtimes = new HashMap<Task, Double>();
  30. TopologicalOrder order = computeTopologicalOrder(dag, runtimes);
  31. /**
  32. * FIXME Later we will determine the best VM type for each task
  33. *
  34. * <pre>
  35. * assignEachTaskToCheapestResource()
  36. * criticalPath = computeCriticalPath()
  37. * while (criticalPath > deadline) {
  38. * upgradeTaskWithBestBangForBuck()
  39. * criticalPath = computeCriticalPath()
  40. * }
  41. * </pre>
  42. */
  43. // Get deadlines for each task (deadline distribution)
  44. final HashMap<Task, Double> deadlines = getDeadlineDistribution(order, runtimes, this.alpha);
  45. // Sort tasks by deadline
  46. LinkedList<Task> sortedTasks = new LinkedList<Task>();
  47. for (Task t : order) {
  48. sortedTasks.add(t);
  49. }
  50. Comparator<Task> deadlineComparator = new Comparator<Task>() {
  51. @Override
  52. public int compare(Task t1, Task t2) {
  53. double d1 = deadlines.get(t1);
  54. double d2 = deadlines.get(t2);
  55. if (d1 < d2) {
  56. return -1;
  57. } else if (d1 > d2) {
  58. return 1;
  59. } else {
  60. return 0;
  61. }
  62. }
  63. };
  64. Collections.sort(sortedTasks, deadlineComparator);
  65. // Create a new plan
  66. Plan plan = new Plan(currentPlan);
  67. // Actual finish times of tasks
  68. HashMap<Task, Double> finishTimes = new HashMap<Task, Double>();
  69. // Assign resources to each task
  70. for (Task task : sortedTasks) {
  71. double runtime = runtimes.get(task);
  72. double deadline = deadlines.get(task);
  73. // Compute earliest start time of task
  74. double earliestStart = 0.0;
  75. for (Task parent : task.getParents()) {
  76. earliestStart = Math.max(earliestStart, finishTimes.get(parent));
  77. }
  78. Solution newResource;
  79. // Best scheduling solution for task
  80. Solution best;
  81. {
  82. // Default is to allocate a new resource
  83. Resource r = new Resource(getEnvironment());
  84. double cost = r.getCostWith(earliestStart, earliestStart + runtime);
  85. Slot sl = new Slot(task, earliestStart, runtime);
  86. best = newResource = new Solution(r, sl, cost, true);
  87. }
  88. // Check each resource for a better (cheaper, earlier) solution
  89. for (Resource r : plan.resources) {
  90. // Try placing task at the beginning of resource schedule
  91. if (earliestStart + runtime < r.getStart()) {
  92. // Option 1: Leave no gap
  93. nogap: {
  94. double ast = r.getStart() - runtime;
  95. if (ast < earliestStart) {
  96. break nogap;
  97. }
  98. double aft = ast + runtime;
  99. if (aft > deadline || aft > r.getStart()) {
  100. break nogap;
  101. }
  102. double cost = r.getCostWith(ast, r.getEnd()) - r.getCost();
  103. Slot slot = new Slot(task, ast, runtime);
  104. Solution soln = new Solution(r, slot, cost, false);
  105. if (soln.betterThan(best)) {
  106. best = soln;
  107. }
  108. }
  109. // Option 2: Leave a big gap
  110. biggap: {
  111. double ast = r.getStart() - getEnvironment().getPricingManager().getFullRuntime(runtime);
  112. if (ast < earliestStart) {
  113. ast = earliestStart;
  114. }
  115. double aft = ast + runtime;
  116. if (aft > deadline || aft > r.getStart()) {
  117. break biggap;
  118. }
  119. double cost = r.getCostWith(ast, r.getEnd()) - r.getCost();
  120. Slot sl = new Slot(task, ast, runtime);
  121. Solution soln = new Solution(r, sl, cost, false);
  122. if (soln.betterThan(best)) {
  123. best = soln;
  124. }
  125. }
  126. // Option 3: Use some slack time (medium gap)
  127. slack: {
  128. double slack = (getEnvironment().getPricingManager().getFullRuntime(r.getStart(), r.getEnd()))
  129. - (r.getEnd() - r.getStart());
  130. double ast = r.getStart() - slack;
  131. if (ast < earliestStart) {
  132. ast = earliestStart;
  133. }
  134. double aft = ast + runtime;
  135. if (aft > deadline || aft > r.getStart()) {
  136. break slack;
  137. }
  138. // This solution should be free because we add no billing units
  139. double cost = r.getCostWith(ast, r.getEnd()) - r.getCost();
  140. if (cost > 1e-6) {
  141. throw new RuntimeException("Solution should be free");
  142. }
  143. Slot sl = new Slot(task, ast, runtime);
  144. Solution soln = new Solution(r, sl, cost, false);
  145. if (soln.betterThan(best)) {
  146. best = soln;
  147. }
  148. }
  149. }
  150. // Try placing it in a gap in the schedule
  151. double lastEnd = -1;
  152. gap: for (double start : r.getStartTimes()) {
  153. double begin = lastEnd;
  154. double end = start;
  155. lastEnd = start + r.schedule.get(start).duration;
  156. // This just skips the first occupied slot
  157. if (begin < 0) {
  158. continue gap;
  159. }
  160. if (begin == end) {
  161. continue gap;
  162. }
  163. // Sanity check
  164. if (begin > end && begin - end > 1e-9) {
  165. throw new RuntimeException("Negative sized empty slot");
  166. }
  167. double ast;
  168. if (begin >= earliestStart) {
  169. ast = begin;
  170. } else {
  171. ast = earliestStart;
  172. }
  173. double aft = ast + runtime;
  174. if (aft <= end && aft <= deadline) {
  175. double cost = 0.0; // free as in beer
  176. Slot sl = new Slot(task, ast, runtime);
  177. Solution soln = new Solution(r, sl, cost, false);
  178. if (soln.betterThan(best)) {
  179. best = soln;
  180. }
  181. // We won't find a better solution by looking at later
  182. // gaps, so we can stop looking here
  183. break gap;
  184. }
  185. }
  186. // Try to placing it at the end of the schedule
  187. atend: if (r.getEnd() + runtime < deadline) {
  188. // Actual start time
  189. double ast;
  190. if (earliestStart < r.getEnd()) {
  191. ast = r.getEnd();
  192. } else {
  193. ast = earliestStart;
  194. }
  195. // Actual finish time
  196. double aft = ast + runtime;
  197. if (aft > deadline) {
  198. break atend;
  199. }
  200. double cost = r.getCostWith(r.getStart(), aft) - r.getCost();
  201. Slot sl = new Slot(task, ast, runtime);
  202. Solution soln = new Solution(r, sl, cost, false);
  203. if (soln.betterThan(best)) {
  204. best = soln;
  205. }
  206. }
  207. }
  208. if (newResource.cost < best.cost) {
  209. getCloudsim()
  210. .log(String.format("%s best: %f %s\n", task.getId(), best.cost, newResource.betterThan(best)));
  211. }
  212. // Schedule task on resource of best solution
  213. best.addToPlan(plan);
  214. // Save actual finish time of task
  215. finishTimes.put(task, best.slot.start + runtime);
  216. }
  217. return plan;
  218. }
  219. }