Example #1
0
    def get_bipartition(
        self,
        direction: Dir,
        max_usage_ratio: float,
        max_search_time: int,
    ) -> Optional[Dict[Vertex, Slot]]:
        """
    bi-partition all the current slots
    """
        m = get_mip_model_silent()

        v2var = self._create_ilp_vars(m)

        self._add_opt_goal(m, v2var, direction)

        # area constraints for each child slot
        self._add_area_constraints(m, v2var, direction, max_usage_ratio)

        self._add_pre_assignment(m, v2var, direction)

        self._add_grouping_constraints(m, v2var)

        m.optimize(max_seconds=max_search_time)

        next_v2s = self._get_partition_result(m, v2var, direction)
        if not next_v2s:
            _logger.debug(
                f'bi-partioning failed with usage ratio {max_usage_ratio}')

        return next_v2s
Example #2
0
    def route_design(self,
                     routing_usage_limit: float = 0.6,
                     detour_path_limit: int = 4) -> Dict[Edge, List[Slot]]:

        while 1:
            if routing_usage_limit > 1:
                _logger.error(f'Global routing failed')
                exit(1)

            _logger.info(
                f'Global routing attempt with routing usage limit {routing_usage_limit}'
            )

            m = get_mip_model_silent()

            fifo_to_paths = self.get_fifo_to_candidate_paths(
                routing_usage_limit, detour_path_limit)
            path_to_var = self.get_path_to_var(m, fifo_to_paths)
            routing_edge_to_paths = self.get_routing_edge_to_passing_paths(
                fifo_to_paths)

            _logger.info(f'there are {len(fifo_to_paths)} dataflow edges')
            _logger.info(
                f'there are {len(path_to_var)} potential paths to select from')

            self.constrain_fifo_to_one_path(m, fifo_to_paths, path_to_var)

            self.constrain_routing_edge_capacity(m, path_to_var,
                                                 routing_edge_to_paths)

            self.add_opt_goal(m, fifo_to_paths, path_to_var)

            status = m.optimize()

            if status == OptimizationStatus.OPTIMAL:
                _logger.warning(
                    f'Succeeded: global routing attempt with routing usage limit {routing_usage_limit}'
                )
                break
            else:
                _logger.warning(
                    f'Failed: global routing attempt with routing usage limit {routing_usage_limit}'
                )
                routing_usage_limit += 0.03

        # extract results
        fifo_to_selected_path, routing_edge_to_selected_paths = \
          self.get_routing_results(fifo_to_paths, path_to_var, routing_edge_to_paths)

        # _logger and analysis
        self.analyze_routing_results(fifo_to_paths, fifo_to_selected_path,
                                     routing_edge_to_selected_paths)

        fifo_to_slots = {
            fifo: path.get_slots_in_path()
            for fifo, path in fifo_to_selected_path.items()
        }
        return fifo_to_slots
Example #3
0
def eight_way_partition(
  init_v2s: Dict[Vertex, Slot],
  grouping_constraints: List[List[Vertex]],
  pre_assignments: Dict[Vertex, Slot],
  slot_manager: SlotManager,
  max_usage_ratio: float,
  slr_width_limit: int,
  max_search_time: int,
  hbm_port_v_list: List[Vertex] = [],
) -> Dict[Vertex, Slot]:

  m = get_mip_model_silent()

  v_list = list(init_v2s.keys())

  # three variables could determine the location of a module
  # y = y1 *2 + y2  (four slots)
  # x = x           (each SLR is divided by half)
  v2var_x, v2var_y1, v2var_y2 = dict(), dict(), dict()
  for v in v_list:
    v2var_x[v] = m.add_var(var_type=BINARY, name=f'{v.name}_x')
    v2var_y1[v] = m.add_var(var_type=BINARY, name=f'{v.name}_y1')
    v2var_y2[v] = m.add_var(var_type=BINARY, name=f'{v.name}_y2')

  func_get_slot_by_idx = _get_slot_by_idx_closure(slot_manager)
  slot_to_idx = _get_slot_to_idx(func_get_slot_by_idx)

  _add_area_constraints(m, v_list, v2var_x=v2var_x, v2var_y1=v2var_y1, v2var_y2=v2var_y2,
    func_get_slot_by_idx=func_get_slot_by_idx, max_usage_ratio=max_usage_ratio)

  _add_pre_assignment(m, v_list, slot_to_idx, pre_assignments, v2var_x=v2var_x, v2var_y1=v2var_y1, v2var_y2=v2var_y2)

  _add_hbm_port_constraints(m, hbm_port_v_list, slot_to_idx, pre_assignments, v2var_x=v2var_x, v2var_y1=v2var_y1, v2var_y2=v2var_y2)

  add_slr_0_1_crossing_constraint(m, v_list, v2var_y1, v2var_y2, slr_width_limit)
  add_slr_1_2_crossing_constraint(m, v_list, v2var_y1, slr_width_limit)
  add_slr_2_3_crossing_constraint(m, v_list, v2var_y1, v2var_y2, slr_width_limit)

  _add_grouping_constraints(m, grouping_constraints, v2var_x=v2var_x, v2var_y1=v2var_y1, v2var_y2=v2var_y2)

  _add_opt_goal(m, v_list, v2var_x=v2var_x, v2var_y1=v2var_y1, v2var_y2=v2var_y2)

  _logger.debug(f'Start ILP solver with max usage ratio {max_usage_ratio} and max search time {max_search_time}s')
  m.optimize(max_seconds=max_search_time)

  next_v2s = _get_results(m, v_list, func_get_slot_by_idx, v2var_x=v2var_x, v2var_y1=v2var_y1, v2var_y2=v2var_y2)

  return next_v2s
