def add_routing_table(self, routing_table): """ Add a routing table :param routing_table: a routing table to add :type routing_table:\ :py:class:`pacman.model.routing_tables.multicast_routing_table.MulticastRoutingTable` :return: None :rtype: None :raise pacman.exceptions.PacmanAlreadyExistsException: If a routing\ table already exists for the chip """ if routing_table in self._routing_tables: raise PacmanAlreadyExistsException( "The Routing table {} has already been added to the collection" " before and therefore already exists".format(routing_table), str(routing_table)) if (routing_table.x, routing_table.y) in \ self._routing_tables_by_chip: raise PacmanAlreadyExistsException( "The Routing table for chip {}:{} already exists in this " "collection and thefore is deemed an error to readd it".format( routing_table.x, routing_table.y), str(routing_table)) self._routing_tables_by_chip[(routing_table.x, routing_table.y)] = \ routing_table self._routing_tables.add(routing_table)
def add_multicast_routing_entry(self, multicast_routing_entry): """ Adds a routing entry to this table :param ~spinn_machine.MulticastRoutingEntry multicast_routing_entry: The route to add :rtype: None :raise PacmanAlreadyExistsException: If a routing entry with the same key-mask combination already exists """ routing_entry_key = multicast_routing_entry.routing_entry_key mask = multicast_routing_entry.mask tuple_key = (routing_entry_key, mask) if tuple_key in self._entries_by_key_mask: raise PacmanAlreadyExistsException("Multicast_routing_entry", str(multicast_routing_entry)) self._entries_by_key_mask[tuple_key] =\ multicast_routing_entry self._entries_by_key[routing_entry_key] = multicast_routing_entry self._multicast_routing_entries.append(multicast_routing_entry) # update default routed counter if required if multicast_routing_entry.defaultable: self._number_of_defaulted_routing_entries += 1
def add_outgoing_edge_partition(self, edge_partition): # verify that this partition is suitable for this graph if not isinstance(edge_partition, AbstractMachineEdgePartition): raise PacmanInvalidParameterException( "outgoing_edge_partition", str(edge_partition.__class__), "Partitions of this graph must be an " "AbstractMachineEdgePartition") # check this partition doesn't already exist if edge_partition in self._edge_partitions: raise PacmanAlreadyExistsException( str(AbstractMachineEdgePartition), edge_partition) self._edge_partitions.add(edge_partition) edge_partition.register_graph_code(id(self)) for pre_vertex in edge_partition.pre_vertices: key = (pre_vertex, edge_partition.identifier) self._outgoing_edge_partitions_by_name[key] = edge_partition if isinstance(edge_partition, MulticastEdgePartition): self._multicast_edge_partitions_by_pre_vertex[pre_vertex].add( edge_partition) elif isinstance(edge_partition, FixedRouteEdgePartition): self._fixed_route_edge_partitions_by_pre_vertex[ pre_vertex].add(edge_partition) elif isinstance(edge_partition, AbstractSDRAMPartition): self._sdram_edge_partitions_by_pre_vertex[pre_vertex].add( edge_partition) else: raise NotImplementedError( "Unexpected edge_partition: {}".format(edge_partition)) for edge in edge_partition.edges: self._register_edge(edge, edge_partition)
def __add_fixed_route_entry(self, key, link_ids, processor_ids): """ :param tuple(int,int) key: :param list(int) link_ids: :param list(int) processor_ids: :raises PacmanAlreadyExistsException: """ fixed_route_entry = FixedRouteEntry(link_ids=link_ids, processor_ids=processor_ids) if key in self._fixed_route_tables: raise PacmanAlreadyExistsException("fixed route entry", str(key)) self._fixed_route_tables[key] = fixed_route_entry
def add_partition_info(self, partition_info): """ Add a partition information item :param PartitionRoutingInfo partition_info:\ The partition information item to add :rtype: None :raise PacmanAlreadyExistsException:\ If the partition is already in the set of edges """ p = partition_info.partition if p in self._info_by_partition: raise PacmanAlreadyExistsException("Partition", str(partition_info)) if (p.pre_vertex, p.identifier) in self._info_by_prevertex: raise PacmanAlreadyExistsException("Partition", str(partition_info)) self._info_by_partition[p] = partition_info self._info_by_prevertex[p.pre_vertex, p.identifier] = partition_info for edge in p.edges: self._info_by_edge[edge] = partition_info
def _do_fixed_routing( self, fixed_route_tables, board_version, placements, ethernet_chip_x, ethernet_chip_y, destination_class, machine): """ Handles this board through the quick routing process, based on a\ predefined routing table. :param fixed_route_tables: fixed routing tables :param board_version: the SpiNNaker machine version :param placements: the placements object :param ethernet_chip_x: chip x of the Ethernet connected chip :param ethernet_chip_y: chip y of the Ethernet connected chip :param destination_class: \ the class of the vertex to route to at the Ethernet connected chip :param machine: SpiNNMachine instance :rtype: None """ joins, paths = self._get_joins_paths(board_version) for path_id in paths: # create entry for each chip along path for (path_chip_x, path_chip_y) in paths[path_id]: # figure link IDs (default is [4]) link_ids = [self.DEFAULT_LINK_ID] if (path_chip_x, path_chip_y) in joins: link_ids = [joins[path_chip_x, path_chip_y]] # build entry and add to table and add to tables fixed_route_entry = FixedRouteEntry( link_ids=link_ids, processor_ids=[]) chip_x = ( path_chip_x + ethernet_chip_x) % (machine.max_chip_x + 1) chip_y = ( path_chip_y + ethernet_chip_y) % (machine.max_chip_y + 1) fixed_route_tables[chip_x, chip_y] = fixed_route_entry # locate where to put data processor_id = self._locate_destination( ethernet_chip_x, ethernet_chip_y, destination_class, placements) # create final fixed route entry # build entry and add to table and add to tables fixed_route_entry = FixedRouteEntry( link_ids=[], processor_ids=[processor_id]) key = (ethernet_chip_x, ethernet_chip_y) if key in fixed_route_tables: raise PacmanAlreadyExistsException( "fixed route entry", str(key)) fixed_route_tables[key] = fixed_route_entry
def add_routing_table(self, routing_table): """ Add a routing table :param MulticastRoutingTable routing_table: a routing table to add :rtype: None :raise PacmanAlreadyExistsException: If a routing table already exists for the chip """ if routing_table in self._routing_tables: raise PacmanAlreadyExistsException( "The Routing table {} has already been added to the collection" " before and therefore already exists".format(routing_table), str(routing_table)) if (routing_table.x, routing_table.y) in self._routing_tables_by_chip: raise PacmanAlreadyExistsException( "The Routing table for chip {}:{} already exists in this " "collection and therefore is deemed an error to re-add it". format(routing_table.x, routing_table.y), str(routing_table)) self._routing_tables_by_chip[(routing_table.x, routing_table.y)] = \ routing_table self._routing_tables.add(routing_table) self._max_number_of_entries = max(self._max_number_of_entries, routing_table.number_of_entries)
def remember_machine_vertex(self, machine_vertex): """ Adds the Machine vertex the iterable returned by machine_vertices This method will be called by MachineVertex.app_vertex No other place should call it. :param MachineVertex machine_vertex: A pointer to a machine_vertex. This vertex may not be fully initialized but will have a slice :raises PacmanValueError: If the slice of the machine_vertex is too big """ machine_vertex.index = len(self._machine_vertices) if machine_vertex in self._machine_vertices: raise PacmanAlreadyExistsException(str(machine_vertex), machine_vertex) self._machine_vertices.add(machine_vertex)
def other_splitter(self, new_value): """ Supports the delayed setting of the other to depend on :param new_value: other splitter :type new_value: AbstractSplitterCommon or None :raise PacmanAlreadyExistsException: If there is already a different other set :raise PacmanPartitionException: If a circular dependency is detected """ if (self._other_splitter is not None and self._other_splitter != new_value): raise PacmanAlreadyExistsException( "other_splitter", self._other_splitter) if self.check_circular(new_value): raise PacmanPartitionException( self.CIRCULAR_ERROR_MESSAGE.format(self, new_value)) self._other_splitter = new_value
def add_outgoing_edge_partition(self, edge_partition): # verify that this partition is suitable for this graph if not isinstance(edge_partition, ApplicationEdgePartition): raise PacmanInvalidParameterException( "outgoing_edge_partition", edge_partition.__class__, "Partitions of this graph must be an ApplicationEdgePartition") # check this partition doesn't already exist key = (edge_partition.pre_vertex, edge_partition.identifier) if key in self._outgoing_edge_partitions_by_name: raise PacmanAlreadyExistsException(str(ApplicationEdgePartition), key) edge_partition.register_graph_code(id(self)) self._outgoing_edge_partitions_by_pre_vertex[ edge_partition.pre_vertex].add(edge_partition) self._outgoing_edge_partitions_by_name[key] = edge_partition for edge in edge_partition.edges: self._register_edge(edge, edge_partition)
def add_vertex(self, vertex): """ Add a vertex to the graph. :param AbstractVertex vertex: The vertex to add :raises PacmanInvalidParameterException: If the vertex is not of a valid type :raises PacmanConfigurationException: If there is an attempt to add the same vertex more than once """ if not isinstance(vertex, self._allowed_vertex_types): raise PacmanInvalidParameterException( "vertex", str(vertex.__class__), "Vertices of this graph must be one of the following types:" " {}".format(self._allowed_vertex_types)) if not vertex.label: vertex.set_label(vertex.__class__.__name__ + "_" + self._label_postfix()) elif vertex.label in self._vertex_by_label: if self._vertex_by_label[vertex.label] == vertex: raise PacmanAlreadyExistsException("vertex", vertex.label) vertex.set_label(vertex.label + self._label_postfix()) vertex.addedToGraph() self._vertices.append(vertex) self._vertex_by_label[vertex.label] = vertex
def _register_edge(self, edge, partition): """ Add an edge to the graph. :param AbstractEdge edge: The edge to add :param AbstractEdgePartition partition: The name of the edge partition to add the edge to; each edge partition is the partition of edges that start at the same vertex :raises PacmanInvalidParameterException: If the edge is not of a valid type or if edges have already been added to this partition that start at a different vertex to this one """ # verify that the edge is one suitable for this graph if not isinstance(edge, self._allowed_edge_types): raise PacmanInvalidParameterException( "edge", edge.__class__, "Edges of this graph must be one of the following types:" " {}".format(self._allowed_edge_types)) if edge.pre_vertex.label not in self._vertex_by_label: raise PacmanInvalidParameterException( "Edge", str(edge.pre_vertex), "Pre-vertex must be known in graph") if edge.post_vertex.label not in self._vertex_by_label: raise PacmanInvalidParameterException( "Edge", str(edge.post_vertex), "Post-vertex must be known in graph") # Add the edge to the indices self._outgoing_edges[edge.pre_vertex].add(edge) self._incoming_edges_by_partition_name[ edge.post_vertex, partition.identifier].append(edge) self._incoming_edges[edge.post_vertex].add(edge) if edge in self._outgoing_edge_partition_by_edge: raise PacmanAlreadyExistsException("edge", edge) self._outgoing_edge_partition_by_edge[edge] = partition
def add_outgoing_edge_partition(self, outgoing_edge_partition): # verify that this partition is suitable for this graph if not isinstance( outgoing_edge_partition, self._allowed_partition_types): raise PacmanInvalidParameterException( "outgoing_edge_partition", outgoing_edge_partition.__class__, "Partitions of this graph must be one of the following types:" " {}".format(self._allowed_partition_types)) # check this partition doesn't already exist if ((outgoing_edge_partition.pre_vertex, outgoing_edge_partition.identifier) in self._outgoing_edge_partitions_by_name): raise PacmanAlreadyExistsException( "{}".format(OutgoingEdgePartition.__class__), (outgoing_edge_partition.pre_vertex, outgoing_edge_partition.identifier)) self._outgoing_edge_partitions_by_pre_vertex[ outgoing_edge_partition.pre_vertex].add(outgoing_edge_partition) self._outgoing_edge_partitions_by_name[ outgoing_edge_partition.pre_vertex, outgoing_edge_partition.identifier] = outgoing_edge_partition
def _do_dynamic_routing( self, fixed_route_tables, placements, ethernet_connected_chip, destination_class, machine, board_version): """ Uses a router to route fixed routes :param fixed_route_tables: fixed route tables entry holder :param placements: placements :param ethernet_connected_chip: the chip to consider for this routing :param destination_class: the class at the Ethernet connected chip\ for receiving all these routes. :param machine: SpiNNMachine instance :param board_version: The version of the machine :rtype: None """ graph = MachineGraph(label="routing graph") fake_placements = Placements() # build fake setup for the routing eth_x = ethernet_connected_chip.x eth_y = ethernet_connected_chip.y down_links = set() for (chip_x, chip_y) in machine.get_chips_on_board( ethernet_connected_chip): vertex = RoutingMachineVertex() graph.add_vertex(vertex) rel_x = chip_x - eth_x if rel_x < 0: rel_x += machine.max_chip_x + 1 rel_y = chip_y - eth_y if rel_y < 0: rel_y += machine.max_chip_y + 1 free_processor = 0 while ((free_processor < machine.MAX_CORES_PER_CHIP) and fake_placements.is_processor_occupied( self.FAKE_ETHERNET_CHIP_X, y=self.FAKE_ETHERNET_CHIP_Y, p=free_processor)): free_processor += 1 fake_placements.add_placement(Placement( x=rel_x, y=rel_y, p=free_processor, vertex=vertex)) down_links.update({ (rel_x, rel_y, link) for link in range( Router.MAX_LINKS_PER_ROUTER) if not machine.is_link_at(chip_x, chip_y, link)}) # Create a fake machine consisting of only the one board that # the routes should go over fake_machine = machine if (board_version in machine.BOARD_VERSION_FOR_48_CHIPS and (machine.max_chip_x > machine.MAX_CHIP_X_ID_ON_ONE_BOARD or machine.max_chip_y > machine.MAX_CHIP_Y_ID_ON_ONE_BOARD)): down_chips = { (x, y) for x, y in zip( range(machine.SIZE_X_OF_ONE_BOARD), range(machine.SIZE_Y_OF_ONE_BOARD)) if not machine.is_chip_at( (x + eth_x) % (machine.max_chip_x + 1), (y + eth_y) % (machine.max_chip_y + 1))} # build a fake machine which is just one board but with the missing # bits of the real board fake_machine = VirtualMachine( machine.SIZE_X_OF_ONE_BOARD, machine.SIZE_Y_OF_ONE_BOARD, False, down_chips=down_chips, down_links=down_links) # build destination verts = graph.vertices vertex_dest = RoutingMachineVertex() graph.add_vertex(vertex_dest) destination_processor = self._locate_destination( ethernet_chip_x=ethernet_connected_chip.x, ethernet_chip_y=ethernet_connected_chip.y, destination_class=destination_class, placements=placements) fake_placements.add_placement(Placement( x=self.FAKE_ETHERNET_CHIP_X, y=self.FAKE_ETHERNET_CHIP_Y, p=destination_processor, vertex=vertex_dest)) # deal with edges for vertex in verts: graph.add_edge( MachineEdge(pre_vertex=vertex, post_vertex=vertex_dest), self.FAKE_ROUTING_PARTITION) # route as if using multicast router = BasicDijkstraRouting() routing_tables_by_partition = router( placements=fake_placements, machine=fake_machine, machine_graph=graph, use_progress_bar=False) # convert to fixed route entries for (chip_x, chip_y) in routing_tables_by_partition.get_routers(): mc_entries = routing_tables_by_partition.get_entries_for_router( chip_x, chip_y) # only want the first entry, as that will all be the same. mc_entry = next(itervalues(mc_entries)) fixed_route_entry = FixedRouteEntry( link_ids=mc_entry.out_going_links, processor_ids=mc_entry.out_going_processors) x = (chip_x + eth_x) % (machine.max_chip_x + 1) y = (chip_y + eth_y) % (machine.max_chip_y + 1) key = (x, y) if key in fixed_route_tables: raise PacmanAlreadyExistsException( "fixed route entry", str(key)) fixed_route_tables[key] = fixed_route_entry