/core/analytical/analytical_solver.py

https://gitlab.com/gmarciani/pydes
Python | 215 lines | 140 code | 34 blank | 41 comment | 17 complexity | a18507cc09f8e58cd7ac7aa7bce21712 MD5 | raw file
  1. from core.analytical.analytical_solution import AnalyticalSolution
  2. from core.utils.logutils import ConsoleHandler
  3. from core.simulation.model.scope import TaskScope
  4. from core.utils.report import SimpleReport as Report
  5. from core.random.rndvar import Variate
  6. from core.simulation.model.scope import SystemScope
  7. from core.markov import markovgen
  8. import logging
  9. # Configure logger
  10. logging.basicConfig(level=logging.INFO, handlers=[ConsoleHandler(logging.INFO)])
  11. logger = logging.getLogger(__name__)
  12. class AnalyticalSolver:
  13. """
  14. A solver for the analytical model of the target system.
  15. """
  16. def __init__(self, config):
  17. """
  18. Creates a new anaytical solver.
  19. :param config: (Configuration) the system configuration.
  20. """
  21. # Validate configuration: Markovian assumption must holds true.
  22. assert config["arrival"][TaskScope.TASK_1.name]["distribution"] == "EXPONENTIAL"
  23. assert config["arrival"][TaskScope.TASK_2.name]["distribution"] == "EXPONENTIAL"
  24. assert config["system"]["cloudlet"]["service"][TaskScope.TASK_1.name]["distribution"] == "EXPONENTIAL"
  25. assert config["system"]["cloudlet"]["service"][TaskScope.TASK_2.name]["distribution"] == "EXPONENTIAL"
  26. assert config["system"]["cloud"]["service"][TaskScope.TASK_1.name]["distribution"] == "EXPONENTIAL"
  27. assert config["system"]["cloud"]["service"][TaskScope.TASK_2.name]["distribution"] == "EXPONENTIAL"
  28. self.config = config
  29. # Dimensions
  30. self.clt_n_servers = self.config["system"]["cloudlet"]["n_servers"]
  31. self.clt_threshold = self.config["system"]["cloudlet"]["threshold"]
  32. # Arrivals
  33. self.arrival_rates = {tsk: self.config["arrival"][tsk.name]["parameters"]["r"] for tsk in TaskScope.concrete()}
  34. self.service_rates = {sys: {tsk: self.config["system"][sys.name.lower()]["service"][tsk.name]["parameters"]["r"] for tsk in TaskScope.concrete()} for sys in SystemScope.subsystems()}
  35. self.t_setup = self.config["system"]["cloud"]["setup"][TaskScope.TASK_2.name]["parameters"]["m"]
  36. print(self.arrival_rates)
  37. print(self.service_rates)
  38. print(self.t_setup)
  39. self.solution = None
  40. def solve(self, routing_a_clt_1=None, routing_a_clt_2=None, routing_r=None, t_lost_clt_2=None):
  41. """
  42. Solves the analytical model of the target system.
  43. :param config: (Configuration) the system configuration.
  44. :param routing_a_clt_1: (float) the routing probability of accepted tasks 1 in Cloudlet.
  45. :param routing_a_clt_2: (float) the routing probability of accepted tasks 2 in Cloudlet.
  46. :param routing_r: (float) the routing probability of restarted tasks 2 in Cloud.
  47. :param t_lost_clt_2: (float) the average time lost by tasks 2 in Cloudlet.
  48. :return: None
  49. """
  50. # Compute routing probabilities (if not yet computed).
  51. if routing_a_clt_1 is None or routing_a_clt_2 is None or routing_r is None:
  52. MC = markovgen.generate_markov_chain(self.clt_n_servers, self.clt_threshold,
  53. self.arrival_rates[TaskScope.TASK_1],
  54. self.arrival_rates[TaskScope.TASK_2],
  55. self.service_rates[SystemScope.CLOUDLET][TaskScope.TASK_1],
  56. self.service_rates[SystemScope.CLOUDLET][TaskScope.TASK_2])
  57. states = MC.get_states()
  58. states_clt_1 = markovgen.compute_states_clt_1(states, self.clt_n_servers)
  59. states_clt_2 = markovgen.compute_states_clt_2(states, self.clt_n_servers, self.clt_threshold)
  60. states_clt_3 = markovgen.compute_states_clt_3(states, self.clt_n_servers, self.clt_threshold)
  61. solutions = markovgen.solve(MC)
  62. routing_a_clt_1 = 0
  63. for state_clt_1 in states_clt_1:
  64. routing_a_clt_1 += solutions[state_clt_1.pretty_str()]
  65. routing_a_clt_2 = 0
  66. for state_clt_2 in states_clt_2:
  67. routing_a_clt_2 += solutions[state_clt_2.pretty_str()]
  68. routing_r = 0
  69. for state_clt_3 in states_clt_3:
  70. routing_r += solutions[state_clt_3.pretty_str()]
  71. routing_r *= (self.arrival_rates[TaskScope.TASK_1] / (self.arrival_rates[TaskScope.TASK_1] + self.arrival_rates[TaskScope.TASK_2]))
  72. # Compute the average time lost by 2nd class tasks in Cloudlet (if not yet computed).
  73. T_lost_clt_2 = t_lost_clt_2 if t_lost_clt_2 is not None else 0.5 * (1.0 / self.service_rates[SystemScope.CLOUDLET][TaskScope.TASK_2])
  74. # Accepted Traffic
  75. lambda_clt_1 = routing_a_clt_1 * self.arrival_rates[TaskScope.TASK_1]
  76. lambda_clt_2 = routing_a_clt_2 * self.arrival_rates[TaskScope.TASK_2]
  77. lambda_cld_1 = (1.0 - routing_a_clt_1) * self.arrival_rates[TaskScope.TASK_1]
  78. lambda_cld_2 = (1.0 - routing_a_clt_2) * self.arrival_rates[TaskScope.TASK_2]
  79. # Restarted Traffic
  80. lambda_r = routing_r * (self.arrival_rates[TaskScope.TASK_1] + self.arrival_rates[TaskScope.TASK_2])
  81. # Performance Metrics: Cloudlet
  82. T_clt_1 = 1.0 / self.service_rates[SystemScope.CLOUDLET][TaskScope.TASK_1]
  83. N_clt_1 = lambda_clt_1 * T_clt_1
  84. T_clt_2 = 1.0 / self.service_rates[SystemScope.CLOUDLET][TaskScope.TASK_2]
  85. N_clt_2 = (lambda_clt_2 * T_clt_2) - (lambda_r * T_lost_clt_2)
  86. N_clt = N_clt_1 + N_clt_2
  87. T_clt = ((N_clt_1 / N_clt) * T_clt_1) + ((N_clt_2 / N_clt) * T_clt_2)
  88. X_clt_1 = lambda_clt_1
  89. X_clt_2 = lambda_clt_2 - lambda_r
  90. X_clt = lambda_clt_1 + lambda_clt_2 - lambda_r
  91. # Performance Metrics: Cloud
  92. T_cld_1 = 1.0 / self.service_rates[SystemScope.CLOUD][TaskScope.TASK_1]
  93. N_cld_1 = lambda_cld_1 * T_cld_1
  94. T_cld_2_np = 1.0 / self.service_rates[SystemScope.CLOUD][TaskScope.TASK_2]
  95. N_cld_2_np = lambda_cld_2 * T_cld_2_np
  96. T_cld_2_p = T_cld_2_np + self.t_setup # TODO WARNING maybe we should add T_lost_cld_2
  97. N_cld_2_p = lambda_r * T_cld_2_p
  98. N_cld_2 = N_cld_2_np + N_cld_2_p
  99. T_cld_2 = ((N_cld_2_np / N_cld_2) * T_cld_2_np) + ((N_cld_2_p / N_cld_2) * T_cld_2_p)
  100. N_cld = N_cld_1 + N_cld_2
  101. T_cld = ((N_cld_1 / N_cld) * T_cld_1) + ((N_cld_2 / N_cld) * T_cld_2)
  102. X_cld_1 = lambda_cld_1
  103. X_cld_2 = lambda_cld_2 + lambda_r
  104. X_cld = lambda_cld_1 + lambda_cld_2 + lambda_r
  105. # Performance Metrics: System
  106. N_sys_1 = N_clt_1 + N_cld_1
  107. N_sys_2 = N_cld_1 + N_cld_2
  108. N_sys = N_clt + N_cld
  109. T_sys_1 = ((N_clt_1 / N_sys) * T_clt_1) + ((N_cld_1 / N_sys) * T_cld_1)
  110. T_sys_2 = ((N_clt_2 / N_sys) * T_clt_2) + ((N_cld_2 / N_sys) * T_cld_2)
  111. T_sys = ((N_clt / N_sys) * T_clt) + ((N_cld / N_sys) * T_cld)
  112. X_sys_1 = X_clt_1 + X_cld_1
  113. X_sys_2 = X_clt_2 + X_cld_2
  114. X_sys = X_sys_1 + X_sys_2
  115. logger.info("routing_a_clt_1 = %f" % routing_a_clt_1)
  116. logger.info("routing_a_clt_2 = %f" % routing_a_clt_2)
  117. logger.info("routing_r = %f" % routing_r)
  118. logger.info("T_lost_clt_2 = %f" % T_lost_clt_2)
  119. self.solution = AnalyticalSolution()
  120. # System
  121. self.solution.performance_metrics.population[SystemScope.SYSTEM][TaskScope.TASK_1] = N_sys_1
  122. self.solution.performance_metrics.population[SystemScope.SYSTEM][TaskScope.TASK_2] = N_sys_2
  123. self.solution.performance_metrics.population[SystemScope.SYSTEM][TaskScope.GLOBAL] = N_sys
  124. self.solution.performance_metrics.response[SystemScope.SYSTEM][TaskScope.TASK_1] = T_sys_1
  125. self.solution.performance_metrics.response[SystemScope.SYSTEM][TaskScope.TASK_2] = T_sys_2
  126. self.solution.performance_metrics.response[SystemScope.SYSTEM][TaskScope.GLOBAL] = T_sys
  127. self.solution.performance_metrics.throughput[SystemScope.SYSTEM][TaskScope.TASK_1] = X_sys_1
  128. self.solution.performance_metrics.throughput[SystemScope.SYSTEM][TaskScope.TASK_2] = X_sys_2
  129. self.solution.performance_metrics.throughput[SystemScope.SYSTEM][TaskScope.GLOBAL] = X_sys
  130. # Cloudlet
  131. self.solution.performance_metrics.population[SystemScope.CLOUDLET][TaskScope.TASK_1] = N_clt_1
  132. self.solution.performance_metrics.population[SystemScope.CLOUDLET][TaskScope.TASK_2] = N_clt_2
  133. self.solution.performance_metrics.population[SystemScope.CLOUDLET][TaskScope.GLOBAL] = N_clt
  134. self.solution.performance_metrics.response[SystemScope.CLOUDLET][TaskScope.TASK_1] = T_clt_1
  135. self.solution.performance_metrics.response[SystemScope.CLOUDLET][TaskScope.TASK_2] = T_clt_2
  136. self.solution.performance_metrics.response[SystemScope.CLOUDLET][TaskScope.GLOBAL] = T_clt
  137. self.solution.performance_metrics.throughput[SystemScope.CLOUDLET][TaskScope.TASK_1] = X_clt_1
  138. self.solution.performance_metrics.throughput[SystemScope.CLOUDLET][TaskScope.TASK_2] = X_clt_2
  139. self.solution.performance_metrics.throughput[SystemScope.CLOUDLET][TaskScope.GLOBAL] = X_clt
  140. # Cloud
  141. self.solution.performance_metrics.population[SystemScope.CLOUD][TaskScope.TASK_1] = N_cld_1
  142. self.solution.performance_metrics.population[SystemScope.CLOUD][TaskScope.TASK_2] = N_cld_2
  143. self.solution.performance_metrics.population[SystemScope.CLOUD][TaskScope.GLOBAL] = N_cld
  144. self.solution.performance_metrics.response[SystemScope.CLOUD][TaskScope.TASK_1] = T_cld_1
  145. self.solution.performance_metrics.response[SystemScope.CLOUD][TaskScope.TASK_2] = T_cld_2
  146. self.solution.performance_metrics.response[SystemScope.CLOUD][TaskScope.GLOBAL] = T_cld
  147. self.solution.performance_metrics.throughput[SystemScope.CLOUD][TaskScope.TASK_1] = X_cld_1
  148. self.solution.performance_metrics.throughput[SystemScope.CLOUD][TaskScope.TASK_2] = X_cld_2
  149. self.solution.performance_metrics.throughput[SystemScope.CLOUD][TaskScope.GLOBAL] = X_cld
  150. # ==================================================================================================================
  151. # REPORT
  152. # ==================================================================================================================
  153. def generate_report(self):
  154. """
  155. Generate the solver report.
  156. :return: (SimpleReport) the solver report.
  157. """
  158. r = Report("ANALYTICAL-SOLUTION")
  159. # Report - Arrivals
  160. for tsk in TaskScope.concrete():
  161. r.add("arrival", "arrival_{}_dist".format(tsk.name.lower()), Variate.EXPONENTIAL.name)
  162. r.add("arrival", "arrival_{}_rate".format(tsk.name.lower()), self.arrival_rates[tsk])
  163. # Report - System/Cloudlet
  164. r.add("system/cloudlet", "n_servers", self.clt_n_servers)
  165. r.add("system/cloudlet", "threshold", self.clt_threshold)
  166. for tsk in TaskScope.concrete():
  167. r.add("system/cloudlet", "service_{}_dist".format(tsk.name.lower()), Variate.EXPONENTIAL.name)
  168. r.add("system/cloudlet", "service_{}_rate".format(tsk.name.lower()), self.service_rates[SystemScope.CLOUDLET][tsk])
  169. # Report - System/Cloud
  170. for tsk in TaskScope.concrete():
  171. r.add("system/cloud", "service_{}_dist".format(tsk.name.lower()), Variate.EXPONENTIAL.name)
  172. r.add("system/cloud", "service_{}_rate".format(tsk.name.lower()), self.service_rates[SystemScope.CLOUD][tsk])
  173. r.add("system/cloud", "setup_{}_dist".format(TaskScope.TASK_2.name.lower()), Variate.EXPONENTIAL.name)
  174. r.add("system/cloud", "service_{}_param_m".format(TaskScope.TASK_2.name.lower()), self.t_setup)
  175. # Report - Statistics
  176. for performance_metric in sorted(self.solution.performance_metrics.__dict__):
  177. for sys in sorted(SystemScope, key=lambda x: x.name):
  178. for tsk in sorted(TaskScope, key=lambda x: x.name):
  179. r.add("statistics", "{}_{}_{}_mean".format(performance_metric, sys.name.lower(), tsk.name.lower()),
  180. getattr(self.solution.performance_metrics, performance_metric)[sys][tsk])
  181. return r