Example #4
0
def latency_balancing(graph, fifo_to_path) -> Dict[str, int]:
    name_to_edge: Dict[str, Edge] = graph.getNameToEdgeMap()
    name_to_vertex: Dict[str, Vertex] = graph.getNameToVertexMap()

    m = get_mip_model_silent()

    # map Vertex -> "arrival time"
    vertex_to_var = {}
    for name, v in name_to_vertex.items():
        vertex_to_var[v] = m.add_var(var_type=INTEGER, name=name)

    # differential constraint for each edge
    for e_name, e in name_to_edge.items():
        # +1 because each FIFO by itself has 1 unit of latency
        # in case the original design is not balanced
        # note that additional pipelining for full_n will not lead to additional latency
        # we only need to increase the grace period of almost full FIFOs by 1
        # [update]: we skip the +1 for the orginial FIFO. We only take care of our own modifications
        m += vertex_to_var[e.src] >= vertex_to_var[e.dst] + get_latency(
            fifo_to_path[e])

    m.objective = minimize(
        xsum(e.width * (vertex_to_var[e.src] - vertex_to_var[e.dst])
             for e in name_to_edge.values()))

    status = m.optimize(max_seconds=120)
    if status != OptimizationStatus.OPTIMAL and status != OptimizationStatus.FEASIBLE:
        cli_logger.warning(
            'Failed to balance reconvergent paths at loop level. Most likely there is a loop of streams.'
        )
        return {}

    # get result
    fifo_name_to_depth = {}
    for e_name, e in name_to_edge.items():
        e.added_depth_for_rebalance = int(
            vertex_to_var[e.src].x - vertex_to_var[e.dst].x) - e.pipeline_level
        fifo_name_to_depth[e_name] = e.depth + e.added_depth_for_rebalance
        assert e.added_depth_for_rebalance >= 0

    # logging
    for e_name, e in name_to_edge.items():
        _logger.info(
            f'{e_name}: pipeline_level: {e.pipeline_level}, original depth: {e.depth}, added_depth_for_rebalance: {e.added_depth_for_rebalance}, width: {e.width} '
        )

    return fifo_name_to_depth
Example #5
0
def get_legalized_v2s(orig_v2s: Dict[Vertex,
                                     Slot], grouping_list: List[List[Vertex]],
                      all_slot_list: List[Slot], pre_assignments: Dict[Vertex,
                                                                       Slot],
                      resource_usage_limit: int) -> Dict[Vertex, Slot]:
    """
  adjust the floorplanning to satisfy the area requirement
  """
    _logger.debug(
        f'Begin legalizing the floorplan results, target resource usage limit: {resource_usage_limit}'
    )

    m = get_mip_model_silent()

    v_list = list(orig_v2s.keys())
    s_list = all_slot_list

    v_to_s_to_var, s_to_v_to_var = _create_ilp_vars(m, v_list, s_list)
    v_to_s_to_cost = _get_v_to_s_to_cost(v_list, s_list, orig_v2s)

    _add_area_constraints(m, s_to_v_to_var, resource_usage_limit)

    _add_pre_assignments(m, v_to_s_to_var, pre_assignments, all_slot_list)

    _add_unique_assign_constraints(m, v_to_s_to_var)

    _add_grouping_constraints(m, grouping_list, v_to_s_to_var, s_list)

    _add_opt_goal(m, v_to_s_to_cost, v_to_s_to_var)

    status = m.optimize()
    if status != OptimizationStatus.OPTIMAL:
        _logger.debug(
            f'Fail to legalize the floorplan under target ratio {resource_usage_limit}'
        )
        return {}

    new_v2s, new_s2v = _get_ilp_results(v_to_s_to_var)

    _log_results(new_v2s, orig_v2s)

    _logger.info('Finish legalizing the floorplan results.')

    return new_v2s