in DSE_utils/hill_climbing.py [0:0]
def select_block_to_migrate_to(self, ex_dp, sim_dp, hot_blck_synced, selected_metric, sorted_metric_dir, selected_krnl):
# get initial information
locality_type = []
parallelism_type =[]
task = ex_dp.get_hardware_graph().get_task_graph().get_task_by_name(selected_krnl.get_task_name())
selected_metric = list(sorted_metric_dir.keys())[-1]
selected_dir = sorted_metric_dir[selected_metric]
# find blocks equal or immeidately better
equal_imm_blocks_present_for_migration = self.dh.get_equal_immediate_blocks_present(ex_dp, hot_blck_synced,
selected_metric, selected_dir, [task])
# does parallelism exist in the current occupying block
current_block_parallelism_exist, parallelism_type = self.check_if_task_can_run_with_any_other_task_in_parallel(sim_dp,
task,
hot_blck_synced)
inequality_dir = selected_dir*-1
results_block = [] # results
task_s_blocks = ex_dp.get_hardware_graph().get_blocks_of_task(task)
if len(task_s_blocks) == 0:
print("a task must have at lease three blocks")
exit(0)
remove_list = [] # list of blocks to remove from equal_imm_blocks_present_for_migration
# improve locality by only allowing migration to the PE/MEM close by
if hot_blck_synced.type == "mem":
# only keep memories that are connected to the IC neighbour of the task's pe
# This is to make sure that we keep data local (to the router), instead of migrating to somewhere far
task_s_pe = [blk for blk in task_s_blocks if blk.type == "pe"][0] # get task's pe
tasks_s_ic = [el for el in task_s_pe.get_neighs() if el.type == "ic"][0] # get pe's ic
potential_mems = [el for el in tasks_s_ic.get_neighs() if el.type == "mem"] # get ic's memories
for el in equal_imm_blocks_present_for_migration:
if el not in potential_mems:
remove_list.append(el)
locality_type = ["spatial_locality"]
for el in remove_list:
equal_imm_blocks_present_for_migration.remove(el)
elif hot_blck_synced.type == "pe":
# only keep memories that are connected to the IC neighbour of the task's pe
# This is to make sure that we keep data local (to the router), instead of migrating to somewhere far
task_s_mems = [blk for blk in task_s_blocks if blk.type == "mem"] # get task's pe
potential_pes = []
for task_s_mem in task_s_mems:
tasks_s_ic = [el for el in task_s_mem.get_neighs() if el.type == "ic"][0] # get pe's ic
potential_pes.extend([el for el in tasks_s_ic.get_neighs() if el.type == "pe"]) # get ic's memories
for el in equal_imm_blocks_present_for_migration:
if el not in potential_pes:
remove_list.append(el)
locality_type = ["spatial_locality"]
for el in remove_list:
equal_imm_blocks_present_for_migration.remove(el)
# iterate through the blocks and find the best one
for block_to_migrate_to in equal_imm_blocks_present_for_migration:
# skip yourself
if block_to_migrate_to == hot_blck_synced:
continue
block_metric_attr = self.get_block_attr(selected_metric) # metric to pay attention to
# iterate and found blocks that are at least as good as the current block
if getattr(block_to_migrate_to, block_metric_attr) == getattr(hot_blck_synced, block_metric_attr):
# blocks have similar attr value
if (selected_metric == "power" and selected_dir == -1) or \
(selected_metric == "latency" and selected_dir == 1) or (selected_metric == "area"):
# if we want to slow down (reduce latency, improve power), look for parallel task on the other block
block_to_mig_to_parallelism_exist, parallelism_type = self.check_if_task_can_run_with_any_other_task_in_parallel(sim_dp,
task,
block_to_migrate_to)
if (selected_metric == "area" and selected_dir == -1):
# no parallelism possibly allows for theo the other memory to shrink
if not block_to_mig_to_parallelism_exist:
results_block.append(block_to_migrate_to)
parallelism_type = ["serialism"]
else:
if block_to_mig_to_parallelism_exist:
results_block.append(block_to_migrate_to)
parallelism_type = ["serialism"]
else:
# if we want to accelerate (improve latency, get more power), look for parallel task on the same block
if current_block_parallelism_exist:
results_block.append(block_to_migrate_to)
elif inequality_dir*getattr(block_to_migrate_to, block_metric_attr) > inequality_dir*getattr(hot_blck_synced, block_metric_attr):
results_block.append(block_to_migrate_to)
break
# if no block found, just load the results_block with current block
if len(results_block) == 0:
results_block = [hot_blck_synced]
found_block_to_mig_to = False
else:
found_block_to_mig_to = True
# pick at random to try random scenarios. At the moment, only equal and immeidately better blocks are considered
random.seed(datetime.now().microsecond)
result_block = random.choice(results_block)
selection_mode = "batch"
if found_block_to_mig_to:
if getattr(result_block, block_metric_attr) == getattr(hot_blck_synced, block_metric_attr):
selection_mode = "batch"
else:
selection_mode = "single"
return result_block, found_block_to_mig_to, selection_mode, parallelism_type, locality_type