Beispiel #1
0
    def _update_neighbour(dijkstra_tables, x_neighbour, y_neighbour, x_current,
                          y_current, x_source, y_source, weight):
        """ Update the lowest cost for each neighbour of a node

        :param dijkstra_tables:
        :param x_current:
        :param y_current:
        :param x_source:
        :param y_source:
        :param x_neighbour:
        :param y_neighbour:
        :param weight:
        :type dijkstra_tables:
        :type x_current:
        :type y_current:
        :type x_source:
        :type y_source:
        :type x_neighbour:
        :type y_neighbour:
        :type weight:
        :return:
        :rtype:
        :raise PacmanRoutingException: when the algorithm goes to a node that\
                    doesn't exist in the machine or the node's cost was set\
                    too low.
        """
        neighbour_exists = (x_neighbour, y_neighbour) in dijkstra_tables
        if not neighbour_exists:
            raise exceptions.PacmanRoutingException(
                "Tried to propagate to ({}, {}), which is not in the"
                " partitionable_graph: remove non-existent neighbours".format(
                    x_neighbour, y_neighbour))

        neighbour_activated =\
            dijkstra_tables[(x_neighbour, y_neighbour)]["activated?"]
        chip_lowest_cost =\
            dijkstra_tables[(x_current, y_current)]["lowest cost"]
        neighbour_lowest_cost =\
            dijkstra_tables[(x_neighbour, y_neighbour)]["lowest cost"]

        # Only try to update if the neighbour is within the partitionable_graph
        #  and the cost if the node hasn't already been activated
        # and the lowest cost if the new cost is less, or if
        # there is no current cost
        new_weight = float(chip_lowest_cost + weight)
        if (not neighbour_activated
                and (neighbour_lowest_cost is None
                     or new_weight < neighbour_lowest_cost)):

            # update Dijkstra table
            dijkstra_tables[(x_neighbour, y_neighbour)]["lowest cost"] =\
                new_weight

        if (dijkstra_tables[(x_neighbour, y_neighbour)]["lowest cost"] == 0) \
                and (x_neighbour != x_source or y_neighbour != y_source):
            raise exceptions.PacmanRoutingException(
                "!!!Cost of non-source node ({}, {}) was set to zero!!!".
                format(x_neighbour, y_neighbour))
Beispiel #2
0
def _locate_routing_entry(current_router, key):
    """ Locate the entry from the router based off the edge

    :param current_router: the current router being used in the trace
    :param key: the key being used by the source placement
    :return: the routing table entry
    :raise PacmanRoutingException: \
        when there is no entry located on this router.
    """
    for entry in current_router.multicast_routing_entries:
        if entry.mask & key == entry.routing_entry_key:
            return entry
    raise exceptions.PacmanRoutingException("no entry located")
Beispiel #3
0
def _locate_routing_entry(current_router, key, n_atoms):
    """ locate the entry from the router based off the subedge

    :param current_router: the current router being used in the trace
    :param key: the key being used by the source placement
    :return None:
    :raise PacmanRoutingException: when there is no entry located on this\
            router.
    """
    found_entry = None
    for entry in current_router.multicast_routing_entries:
        key_combo = entry.mask & key
        e_key = entry.routing_entry_key
        if key_combo == e_key:
            if found_entry is None:
                found_entry = entry
            else:
                logger.warn(
                    "Found more than one entry for key {}. This could be "
                    "an error, as currently no router supports overloading"
                    " of entries.".format(hex(key)))
            if entry.mask in range_masks:
                last_atom = key + n_atoms - 1
                last_key = e_key + (~entry.mask & 0xFFFFFFFFL)
                if last_key < last_atom:
                    raise Exception(
                        "Full key range not covered: key:{} key_combo:{} "
                        "mask:{}, last_key:{}, e_key:{}".format(
                            hex(key), hex(key_combo), hex(entry.mask),
                            hex(last_key), hex(e_key)))
        elif entry.mask in range_masks:
            last_atom = key + n_atoms
            last_key = e_key + (~entry.mask & 0xFFFFFFFFL)
            if (min(last_key, last_atom) - max(e_key, key)) + 1 > 0:
                raise Exception(
                    "Key range partially covered:  key:{} key_combo:{} "
                    "mask:{}, last_key:{}, e_key:{}".format(
                        hex(key), hex(key_combo), hex(entry.mask),
                        hex(last_key), hex(e_key)))
    if found_entry is not None:
        return found_entry
    else:
        raise exceptions.PacmanRoutingException("no entry located")
