def select_block_to_migrate_to()

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