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 __call__(self, spalloc_server, spalloc_port=22244, spalloc_machine=None, max_sdram_size=None, max_machine_core_reduction=0): """ :param str spalloc_server: :param int spalloc_port: :param str spalloc_machine: :param int max_sdram_size: :param int max_machine_core_reduction: :rtype: ~.Machine """ with ProtocolClient(spalloc_server, spalloc_port) as client: machines = client.list_machines() # Close the context immediately; don't want to keep this particular # connection around as there's not a great chance of this code # being rerun in this process any time soon. max_width = None max_height = None max_area = -1 for machine in self._filter(machines, spalloc_machine): # Get the width and height in chips, and logical area in chips**2 width, height, area = self._get_size(machine) # The "biggest" board is the one with the most chips if area > max_area: max_area = area max_width = width max_height = height if max_width is None: raise Exception( "The spalloc server appears to have no compatible machines") n_cpus_per_chip = (Machine.max_cores_per_chip() - max_machine_core_reduction) # Return the width and height, and make no assumption about wrap- # arounds or version. return virtual_machine(width=max_width, height=max_height, sdram_per_chip=max_sdram_size, n_cpus_per_chip=n_cpus_per_chip, validate=False)
def test_allocate_resources_when_chip_used(self): router = Router([]) sdram = SDRAM() empty_chip = Chip(0, 0, [], router, sdram, 0, 0, "127.0.0.1", virtual=False, tag_ids=[1]) machine = Machine([empty_chip], 0, 0) resource_tracker = ResourceTracker(machine) with self.assertRaises(PacmanValueError): resource_tracker.allocate_resources( ResourceContainer(sdram=SDRAMResource(1024)))
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 check_machine_is_booted(self): # Check that chip 0, 0 is booted result, chip_0_0_data = self._read_chip(0, 0) if chip_0_0_data is None: logger.error("Could not read from 0, 0: {}", result) return None, None progress_bar = ProgressBar( float(chip_0_0_data.x_size * chip_0_0_data.y_size * 2), "Verifying Machine") # Go through the chips, link by link chip_search = deque([chip_0_0_data]) seen_chips = OrderedDict({(0, 0): chip_0_0_data}) link_destination = dict() while len(chip_search) > 0: chip = chip_search.pop() details = seen_chips[chip.x, chip.y] for link in range(0, 6): chip_data = None retries = 3 while chip_data is None and retries > 0: _, chip_data = self._read_chip_down_link( chip.x, chip.y, link) if chip_data is not None and ( self._ignore_chips is None or not self._ignore_chips.is_chip( chip_data.x, chip_data.y)): link_destination[(chip.x, chip.y, link)] = (chip_data.x, chip_data.y) if (chip_data.x, chip_data.y) not in seen_chips: chip_search.append(chip_data) seen_chips[(chip_data.x, chip_data.y)] = chip_data progress_bar.update() elif link in details.links_available: retries -= 1 time.sleep(0.2) else: retries = 0 # Try to read each found chip machine = Machine([]) for x, y in seen_chips: if (self._ignore_chips is None or not self._ignore_chips.is_chip(x, y)): # Retry up to 3 times retries = 3 result = None chip_details = None while retries > 0: result, chip_details = self._read_chip(x, y) if chip_details is not None: self._add_chip(machine, chip_details, link_destination) progress_bar.update() break # Wait between retries time.sleep(0.5) retries -= 1 # If no version could be read, the machine might be faulty if chip_details is None: logger.warn( "Could not get version from chip {}, {}: {}".format( x, y, result)) progress_bar.update() progress_bar.end() return machine, seen_chips
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
def __init__( self, width=None, height=None, with_wrap_arounds=False, version=None, n_cpus_per_chip=18, with_monitors=True, sdram_per_chip=None): """ :param width: the width of the virtual machine in chips :type width: int :param height: the height of the virtual machine in chips :type height: int :param with_wrap_arounds: bool defining if wrap around links exist :type with_wrap_arounds: bool :param version: the version id of a board; if None, a machine is\ created with the correct dimensions, otherwise the machine\ will be a single board of the given version :type version: int :param n_cpus_per_chip: The number of CPUs to put on each chip :type n_cpus_per_chip: int :param with_monitors: True if CPU 0 should be marked as a monitor :type with_monitors: bool :param sdram_per_chip: The amount of SDRAM to give to each chip :type sdram_per_chip: int or None """ Machine.__init__(self, ()) if ((width is not None and width < 0) or (height is not None and height < 0)): raise exceptions.SpinnMachineInvalidParameterException( "width or height", "{} or {}".format(width, height), "Negative dimensions are not supported") if version is None and (width is None or height is None): raise exceptions.SpinnMachineInvalidParameterException( "version, width, height", "{}, {}, {}".format(version, width, height), "Either version must be specified, " "or width and height must both be specified") if version is not None and (version < 2 or version > 5): raise exceptions.SpinnMachineInvalidParameterException( "version", str(version), "Version must be between 2 and 5 inclusive or None") if ((version == 5 or version == 4) and with_wrap_arounds is not None and with_wrap_arounds): raise exceptions.SpinnMachineInvalidParameterException( "version and with_wrap_arounds", "{} and True".format(version), "A version {} board does not have wrap arounds; set " "version to None or with_wrap_arounds to None".format(version)) if (version == 2 or version == 3) and with_wrap_arounds is not None: raise exceptions.SpinnMachineInvalidParameterException( "version and with_wrap_arounds", "{} and {}".format(version, with_wrap_arounds), "A version {} board has complex wrap arounds; set " "version to None or with_wrap_arounds to None".format(version)) if ((version == 5 or version == 4) and ( (width is not None and width != 8) or (height is not None and height != 8))): raise exceptions.SpinnMachineInvalidParameterException( "version, width, height", "{}, {}, {}".format(version, width, height), "A version {} board has a width and height of 8; set " "version to None or width and height to None".format(version)) if ((version == 2 or version == 3) and ( (width is not None and width != 2) or (height is not None and height != 2))): raise exceptions.SpinnMachineInvalidParameterException( "version, width, height", "{}, {}, {}".format(version, width, height), "A version {} board has a width and height of 2; set " "version to None or width and height to None".format(version)) if version == 5 or version == 4: if width is None: width = 8 if height is None: height = 8 with_wrap_arounds = False if version == 2 or version == 3: if width is None: width = 2 if height is None: height = 2 with_wrap_arounds = True # if x and y are none, assume a 48 chip board logger.debug("width = {} and height = {}".format(width, height)) # calculate the chip ids which this machine is going to have chip_ids = list() for i in xrange(width): for j in xrange(height): coords = (i, j) if (version == 5 and width == 8 and height == 8 and coords in _48boardgaps): # a chip doesn't exist in this static position # on these boards, so nullify it pass else: chip_ids.append((i, j)) progress_bar = ProgressBar( width * height, "Generating a virtual machine") # Create the chips and their links for i in xrange(width): for j in xrange(height): coords = (i, j) if (version == 5 and width == 8 and height == 8 and coords in _48boardgaps): # a chip doesn't exist in this static position # on these boards, so nullify it pass else: processors = list() for processor_id in range(0, n_cpus_per_chip): processor = Processor(processor_id, 200000000) if processor_id == 0 and with_monitors: processor.is_monitor = True processors.append(processor) chip_links = self._calculate_links( i, j, width, height, with_wrap_arounds, version, chip_ids) chip_router = Router(chip_links, False) if sdram_per_chip is None: sdram = SDRAM() else: system_base_address = ( SDRAM.DEFAULT_BASE_ADDRESS + sdram_per_chip) sdram = SDRAM(system_base_address=system_base_address) chip = Chip(i, j, processors, chip_router, sdram, 0, 0, "127.0.0.1") self.add_chip(chip) progress_bar.update() progress_bar.end() processor_count = 0 for chip in self.chips: processor_count += len(list(chip.processors)) link_count = 0 for chip in self.chips: link_count += len(list(chip.router.links)) logger.debug( "Static Allocation Complete;" " {} calculated app cores and {} links!".format( processor_count, link_count))