Beispiel #4
0
def _locate_routing_entry(current_router, key):
    """ locate the entry from the router based off the subedge

    :param current_router: the current router being used in the trace
    :param key: the key being used by the source placement
    :return None:
    :raise PacmanRoutingException: when there is no entry located on this\
            router.
    """
    found_entry = None
    for entry in current_router.multicast_routing_entries:
        key_combo = entry.mask & key
        e_key = entry.routing_entry_key
        if key_combo == e_key:
            if found_entry is None:
                found_entry = entry
    if found_entry is not None:
        return found_entry
    else:
        raise exceptions.PacmanRoutingException("no entry located")
Beispiel #5
0
def _check_visited_routers(chip_x, chip_y, visited_routers):
    """ Check if the trace has visited this router already

    :param chip_x: the x coordinate of the chip being checked
    :param chip_y: the y coordinate of the chip being checked
    :param visited_routers: routers already visited
    :type chip_x: int
    :type chip_y: int
    :type visited_routers: iterable of\
                pacman.model.routing_tables.multicast_routing_table.MulticastRoutingTable
    :return: None
    :raise PacmanRoutingException: when a router has been visited twice.
    """
    visited_routers_router = (chip_x, chip_y)
    if visited_routers_router in visited_routers:
        raise exceptions.PacmanRoutingException(
            "visited this router before, there is a cycle here. "
            "The routers I've currently visited are {} and the router i'm "
            "visiting is {}".format(visited_routers, visited_routers_router))
    else:
        visited_routers.add(visited_routers_router)
Beispiel #6
0
def _search_route(source_placement, dest_placements, key_and_mask,
                  routing_tables, machine, n_atoms, is_continuous):
    """ Locate if the routing tables work for the source to desks as\
        defined

    :param source_placement: the placement from which the search started
    :param dest_placements: the placements to which this trace should visit\
            only once
    :param key_and_mask: the key and mask associated with this set of\
            subedges
    :param n_atoms: the number of atoms going through this path
    :param is_continuous: bool stating if the keys and atoms mapping is
    continuous
    :type source_placement: instance of\
            pacman.model.placements.placement.Placement
    :type dest_placements: iterable of PlacementTuple
    :type key_and_mask: instance of\
            pacman.model.routing_info.key_and_mask.BaseKeyAndMask
    :return: None
    :raise PacmanRoutingException: when the trace completes and there are\
                still destinations not visited
    """
    for dest in dest_placements:
        logger.debug("[{}:{}:{}]".format(dest.x, dest.y, dest.p))

    located_destinations = set()

    failed_to_cover_all_keys_routers = list()

    _start_trace_via_routing_tables(source_placement, key_and_mask,
                                    located_destinations, routing_tables,
                                    machine, n_atoms, is_continuous,
                                    failed_to_cover_all_keys_routers)

    # start removing from located_destinations and check if destinations not
    #  reached
    failed_to_reach_destinations = list()
    for dest in dest_placements:
        if dest in located_destinations:
            located_destinations.remove(dest)
        else:
            failed_to_reach_destinations.append(dest)

    # check for error if trace didn't reach a destination it was meant to
    error_message = ""
    if len(failed_to_reach_destinations) > 0:
        output_string = ""
        for dest in failed_to_reach_destinations:
            output_string += "[{}:{}:{}]".format(dest.x, dest.y, dest.p)
        source_processor = "[{}:{}:{}]".format(source_placement.x,
                                               source_placement.y,
                                               source_placement.p)
        error_message += ("failed to locate all destinations with subvertex"
                          " {} on processor {} with keys {} as it did not "
                          "reach destinations {}".format(
                              source_placement.subvertex.label,
                              source_processor, key_and_mask, output_string))

    # check for error if the trace went to a destination it shouldn't have
    if len(located_destinations) > 0:
        output_string = ""
        for dest in located_destinations:
            output_string += "[{}:{}:{}]".format(dest.x, dest.y, dest.p)
        source_processor = "[{}:{}:{}]".format(source_placement.x,
                                               source_placement.y,
                                               source_placement.p)
        error_message += (
            "trace went to more failed to locate all "
            "destinations with subvertex {} on processor {} "
            "with keys {} as it didn't reach destinations {}".format(
                source_placement.subvertex.label, source_processor,
                key_and_mask, output_string))

    if len(failed_to_cover_all_keys_routers) > 0:
        output_string = ""
        for data_entry in failed_to_cover_all_keys_routers:
            output_string += "[{}, {}, {}, {}]".format(
                data_entry['router_x'], data_entry['router_y'],
                data_entry['keys'], data_entry['source_mask'])
        source_processor = "[{}:{}:{}]".format(source_placement.x,
                                               source_placement.y,
                                               source_placement.p)
        error_message += (
            "trace detected that there were atoms which the routing entry's"
            " wont cover and therefore packets will fly off to unknown places."
            " These keys came from the subvertex {} on processor {} and the"
            " failed routers are {}".format(source_placement.subvertex.label,
                                            source_processor, output_string))

    # raise error if required
    if error_message != "":
        raise exceptions.PacmanRoutingException(error_message)
    else:
        logger.debug("successful test between {} and {}".format(
            source_placement.subvertex.label, dest_placements))
