Source code for spinn_machine.router

# Copyright (c) 2017-2019 The University of Manchester
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from collections import OrderedDict
from .exceptions import (
    SpinnMachineAlreadyExistsException, SpinnMachineInvalidParameterException)
from .machine import Machine


[docs]class Router(object): """ Represents a router of a chip, with a set of available links.\ The router is iterable over the links, providing (source_link_id,\ link) where: * ``source_link_id`` is the ID of a link * ``link`` is the :py:class:`Link` with ID ``source_link_id`` """ # The maximum number of links/directions a router can handle MAX_LINKS_PER_ROUTER = 6 # Number to add or sub from a link to get its opposite LINK_OPPOSITE = 3 MAX_CORES_PER_ROUTER = 18 __slots__ = ( "_emergency_routing_enabled", "_links", "_n_available_multicast_entries" ) def __init__( self, links, emergency_routing_enabled=False, n_available_multicast_entries=Machine.ROUTER_ENTRIES): """ :param iterable(~spinn_machine.Link) links: iterable of links :param bool emergency_routing_enabled: Determines if the router emergency routing is operating :param int n_available_multicast_entries: The number of entries available in the routing table :raise ~spinn_machine.exceptions.SpinnMachineAlreadyExistsException: If any two links have the same ``source_link_id`` """ self._links = OrderedDict() for link in links: self.add_link(link) self._emergency_routing_enabled = emergency_routing_enabled self._n_available_multicast_entries = n_available_multicast_entries def __contains__(self, source_link_id): """ See :py:meth:`is_link` """ return self.is_link(source_link_id) def __getitem__(self, source_link_id): """ See :py:meth:`get_link` """ return self.get_link(source_link_id) @property def links(self): """ The available links of this router :return: an iterable of available links :rtype: iterable(~spinn_machine.Link) :raise None: does not raise any known exceptions """ return iter(self._links.values()) def __iter__(self): """ Get an iterable of source link IDs and links in the router :return: an iterable of tuples of ``(source_link_id, link)`` where: * ``source_link_id`` is the ID of the link * ``link`` is a router link :rtype: iterable(int, ~spinn_machine.Link) :raise None: does not raise any known exceptions """ return iter(self._links.items()) def __len__(self): """ Get the number of links in the router :return: The length of the underlying iterable :rtype: int """ return len(self._links) @property def emergency_routing_enabled(self): """ Indicator of whether emergency routing is enabled :return: True if emergency routing is enabled, False otherwise :rtype: bool """ return self._emergency_routing_enabled @property def n_available_multicast_entries(self): """ The number of available multicast entries in the routing tables :return: The number of available entries :rtype: int """ return self._n_available_multicast_entries
[docs] @staticmethod def convert_routing_table_entry_to_spinnaker_route(routing_table_entry): """ Convert a routing table entry represented in software to a\ binary routing table entry usable on the machine :param ~spinn_machine.MulticastRoutingEntry routing_table_entry: The entry to convert :rtype: int """ route_entry = 0 for processor_id in routing_table_entry.processor_ids: if processor_id >= Router.MAX_CORES_PER_ROUTER or processor_id < 0: raise SpinnMachineInvalidParameterException( "route.processor_ids", str(routing_table_entry.processor_ids), "Processor IDs must be between 0 and " + str(Router.MAX_CORES_PER_ROUTER - 1)) route_entry |= (1 << (Router.MAX_LINKS_PER_ROUTER + processor_id)) for link_id in routing_table_entry.link_ids: if link_id >= Router.MAX_LINKS_PER_ROUTER or link_id < 0: raise SpinnMachineInvalidParameterException( "route.link_ids", str(routing_table_entry.link_ids), "Link IDs must be between 0 and " + str(Router.MAX_LINKS_PER_ROUTER - 1)) route_entry |= (1 << link_id) return route_entry
[docs] @staticmethod def convert_spinnaker_route_to_routing_ids(route): """ Convert a binary routing table entry usable on the machine to \ lists of route IDs usable in a routing table entry represented in \ software. :param int route: The routing table entry :return: The list of processor IDs, and the list of link IDs. :rtype: tuple(list(int), list(int)) """ processor_ids = [pi for pi in range(0, Router.MAX_CORES_PER_ROUTER) if route & 1 << (Router.MAX_LINKS_PER_ROUTER + pi)] link_ids = [li for li in range(0, Router.MAX_LINKS_PER_ROUTER) if route & 1 << li] return processor_ids, link_ids
[docs] def get_neighbouring_chips_coords(self): """ Utility method to convert links into x and y coordinates :return: iterable list of destination coordinates in x and y dict :rtype: iterable(dict(str,int)) """ next_hop_chips_coords = list() for link in self.links: next_hop_chips_coords.append( {'x': link.destination_x, 'y': link.destination_y}) return next_hop_chips_coords
def __str__(self): return ( "[Router: emergency_routing={}, " "available_entries={}, links={}]".format( self._emergency_routing_enabled, self._n_available_multicast_entries, list(self._links.values()))) def __repr__(self): return self.__str__()
[docs] @staticmethod def opposite(link_id): """ Given a valid link_id this method returns its opposite. GIGO: this method assumes the input is valid. No verfication is done :param int link_id: A valid link_id :return: The link_id for the opposite direction :rtype: int """ # Mod is faster than if return (link_id + Router.LINK_OPPOSITE) % Router.MAX_LINKS_PER_ROUTER