class Strategy(strategy.StrategyBase): def __init__(self, scoreboard, pump, model): super(Strategy, self).__init__(scoreboard, pump, model, INTERVAL, START_WAIT) # Setup migration queue simple = True self.migration_queue = MigrationQueue(self, simple, not simple) # Build allocations self.placement = initial_placement_dsap_helper.DSAPPlacement() self.initial_migrations, self.active_server_info = self.placement.execute(NUM_BUCKETS, lambda x: np.percentile(x, PERCENTILE), MIGRATION_LIMIT) # Current bucket self.curr_bucket = 0 def start(self): # Initialization time self.time_null = self.pump.sim_time() # Super call super(Strategy, self).start() def dump(self): print 'DSAP controller - Dump configuration...' logger.info('Strategy Configuration: %s' % json.dumps({'name' : 'DSAP-Strategy', 'start_wait' : START_WAIT, 'interval' : INTERVAL, 'num_bucketsl' : NUM_BUCKETS, })) def __run_migrations(self, bucket_index): # Assignment curr_assignment = self.placement.assignment_list[bucket_index] # Previous assignment (based on model data - not uncertain calculation data) # Calculated data might be different from model data due to failed migrations # prev_assignment = self.placement.assignment_list[(bucket_index - 1) % NUM_BUCKETS] prev_assignment = self.model.get_assignment_list() for index_domain in curr_assignment.keys(): # Get data domain_name = conf_domains.initial_domains[index_domain].name source_node = conf_nodes.get_node_name(prev_assignment[index_domain]) target_node = conf_nodes.get_node_name(curr_assignment[index_domain]) # Find current node for domain source_node = self.model.get_host_for_domain(domain_name).name # Trigger migration model_domain = self.model.get_host(domain_name) model_source = self.model.get_host(source_node) model_target = self.model.get_host(target_node) self.migration_queue.add(model_domain, model_source, model_target) def __run_optimized_migrations(self, bucket_index): # Create allocations lists for GOAP # Assignment curr_assignment = self.placement.assignment_list[bucket_index] # Previous assignment prev_assignment = self.placement.assignment_list[(bucket_index - 1) % NUM_BUCKETS] as_current = [0 for _ in xrange(conf_domains.count())] as_next = [0 for _ in xrange(conf_domains.count())] for index_domain in xrange(conf_domains.count()): as_current[index_domain] = prev_assignment[index_domain] as_next[index_domain] = curr_assignment[index_domain] # Get current domain loads domain_load = [] for mapping in conf_domains.initial_domains: domain_name = mapping.domain load = self.model.get_host(domain_name).mean_load(20) domain_load.append(conf_nodes.to_node_load(load, conf_domainsize.DEFAULT)) # Schedule migrations from ai import astar migrations = astar.plan(conf_nodes.NODE_COUNT, as_current, as_next, domain_load) # Trigger migrations dep = None for migration in migrations: domain_name = conf_domains.initial_domains[migration[0]].domain source_node = conf_nodes.get_node_name(migration[1]) target_node = conf_nodes.get_node_name(migration[2]) print 'domain %s - source %s - target %s' % (domain_name, source_node, target_node) model_domain = self.model.get_host(domain_name) model_source = self.model.get_host(source_node) model_target = self.model.get_host(target_node) # dep = self.migration_queue.add(model_domain, model_source, model_target, dep) dep = self.migration_queue.add(model_domain, model_source, model_target) return def balance(self): # Current bucket index bucket_duration = TOTAL_EXPERIMENT_DURATION / NUM_BUCKETS time = self.pump.sim_time() - self.time_null # relative time since end of ramp-up and start of steady-state timeg = time # global time in TS data bucket_index = int(timeg / bucket_duration) # always floor this value bucket_time = bucket_duration - (timeg - bucket_duration * bucket_index) # bucket_index %= NUM_BUCKETS print 'bucket index %i' % bucket_index print 'time till next bucket %i' % (bucket_time) if bucket_index >= NUM_BUCKETS: return # Schedule migrations only once per bucket if self.curr_bucket == bucket_index: return # Wait for migration queue to finish up all migrations if not self.migration_queue.empty(): return # Update current bucket status self.curr_bucket = bucket_index # Trigger migrations to get new bucket allocation self.__run_migrations(self.curr_bucket) # self.__run_optimized_migrations(self.curr_bucket) def post_migrate_hook(self, success, domain, node_from, node_to, end_time): node_from.blocked = self.pump.sim_time() - 1 node_to.blocked = self.pump.sim_time() - 1 self.migration_queue.finished(success, domain, node_from, node_to)
class Strategy(strategy.StrategyBase): def __init__(self, scoreboard, pump, model): super(Strategy, self).__init__(scoreboard, pump, model, INTERVAL, START_WAIT) # Setup migration queue simple = True self.migration_queue = MigrationQueue(self, simple, not simple, True) def start(self): # Super call super(Strategy, self).start() def dump(self): print 'DSAP controller - Dump configuration...' logger.info('Strategy Configuration: %s' % json.dumps({'name' : 'DSAP-Strategy', 'start_wait' : START_WAIT, 'interval' : INTERVAL, })) def __run_migrations(self): conversion_table = {} prev_assignment = {} i = 0 for node in self.model.get_hosts(types.NODE): for domain_name in node.domains.keys(): conversion_table[i] = domain_name prev_assignment[i] = conf_nodes.index_of(node.name) i +=1 inverse_conversion_table = {domain_name : i for i, domain_name in conversion_table.iteritems()} demand_cpu = {} demand_mem = {} for domain in self.model.get_hosts(types.DOMAIN): if domain in conf_domains.initial_domains: domain_size = conf_domains.initial_domains[conf_domains.initial_domain_index(domain.name)].size else: domain_size = conf_domains.available_domains[conf_domains.available_domain_index(domain.name)].size domain_index = inverse_conversion_table[domain.name] cpu_readings = domain.get_readings() domain_load = conf_nodes.to_node_load(np.mean(cpu_readings[-NUM_CPU_READINGS:]), domain_size) demand_cpu[domain_index] = domain_load demand_mem[domain_index] = domain.domain_configuration.get_domain_spec().total_memory() print 'domain : %d, demand_cpu : %d, demand_memory : %d' % (domain_index, domain_load, domain.domain_configuration.get_domain_spec().total_memory()) # Assignment try: _, curr_assignment = dsapp.solve(conf_nodes.NODE_COUNT, conf_nodes.UTIL, conf_nodes.NODE_MEM, demand_cpu, demand_mem, prev_assignment, MIG_OVERHEAD_SOURCE, MIG_OVERHEAD_TARGET) except: print 'invalid solution #######################' # don't change anything and just return in case the model was infeasible return assignment_changed = dsapp.AssignmentChanged(prev_assignment, curr_assignment) print 'CHANGE in the Assignment : %s' % assignment_changed if not assignment_changed: # there is no change in the assignment, we can just return logger.info("Returning because the previous assignment was optimal...") return for index_domain in curr_assignment.keys(): domain_name = conversion_table[index_domain] source_node = conf_nodes.get_node_name(prev_assignment[index_domain]) target_node = conf_nodes.get_node_name(curr_assignment[index_domain]) # Find current node for domain source_node = self.model.get_host_for_domain(domain_name).name # Trigger migration model_domain = self.model.get_host(domain_name) model_source = self.model.get_host(source_node) model_target = self.model.get_host(target_node) self.migration_queue.add(model_domain, model_source, model_target) def balance(self): # Wait for migration queue to finish up all migrations if not self.migration_queue.empty(): return # Trigger migrations self.__run_migrations() def post_migrate_hook(self, success, domain, node_from, node_to, end_time): node_from.blocked = self.pump.sim_time() - 1 node_to.blocked = self.pump.sim_time() - 1 self.migration_queue.finished(success, domain, node_from, node_to)