Beispiel #7
0
    def _retrace_back_to_source(self, x_destination, y_destination,
                                dijkstra_tables, processor_dest, subedge,
                                nodes_info, source_processor,
                                partitioned_graph):
        """

        :param x_destination:
        :param y_destination:
        :param dijkstra_tables:
        :param processor_dest:
        :param subedge:
        :param nodes_info:
        :type nodes_info:
        :type subedge:
        :type x_destination:
        :type y_destination:
        :type dijkstra_tables:
        :type processor_dest:
        :param partitioned_graph:
        :type partitioned_graph:
        :return: the next coordinates to look into
        :rtype: int int
        :raise PacmanRoutingException: when the algorithm doesn't find a next\
                    point to search from. AKA, the neighbours of a chip do not\
                    have a cheaper cost than the node itself, but the node is\
                    not the destination or when the algorithm goes to a node\
                    that's not considered in the weighted search
        """
        # Set the tracking node to the destination to begin with
        x_current, y_current = x_destination, y_destination
        routing_entry_route_processors = []

        # if the processor is None, don't add to router path entry
        if processor_dest is not None:
            routing_entry_route_processors.append(processor_dest)
        routing_entry_route_links = None

        # build the multicast entry
        partitions = partitioned_graph.outgoing_edges_partitions_from_vertex(
            subedge.pre_subvertex)

        previous_routing_entry = None
        for partition_key in partitions:
            partition = partitions[partition_key]
            if subedge in partition:
                entry = MulticastRoutingTableByPartitionEntry(
                    out_going_links=routing_entry_route_links,
                    outgoing_processors=routing_entry_route_processors)

                self._routing_paths.add_path_entry(entry, x_destination,
                                                   y_destination, partition)
                previous_routing_entry = entry

        while dijkstra_tables[(x_current, y_current)]["lowest cost"] != 0:

            x_check, y_check = x_current, y_current

            neighbours = nodes_info[(x_current, y_current)]["neighbours"]
            neighbour_index = 0
            added_an_entry = False
            while not added_an_entry and neighbour_index < len(neighbours):
                neighbour = neighbours[neighbour_index]
                if neighbour is not None:

                    x_neighbour, y_neighbour = (neighbour.destination_x,
                                                neighbour.destination_y)

                    # Only check if it can be a preceding node if it actually
                    # exists
                    if (x_neighbour, y_neighbour) in dijkstra_tables:
                        dijkstra_table_key = (x_neighbour, y_neighbour)
                        lowest_cost = \
                            dijkstra_tables[dijkstra_table_key]["lowest cost"]
                        if lowest_cost is not None:
                            (x_current, y_current, previous_routing_entry,
                             added_an_entry) = self._create_routing_entry(
                                 x_neighbour, y_neighbour, dijkstra_tables,
                                 neighbour_index, nodes_info, x_current,
                                 y_current, previous_routing_entry, subedge,
                                 partitioned_graph)
                    else:
                        raise exceptions.PacmanRoutingException(
                            "Tried to trace back to node not in "
                            "partitionable_graph: remove non-existent"
                            " neighbours")
                neighbour_index += 1

            if x_current == x_check and y_current == y_check:
                raise exceptions.PacmanRoutingException(
                    "Iterated through all neighbours of tracking node but"
                    " did not find a preceding node! Consider increasing "
                    "acceptable discrepancy between sought traceback cost"
                    " and actual cost at node. Terminating...")
        previous_routing_entry.incoming_processor = source_processor
        return x_current, y_current
