class GetMachineProcess(AbstractMultiConnectionProcess): """ A process for getting the machine details over a set of connections """ def __init__(self, scamp_connections, ignore_chips, ignore_cores, max_core_id): """ :param scamp_connections: The connections to use for the interaction :type scamp_connections: iterable of\ :py:class:`spinnman.connections.abstract_classes.abstract_connection.AbstractConnection` """ AbstractMultiConnectionProcess.__init__(self, scamp_connections) self._ignore_chips = ignore_chips self._ignore_cores = ignore_cores self._max_core_id = max_core_id # A dictionary of (x, y) -> ChipInfo self._chip_info = dict() # The machine so far self._machine = Machine([]) # A dictionary of which link goes where from a chip: # (x, y, link) -> (x, y) self._link_destination = dict() # A queue of ChipInfo to be examined self._search = deque() def _make_chip(self, chip_details): """ Creates a chip from a ChipInfo structure :param chip_details: The ChipInfo structure to create the chip\ from :type chip_details: \ :py:class:`spinnman.model.chip_info.ChipInfo` :return: The created chip :rtype: :py:class:`spinn_machine.chip.Chip` """ # Create the processor list processors = list() for virtual_core_id in chip_details.virtual_core_ids: if self._ignore_cores is not None and self._ignore_cores.is_core( chip_details.x, chip_details.y, virtual_core_id ): continue if self._max_core_id is not None and virtual_core_id > self._max_core_id: continue processors.append(Processor(virtual_core_id, chip_details.cpu_clock_mhz * 1000000, virtual_core_id == 0)) # Create the router - add the links later during search router = Router( links=list(), emergency_routing_enabled=False, clock_speed=Router.ROUTER_DEFAULT_CLOCK_SPEED, n_available_multicast_entries=( Router.ROUTER_DEFAULT_AVAILABLE_ENTRIES - chip_details.first_free_router_entry ), ) # Create the chip chip = Chip( x=chip_details.x, y=chip_details.y, processors=processors, router=router, sdram=SDRAM( user_base_address=chip_details.sdram_base_address, system_base_address=chip_details.system_sdram_base_address, ), ip_address=chip_details.ip_address, nearest_ethernet_x=chip_details.nearest_ethernet_x, nearest_ethernet_y=chip_details.nearest_ethernet_y, ) return chip def _receive_chip_details(self, scp_read_memory_response): try: new_chip_details = ChipInfo(scp_read_memory_response.data, scp_read_memory_response.offset) if self._ignore_chips is not None and self._ignore_chips.is_chip(new_chip_details.x, new_chip_details.y): return None key = (new_chip_details.x, new_chip_details.y) if key not in self._chip_info: self._chip_info[key] = new_chip_details self._search.append(new_chip_details) new_chip = self._make_chip(new_chip_details) self._machine.add_chip(new_chip) return new_chip return self._machine.get_chip_at(new_chip_details.x, new_chip_details.y) except Exception: traceback.print_exc() def _receive_chip_details_from_link(self, scp_read_link_response, source_x, source_y, link): new_chip = self._receive_chip_details(scp_read_link_response) if new_chip is not None: self._link_destination[(source_x, source_y, link)] = new_chip def _receive_error(self, request, exception, tracebackinfo): # If we get an SCPReadLinkRequest with a # SpinnmanUnexpectedResponseCodeException, this is a failed link # and so can be ignored if not isinstance(request, SCPReadLinkRequest) or not isinstance( exception, SpinnmanUnexpectedResponseCodeException ): AbstractProcess._receive_error(self, request, exception, tracebackinfo) def get_machine_details(self): # Get the details of chip 0, 0 self._send_request( SCPReadMemoryRequest( x=0, y=0, base_address=constants.SYSTEM_VARIABLE_BASE_ADDRESS, size=constants.SYSTEM_VARIABLE_BYTES ), self._receive_chip_details, self._receive_error, ) self._finish() # Continue until there is nothing to search (and no exception) while not self.is_error() and len(self._search) > 0: # Set up the next round of searches using everything that # needs to search (same loop as above, I know, but wait for it) while not self.is_error() and len(self._search) > 0: chip_info = self._search.pop() # Examine the links of the chip to find the next chips for link in chip_info.links_available: # Add the read_link request - note that this might # add to the search if a response is received receiver = _ChipInfoReceiver(self, chip_info.x, chip_info.y, link) self._send_request( SCPReadLinkRequest( x=chip_info.x, y=chip_info.y, cpu=0, link=link, base_address=(constants.SYSTEM_VARIABLE_BASE_ADDRESS), size=constants.SYSTEM_VARIABLE_BYTES, ), receiver._receive_chip_details, self._receive_error, ) # Ensure all responses up to this point have been received self._finish() # If there is an exception, raise it self.check_for_error() # We now have all the chip details, now link them up and make a machine # Start by making a queue of (chip, link ids) to search, starting at # 0, 0 chip_0_0_info = self._chip_info[(0, 0)] chip_0_0 = self._machine.get_chip_at(0, 0) chip_search = deque([(chip_0_0, chip_0_0_info.links_available)]) # Go through the chips, link by link seen_chips = set() seen_chips.add((0, 0)) while len(chip_search) > 0: chip, links = chip_search.pop() # Go through the links of the chip for link in links: # Only continue if the chip link worked if (chip.x, chip.y, link) in self._link_destination: other_chip = self._link_destination[(chip.x, chip.y, link)] # Standard links use the opposite link id (with ids between # 0 and 5) as default opposite_link_id = (link + 3) % 6 # Check that the other chip link worked in reverse if (other_chip.x, other_chip.y, opposite_link_id) in self._link_destination: # Add the link to this chip chip.router.add_link( Link(chip.x, chip.y, link, other_chip.x, other_chip.y, opposite_link_id, opposite_link_id) ) # If the chip is not already seen, add it to the search if (other_chip.x, other_chip.y) not in seen_chips: other_chip_details = self._chip_info[(other_chip.x, other_chip.y)] chip_search.append((other_chip, other_chip_details.links_available)) seen_chips.add((other_chip.x, other_chip.y)) return self._machine def get_chip_info(self): """ Get the chip information for the machine. Note that\ get_machine_details must have been called first """ return self._chip_info
class GetMachineProcess(AbstractMultiConnectionProcess): """ A process for getting the machine details over a set of connections """ def __init__(self, connection_selector, ignore_chips, ignore_cores, max_core_id, max_sdram_size=None): """ :param scamp_connections: The connections to use for the interaction :type scamp_connections: iterable of\ :py:class:`spinnman.connections.abstract_classes.abstract_connection.AbstractConnection` """ AbstractMultiConnectionProcess.__init__(self, connection_selector) self._ignore_chips = ignore_chips self._ignore_cores = ignore_cores self._max_core_id = max_core_id self._max_sdram_size = max_sdram_size # A dictionary of (x, y) -> ChipInfo self._chip_info = dict() # The machine so far self._machine = Machine([]) # A dictionary of which link goes where from a chip: # (x, y, link) -> (x, y) self._link_destination = dict() # A queue of ChipInfo to be examined self._search = deque() def _make_chip(self, chip_details): """ Creates a chip from a ChipInfo structure :param chip_details: The ChipInfo structure to create the chip\ from :type chip_details: \ :py:class:`spinnman.model.chip_info.ChipInfo` :return: The created chip :rtype: :py:class:`spinn_machine.chip.Chip` """ # Create the processor list processors = list() for virtual_core_id in chip_details.virtual_core_ids: if (self._ignore_cores is not None and self._ignore_cores.is_core( chip_details.x, chip_details.y, virtual_core_id)): continue if (self._max_core_id is not None and virtual_core_id > self._max_core_id): continue processors.append( Processor(virtual_core_id, chip_details.cpu_clock_mhz * 1000000, virtual_core_id == 0)) # Create the router - add the links later during search router = Router(links=list(), emergency_routing_enabled=False, clock_speed=Router.ROUTER_DEFAULT_CLOCK_SPEED, n_available_multicast_entries=( Router.ROUTER_DEFAULT_AVAILABLE_ENTRIES - chip_details.first_free_router_entry)) # Create the chip's SDRAM object sdram = None if self._max_sdram_size is not None: size = (chip_details.system_sdram_base_address - chip_details.sdram_heap_address) if size > self._max_sdram_size: system_base_address = \ chip_details.sdram_heap_address + self._max_sdram_size sdram = SDRAM( user_base_address=chip_details.sdram_heap_address, system_base_address=system_base_address) else: sdram = SDRAM( user_base_address=chip_details.sdram_heap_address, system_base_address=chip_details.system_sdram_base_address) else: sdram = SDRAM( user_base_address=chip_details.sdram_heap_address, system_base_address=chip_details.system_sdram_base_address) # Create the chip chip = Chip(x=chip_details.x, y=chip_details.y, processors=processors, router=router, sdram=sdram, ip_address=chip_details.ip_address, nearest_ethernet_x=chip_details.nearest_ethernet_x, nearest_ethernet_y=chip_details.nearest_ethernet_y) # reset params for next iteration self._chip_x = None self._chip_y = None self._heap_address = None self._heap_size = None return chip def _receive_chip_details(self, scp_read_memory_response): try: new_chip_details = ChipInfo(scp_read_memory_response.data, scp_read_memory_response.offset) if (self._ignore_chips is not None and self._ignore_chips.is_chip( new_chip_details.x, new_chip_details.y)): return None key = (new_chip_details.x, new_chip_details.y) if key not in self._chip_info: self._chip_info[key] = new_chip_details self._search.append(new_chip_details) new_chip = self._make_chip(new_chip_details) self._machine.add_chip(new_chip) return new_chip return self._machine.get_chip_at(new_chip_details.x, new_chip_details.y) except Exception: traceback.print_exc() def _receive_chip_details_from_link(self, scp_read_link_response, source_x, source_y, link): new_chip = self._receive_chip_details(scp_read_link_response) if new_chip is not None: self._link_destination[(source_x, source_y, link)] = new_chip def _receive_error(self, request, exception, tracebackinfo): # If we get an SCPReadLinkRequest with a # SpinnmanUnexpectedResponseCodeException, this is a failed link # and so can be ignored if (not isinstance(request, SCPReadLinkRequest) or not isinstance( exception, exceptions.SpinnmanUnexpectedResponseCodeException)): AbstractProcess._receive_error(self, request, exception, tracebackinfo) def get_machine_details(self): # Get the details of chip 0, 0 self._send_request( SCPReadMemoryRequest( x=0, y=0, base_address=constants.SYSTEM_VARIABLE_BASE_ADDRESS, size=constants.SYSTEM_VARIABLE_BYTES), self._receive_chip_details, self._receive_error) self._finish() # Continue until there is nothing to search (and no exception) while not self.is_error() and len(self._search) > 0: # Set up the next round of searches using everything that # needs to search (same loop as above, I know, but wait for it) while not self.is_error() and len(self._search) > 0: chip_info = self._search.pop() # Examine the links of the chip to find the next chips for link in chip_info.links_available: # Add the read_link request - note that this might # add to the search if a response is received receiver = _ChipInfoReceiver(self, chip_info.x, chip_info.y, link) self._send_request( SCPReadLinkRequest( x=chip_info.x, y=chip_info.y, cpu=0, link=link, base_address=( constants.SYSTEM_VARIABLE_BASE_ADDRESS), size=constants.SYSTEM_VARIABLE_BYTES), receiver._receive_chip_details, self._receive_error) # Ensure all responses up to this point have been received self._finish() # If there is an exception, raise it self.check_for_error() # We now have all the chip details, now link them up and make a machine # Start by making a queue of (chip, link ids) to search, starting at # 0, 0 chip_0_0_info = self._chip_info[(0, 0)] chip_0_0 = self._machine.get_chip_at(0, 0) chip_search = deque([(chip_0_0, chip_0_0_info.links_available)]) # Go through the chips, link by link seen_chips = set() seen_chips.add((0, 0)) while len(chip_search) > 0: chip, links = chip_search.pop() # Go through the links of the chip for link in links: # Only continue if the chip link worked if (chip.x, chip.y, link) in self._link_destination: other_chip = self._link_destination[(chip.x, chip.y, link)] # Standard links use the opposite link id (with ids between # 0 and 5) as default opposite_link_id = (link + 3) % 6 # Check that the other chip link worked in reverse if ((other_chip.x, other_chip.y, opposite_link_id) in self._link_destination): # Add the link to this chip chip.router.add_link( Link(chip.x, chip.y, link, other_chip.x, other_chip.y, opposite_link_id, opposite_link_id)) # If the chip is not already seen, add it to the search if (other_chip.x, other_chip.y) not in seen_chips: other_chip_details = self._chip_info[( other_chip.x, other_chip.y)] chip_search.append( (other_chip, other_chip_details.links_available)) seen_chips.add((other_chip.x, other_chip.y)) return self._machine def get_chip_info(self): """ Get the chip information for the machine. Note that\ get_machine_details must have been called first """ return self._chip_info