Beispiel #8
0
    def _propagate_costs_until_reached_destinations(self, dijkstra_tables,
                                                    nodes_info, dest_chips,
                                                    x_source, y_source):
        """ Propagate the weights till the destination nodes of the source\
            nodes are retraced

         :param dijkstra_tables: the dictionary object for the Dijkstra-tables
         :param nodes_info: the dictionary object for the nodes inside a route\
                    scope
         :param dest_chips:
         :param x_source:
         :param y_source:
         :type dijkstra_tables: dict
         :type nodes_info: dict
         :type dest_chips:
         :type x_source: int
         :type y_source: int
         :return: None
         :rtype: None
         :raise PacmanRoutingException: when the destination node could not be\
                    reached from this source node.
        """

        dest_chips_to_find = set(dest_chips)
        try:
            dest_chips_to_find.remove((x_source, y_source))
        except KeyError:
            # Ignore this - it just isn't in the set of destinations
            pass

        x_current = x_source
        y_current = y_source

        # Iterate only if the destination node hasn't been activated
        while len(dest_chips_to_find) > 0:

            # PROPAGATE!
            for i in range(
                    len(nodes_info[(x_current, y_current)]["neighbours"])):
                neighbour = nodes_info[(x_current, y_current)]["neighbours"][i]
                weight = nodes_info[(x_current, y_current)]["weights"][i]

                # "neighbours" is a list of 6 links or None objects.
                # There is a None object where there is no connection to
                # that neighbour.
                if ((neighbour is not None)
                        and not (neighbour.destination_x == x_source
                                 and neighbour.destination_y == y_source)):

                    # These variables change with every look at a new neighbour
                    self._update_neighbour(dijkstra_tables,
                                           neighbour.destination_x,
                                           neighbour.destination_y, x_current,
                                           y_current, x_source, y_source,
                                           weight)

            # This is the lowest cost across ALL
            # deactivated nodes in the partitionable_graph.
            graph_lowest_cost = None

            # Find the next node to be activated
            for key in dijkstra_tables:

                # Don't continue if the node hasn't even been touched yet
                if (dijkstra_tables[key]["lowest cost"] is not None
                        and not dijkstra_tables[key]["activated?"] and
                    (graph_lowest_cost is not None and
                     (dijkstra_tables[key]["lowest cost"] < graph_lowest_cost)
                     or graph_lowest_cost is None)):
                    graph_lowest_cost = dijkstra_tables[key]["lowest cost"]
                    x_current, y_current = int(key[0]), int(key[1])

            # If there were no deactivated nodes with costs,
            # but the destination was not reached this iteration,
            # raise an exception
            if graph_lowest_cost is None:
                raise exceptions.PacmanRoutingException(
                    "Destination could not be activated, ending run")

            # Set the next activated node as the deactivated node with the
            #  lowest current cost
            dijkstra_tables[(x_current, y_current)]["activated?"] = True
            try:
                dest_chips_to_find.remove((x_current, y_current))
            except KeyError:
                # Ignore the error - it just isn't a destination chip
                pass