From 8d219e790d50e52c94811f3b091a983685ba31db Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 11:49:33 +0100 Subject: [PATCH 1/9] ExtendedTransceiver --- quick_tests/quick_tests.py | 3 +- spinnman/extended/__init__.py | 1 + spinnman/extended/extended_transceiver.py | 688 ++++++++++++++++++++++ spinnman/processes/__init__.py | 2 +- spinnman/transceiver.py | 497 ---------------- unittests/test_transceiver.py | 11 +- 6 files changed, 701 insertions(+), 501 deletions(-) create mode 100644 spinnman/extended/__init__.py create mode 100644 spinnman/extended/extended_transceiver.py diff --git a/quick_tests/quick_tests.py b/quick_tests/quick_tests.py index 293cad6f5..89ae9315f 100644 --- a/quick_tests/quick_tests.py +++ b/quick_tests/quick_tests.py @@ -29,7 +29,8 @@ from spinn_machine.tags import IPTag, ReverseIPTag from spinnman.data import SpiNNManDataView from spinnman.config_setup import unittest_setup -from spinnman.transceiver import create_transceiver_from_hostname +from spinnman.extended.extended_transceiver import ( + create_transceiver_from_hostname) from spinnman.model.enums import CPUState from spinnman.messages.scp.enums import Signal from spinnman.model import DiagnosticFilter diff --git a/spinnman/extended/__init__.py b/spinnman/extended/__init__.py new file mode 100644 index 000000000..8a28c5495 --- /dev/null +++ b/spinnman/extended/__init__.py @@ -0,0 +1 @@ +from .de_alloc_sdram_process import DeAllocSDRAMProcess \ No newline at end of file diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py new file mode 100644 index 000000000..5cbe6a7c4 --- /dev/null +++ b/spinnman/extended/extended_transceiver.py @@ -0,0 +1,688 @@ +# Copyright (c) 2014 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=too-many-arguments +import io +import os +import random +import struct +from threading import Condition, RLock +from collections import defaultdict +from contextlib import contextmanager, suppress +import logging +import socket +import time +from spinn_utilities.config_holder import get_config_bool +from spinn_utilities.log import FormatAdapter +from spinn_utilities.logger_utils import warn_once +from spinn_machine import CoreSubsets +from spinnman.transceiver import Transceiver +from spinnman.constants import ( + BMP_POST_POWER_ON_SLEEP_TIME, BMP_POWER_ON_TIMEOUT, BMP_TIMEOUT, + CPU_MAX_USER, CPU_USER_OFFSET, CPU_USER_START_ADDRESS, + IPTAG_TIME_OUT_WAIT_TIMES, SCP_SCAMP_PORT, SYSTEM_VARIABLE_BASE_ADDRESS, + UDP_BOOT_CONNECTION_DEFAULT_PORT, NO_ROUTER_DIAGNOSTIC_FILTERS, + ROUTER_REGISTER_BASE_ADDRESS, ROUTER_DEFAULT_FILTERS_MAX_POSITION, + ROUTER_FILTER_CONTROLS_OFFSET, ROUTER_DIAGNOSTIC_FILTER_SIZE, N_RETRIES, + BOOT_RETRIES) +from spinnman.data import SpiNNManDataView +from spinnman.exceptions import ( + SpinnmanInvalidParameterException, SpinnmanException, SpinnmanIOException, + SpinnmanTimeoutException, SpinnmanGenericProcessException, + SpinnmanUnexpectedResponseCodeException, + SpiNNManCoresNotInStateException) +from spinnman.model import DiagnosticFilter, MachineDimensions +from spinnman.model.enums import ( + CPUState, SDP_PORTS, SDP_RUNNING_MESSAGE_CODES) +from spinnman.messages.scp.enums import Signal +from spinnman.messages.scp.impl.get_chip_info import GetChipInfo +from spinnman.messages.sdp import SDPFlag, SDPHeader, SDPMessage +from spinnman.messages.spinnaker_boot import ( + SystemVariableDefinition, SpinnakerBootMessages) +from spinnman.messages.scp.enums import PowerCommand +from spinnman.messages.scp.abstract_messages import AbstractSCPRequest +from spinnman.messages.scp.impl import ( + BMPSetLed, BMPGetVersion, SetPower, ReadADC, ReadFPGARegister, + WriteFPGARegister, IPTagSetTTO, ReverseIPTagSet, ReadMemory, + CountState, WriteMemory, SetLED, ApplicationRun, SendSignal, AppStop, + IPTagSet, IPTagClear, RouterClear, DoSync) +from spinnman.connections.udp_packet_connections import ( + BMPConnection, BootConnection, SCAMPConnection) +from spinnman.processes import ( + DeAllocSDRAMProcess, GetMachineProcess, GetVersionProcess, + MallocSDRAMProcess, WriteMemoryProcess, ReadMemoryProcess, + GetCPUInfoProcess, GetExcludeCPUInfoProcess, GetIncludeCPUInfoProcess, + ReadIOBufProcess, ApplicationRunProcess, GetHeapProcess, + LoadFixedRouteRoutingEntryProcess, FixedConnectionSelector, + ReadFixedRouteRoutingEntryProcess, WriteMemoryFloodProcess, + LoadMultiCastRoutesProcess, GetTagsProcess, GetMultiCastRoutesProcess, + SendSingleCommandProcess, ReadRouterDiagnosticsProcess, + MostDirectConnectionSelector, ApplicationCopyRunProcess) +from spinnman.utilities.utility_functions import ( + get_vcpu_address, work_out_bmp_from_machine_details) + +logger = FormatAdapter(logging.getLogger(__name__)) + +_SCAMP_NAME = "SC&MP" +_SCAMP_VERSION = (3, 0, 1) + +_BMP_NAME = "BC&MP" +_BMP_MAJOR_VERSIONS = [1, 2] + +_CONNECTION_CHECK_RETRIES = 3 +INITIAL_FIND_SCAMP_RETRIES_COUNT = 3 + +_ONE_BYTE = struct.Struct("B") +_TWO_BYTES = struct.Struct("= 4 and auto_detect_bmp is True and + (bmp_connection_data is None or not bmp_connection_data)): + bmp_connection_data = [ + work_out_bmp_from_machine_details(hostname, number_of_boards)] + + # handle BMP connections + if bmp_connection_data is not None: + bmp_ip_list = list() + for conn_data in bmp_connection_data: + bmp_connection = BMPConnection(conn_data) + connections.append(bmp_connection) + bmp_ip_list.append(bmp_connection.remote_ip_address) + logger.info("Transceiver using BMPs: {}", bmp_ip_list) + + connections.append(SCAMPConnection(remote_host=hostname)) + + # handle the boot connection + connections.append(BootConnection(remote_host=hostname)) + + return ExtendedTransceiver(version, connections=connections) + + +class ExtendedTransceiver(Transceiver): + """ + An encapsulation of various communications with the SpiNNaker board. + + The methods of this class are designed to be thread-safe (provided they do + not access a BMP, as access to those is never thread-safe); + thus you can make multiple calls to the same (or different) methods + from multiple threads and expect each call to work as if it had been + called sequentially, although the order of returns is not guaranteed. + + .. note:: + With multiple connections to the board, using multiple threads in this + way may result in an increase in the overall speed of operation, since + the multiple calls may be made separately over the set of given + connections. + """ + __slots__ = [] + + def send_scp_message(self, message, connection=None): + """ + Sends an SCP message, without expecting a response. + + :param AbstractSCPRequest message: The message to send + :param SCAMPConnection connection: + The connection to use (omit to pick a random one) + :raise SpinnmanTimeoutException: + If there is a timeout before a message is received + :raise SpinnmanInvalidParameterException: + If one of the fields of the received message is invalid + :raise SpinnmanInvalidPacketException: + * If the message is not a recognised packet type + * If a packet is received that is not a valid response + :raise SpinnmanUnsupportedOperationException: + If no connection can send the type of message given + :raise SpinnmanIOException: + If there is an error sending the message or receiving the response + :raise SpinnmanUnexpectedResponseCodeException: + If the response is not one of the expected codes + """ + if connection is None: + connection = self._get_random_connection(self._scamp_connections) + connection.send_scp_request(message) + + def get_connections(self): + """ + Get the currently known connections to the board, made up of those + passed in to the transceiver and those that are discovered during + calls to discover_connections. No further discovery is done here. + + :return: An iterable of connections known to the transceiver + :rtype: list(Connection) + """ + return self._all_connections + + def is_connected(self, connection=None): + """ + Determines if the board can be contacted. + + :param Connection connection: + The connection which is to be tested. If `None`, + all connections will be tested, and the board will be considered + to be connected if any one connection works. + :return: True if the board can be contacted, False otherwise + :rtype: bool + """ + if connection is not None: + return connection.is_connected() + return any(c.is_connected() for c in self._scamp_connections) + + def set_watch_dog(self, watch_dog): + """ + Enable, disable or set the value of the watch dog timer. + + .. warning:: + This method is currently deprecated and untested as there is no + known use. Same functionality provided by ybug and bmpc. + Retained in case needed for hardware debugging. + + :param watch_dog: + Either a boolean indicating whether to enable (True) or + disable (False) the watch dog timer, or an int value to set the + timer count to. + :type watch_dog: bool or int + """ + warn_once(logger, "The set_watch_dog method is deprecated and " + "untested due to no known use.") + for x, y in SpiNNManDataView.get_machine().chip_coordinates: + self.set_watch_dog_on_chip(x, y, watch_dog) + + def get_iobuf_from_core(self, x, y, p): + """ + Get the contents of IOBUF for a given core. + + .. warning:: + This method is currently deprecated and likely to be removed. + + :param int x: The x-coordinate of the chip containing the processor + :param int y: The y-coordinate of the chip containing the processor + :param int p: The ID of the processor to get the IOBUF for + :return: An IOBUF buffer + :rtype: IOBuffer + :raise SpinnmanIOException: + If there is an error communicating with the board + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + * If chip_and_cores contains invalid items + * If a packet is received that has invalid parameters + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + warn_once(logger, "The get_iobuf_from_core method is deprecated and " + "likely to be removed.") + core_subsets = CoreSubsets() + core_subsets.add_processor(x, y, p) + return next(self.get_iobuf(core_subsets)) + + def execute( + self, x, y, processors, executable, app_id, n_bytes=None, + wait=False, is_filename=False): + """ + Start an executable running on a single chip. + + .. warning:: + This method is currently deprecated and likely to be removed. + + :param int x: + The x-coordinate of the chip on which to run the executable + :param int y: + The y-coordinate of the chip on which to run the executable + :param list(int) processors: + The cores on the chip on which to run the application + :param executable: + The data that is to be executed. Should be one of the following: + + * An instance of RawIOBase + * A bytearray/bytes + * A filename of a file containing the executable (in which case + `is_filename` must be set to True) + :type executable: + ~io.RawIOBase or bytes or bytearray or str + :param int app_id: + The ID of the application with which to associate the executable + :param int n_bytes: + The size of the executable data in bytes. If not specified: + + * If executable is an RawIOBase, an error is raised + * If executable is a bytearray, the length of the bytearray will + be used + * If executable is an int, 4 will be used + * If executable is a str, the length of the file will be used + :param bool wait: + True if the binary should enter a "wait" state on loading + :param bool is_filename: True if executable is a filename + :raise SpinnmanIOException: + * If there is an error communicating with the board + * If there is an error reading the executable + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + * If x, y, p does not lead to a valid core + * If app_id is an invalid application ID + * If a packet is received that has invalid parameters + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + warn_once(logger, "The Transceiver's execute method is deprecated " + "likely to be removed.") + # Lock against updates + with self._chip_execute_lock(x, y): + # Write the executable + self.write_memory( + x, y, _EXECUTABLE_ADDRESS, executable, n_bytes, + is_filename=is_filename) + + # Request the start of the executable + process = SendSingleCommandProcess(self._scamp_connection_selector) + process.execute(ApplicationRun(app_id, x, y, processors, wait)) + + def execute_application(self, executable_targets, app_id): + """ + Execute a set of binaries that make up a complete application on + specified cores, wait for them to be ready and then start all of the + binaries. + + .. note:: + This will get the binaries into c_main but will not signal the + barrier. + + :param ExecutableTargets executable_targets: + The binaries to be executed and the cores to execute them on + :param int app_id: The app_id to give this application + """ + # Execute each of the binaries and get them in to a "wait" state + for binary in executable_targets.binaries: + core_subsets = executable_targets.get_cores_for_binary(binary) + self.execute_flood( + core_subsets, binary, app_id, wait=True, is_filename=True) + + # Sleep to allow cores to get going + time.sleep(0.5) + + # Check that the binaries have reached a wait state + count = self.get_core_state_count(app_id, CPUState.READY) + if count < executable_targets.total_processors: + cores_ready = self.get_cpu_infos( + executable_targets.all_core_subsets, [CPUState.READY], + include=False) + if len(cores_ready) > 0: + raise SpinnmanException( + f"Only {count} of {executable_targets.total_processors} " + "cores reached ready state: " + f"{cores_ready.get_status_string()}") + + # Send a signal telling the application to start + self.send_signal(app_id, Signal.START) + + def set_led(self, led, action, board, cabinet, frame): + """ + Set the LED state of a board in the machine. + + .. warning:: + This method is currently deprecated and untested as there is no + known use. Same functionality provided by ybug and bmpc. + Retained in case needed for hardware debugging. + + :param led: + Number of the LED or an iterable of LEDs to set the state of (0-7) + :type led: int or iterable(int) + :param LEDAction action: + State to set the LED to, either on, off or toggle + :param board: Specifies the board to control the LEDs of. This may + also be an iterable of multiple boards (in the same frame). The + command will actually be sent to the first board in the iterable. + :type board: int or iterable(int) + :param int cabinet: the cabinet this is targeting + :param int frame: the frame this is targeting + """ + warn_once(logger, "The set_led method is deprecated and " + "untested due to no known use.") + process = SendSingleCommandProcess( + self._bmp_connection(cabinet, frame)) + process.execute(BMPSetLed(led, action, board)) + + def read_adc_data(self, board, cabinet, frame): + """ + Read the BMP ADC data. + + .. warning:: + This method is currently deprecated and untested as there is no + known use. Same functionality provided by ybug and bmpc. + Retained in case needed for hardware debugging. + + :param int cabinet: cabinet: the cabinet this is targeting + :param int frame: the frame this is targeting + :param int board: which board to request the ADC data from + :return: the FPGA's ADC data object + :rtype: ADCInfo + """ + warn_once(logger, "The read_adc_data method is deprecated and " + "untested due to no known use.") + process = SendSingleCommandProcess( + self._bmp_connection(cabinet, frame)) + response = process.execute(ReadADC(board)) + return response.adc_info # pylint: disable=no-member + + def write_neighbour_memory(self, x, y, link, base_address, data, + n_bytes=None, offset=0, cpu=0): + """ + Write to the memory of a neighbouring chip using a LINK_READ SCP + command. If sent to a BMP, this command can be used to communicate + with the FPGAs' debug registers. + + .. warning:: + This method is deprecated and untested due to no known use. + + :param int x: + The x-coordinate of the chip whose neighbour is to be written to + :param int y: + The y-coordinate of the chip whose neighbour is to be written to + :param int link: + The link index to send the request to (or if BMP, the FPGA number) + :param int base_address: + The address in SDRAM where the region of memory is to be written + :param data: The data to write. Should be one of the following: + + * An instance of RawIOBase + * A bytearray/bytes + * A single integer; will be written in little-endian byte order + :type data: + ~io.RawIOBase or bytes or bytearray or int + :param int n_bytes: + The amount of data to be written in bytes. If not specified: + + * If `data` is an RawIOBase, an error is raised + * If `data` is a bytearray, the length of the bytearray will be + used + * If `data` is an int, 4 will be used + :param int offset: + The offset where the valid data starts (if `data` is + an int then offset will be ignored and used 0) + :param int cpu: + The CPU to use, typically 0 (or if a BMP, the slot number) + :raise SpinnmanIOException: + * If there is an error communicating with the board + * If there is an error reading the data + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + * If `x, y` does not lead to a valid chip + * If a packet is received that has invalid parameters + * If `base_address` is not a positive integer + * If `data` is an RawIOBase but `n_bytes` is not specified + * If `data` is an int and `n_bytes` is more than 4 + * If `n_bytes` is less than 0 + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + warn_once(logger, "The write_neighbour_memory method is deprecated " + "and untested due to no known use.") + process = WriteMemoryProcess(self._scamp_connection_selector) + if isinstance(data, io.RawIOBase): + process.write_link_memory_from_reader( + x, y, cpu, link, base_address, data, n_bytes) + elif isinstance(data, int): + data_to_write = _ONE_WORD.pack(data) + process.write_link_memory_from_bytearray( + x, y, cpu, link, base_address, data_to_write, 0, 4) + else: + if n_bytes is None: + n_bytes = len(data) + process.write_link_memory_from_bytearray( + x, y, cpu, link, base_address, data, offset, n_bytes) + + def read_neighbour_memory(self, x, y, link, base_address, length, cpu=0): + """ + Read some areas of memory on a neighbouring chip using a LINK_READ + SCP command. If sent to a BMP, this command can be used to + communicate with the FPGAs' debug registers. + + .. warning:: + This method is currently deprecated and untested as there is no + known use. Same functionality provided by ybug and bmpc. + Retained in case needed for hardware debugging. + + :param int x: + The x-coordinate of the chip whose neighbour is to be read from + :param int y: + The y-coordinate of the chip whose neighbour is to be read from + :param int cpu: + The CPU to use, typically 0 (or if a BMP, the slot number) + :param int link: + The link index to send the request to (or if BMP, the FPGA number) + :param int base_address: + The address in SDRAM where the region of memory to be read starts + :param int length: The length of the data to be read in bytes + :return: An iterable of chunks of data read in order + :rtype: bytes + :raise SpinnmanIOException: + If there is an error communicating with the board + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + * If one of `x`, `y`, `cpu`, `base_address` or `length` is invalid + * If a packet is received that has invalid parameters + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + try: + warn_once(logger, "The read_neighbour_memory method is deprecated " + "and untested due to no known use.") + process = ReadMemoryProcess(self._scamp_connection_selector) + return process.read_link_memory( + x, y, cpu, link, base_address, length) + except Exception: + logger.info(self.__where_is_xy(x, y)) + raise + + def set_leds(self, x, y, cpu, led_states): + """ + Set LED states. + + .. warning:: + The set_leds is deprecated and untested due to no known use. + + :param int x: The x-coordinate of the chip on which to set the LEDs + :param int y: The x-coordinate of the chip on which to set the LEDs + :param int cpu: The CPU of the chip on which to set the LEDs + :param dict(int,int) led_states: + A dictionary mapping SetLED index to state with + 0 being off, 1 on and 2 inverted. + :raise SpinnmanIOException: + If there is an error communicating with the board + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + If a packet is received that has invalid parameters + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + try: + warn_once(logger, "The set_leds is deprecated and " + "untested due to no known use.") + process = SendSingleCommandProcess(self._scamp_connection_selector) + process.execute(SetLED(x, y, cpu, led_states)) + except Exception: + logger.info(self.__where_is_xy(x, y)) + raise + + def free_sdram(self, x, y, base_address, app_id): + """ + Free allocated SDRAM. + + .. warning:: + This method is currently deprecated and likely to be removed. + + :param int x: The x-coordinate of the chip onto which to ask for memory + :param int y: The y-coordinate of the chip onto which to ask for memory + :param int base_address: The base address of the allocated memory + :param int app_id: The app ID of the allocated memory + """ + try: + warn_once(logger, "The free_sdram method is deprecated and " + "likely to be removed.") + process = DeAllocSDRAMProcess(self._scamp_connection_selector) + process.de_alloc_sdram(x, y, app_id, base_address) + except Exception: + logger.info(self.__where_is_xy(x, y)) + raise + + def free_sdram_by_app_id(self, x, y, app_id): + """ + Free all SDRAM allocated to a given app ID. + + .. warning:: + This method is currently deprecated and untested as there is no + known use. Same functionality provided by ybug and bmpc. + Retained in case needed for hardware debugging. + + :param int x: The x-coordinate of the chip onto which to ask for memory + :param int y: The y-coordinate of the chip onto which to ask for memory + :param int app_id: The app ID of the allocated memory + :return: The number of blocks freed + :rtype: int + """ + try: + warn_once(logger, "The free_sdram_by_app_id method is deprecated " + "and untested due to no known use.") + process = DeAllocSDRAMProcess(self._scamp_connection_selector) + process.de_alloc_sdram(x, y, app_id) + return process.no_blocks_freed + except Exception: + logger.info(self.__where_is_xy(x, y)) + raise + + def get_router_diagnostic_filter(self, x, y, position): + """ + Gets a router diagnostic filter from a router. + + :param int x: + the X address of the router from which this filter is being + retrieved + :param int y: + the Y address of the router from which this filter is being + retrieved + :param int position: + the position in the list of filters to read the information from + :return: The diagnostic filter read + :rtype: DiagnosticFilter + :raise SpinnmanIOException: + * If there is an error communicating with the board + * If there is an error reading the data + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + * If x, y does not lead to a valid chip + * If a packet is received that has invalid parameters + * If position is less than 0 or more than 15 + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + try: + memory_position = ( + ROUTER_REGISTER_BASE_ADDRESS + ROUTER_FILTER_CONTROLS_OFFSET + + position * ROUTER_DIAGNOSTIC_FILTER_SIZE) + + process = SendSingleCommandProcess( + self._scamp_connection_selector) + response = process.execute(ReadMemory(x, y, memory_position, 4)) + return DiagnosticFilter.read_from_int(_ONE_WORD.unpack_from( + response.data, response.offset)[0]) + # pylint: disable=no-member + except Exception: + logger.info(self.__where_is_xy(x, y)) + raise + + @property + def number_of_boards_located(self): + """ + The number of boards currently configured. + + .. warning:: + This property is currently deprecated and likely to be removed. + + :rtype: int + """ + warn_once(logger, "The number_of_boards_located method is deprecated " + "and likely to be removed.") + boards = 0 + for bmp_connection in self._bmp_connections: + boards += len(bmp_connection.boards) + + # if no BMPs are available, then there's still at least one board + return max(1, boards) + + @property + def bmp_connection(self): + """ + The BMP connections. + + .. warning:: + This property is currently deprecated and likely to be removed. + + :rtype: dict(tuple(int,int),MostDirectConnectionSelector) + """ + warn_once(logger, "The bmp_connection property is deprecated and " + "likely to be removed.") + return self._bmp_connection_selectors diff --git a/spinnman/processes/__init__.py b/spinnman/processes/__init__.py index a14231574..cff96694f 100644 --- a/spinnman/processes/__init__.py +++ b/spinnman/processes/__init__.py @@ -17,7 +17,7 @@ AbstractMultiConnectionProcessConnectionSelector) from .application_copy_run_process import ApplicationCopyRunProcess from .application_run_process import ApplicationRunProcess -from .de_alloc_sdram_process import DeAllocSDRAMProcess + from .fixed_connection_selector import FixedConnectionSelector from .get_heap_process import GetHeapProcess from .get_cpu_info_process import GetCPUInfoProcess diff --git a/spinnman/transceiver.py b/spinnman/transceiver.py index ec62af2a4..16cd2b385 100644 --- a/spinnman/transceiver.py +++ b/spinnman/transceiver.py @@ -438,31 +438,6 @@ def _get_random_connection(connections): return None return connections[random.randint(0, len(connections) - 1)] - def send_scp_message(self, message, connection=None): - """ - Sends an SCP message, without expecting a response. - - :param AbstractSCPRequest message: The message to send - :param SCAMPConnection connection: - The connection to use (omit to pick a random one) - :raise SpinnmanTimeoutException: - If there is a timeout before a message is received - :raise SpinnmanInvalidParameterException: - If one of the fields of the received message is invalid - :raise SpinnmanInvalidPacketException: - * If the message is not a recognised packet type - * If a packet is received that is not a valid response - :raise SpinnmanUnsupportedOperationException: - If no connection can send the type of message given - :raise SpinnmanIOException: - If there is an error sending the message or receiving the response - :raise SpinnmanUnexpectedResponseCodeException: - If the response is not one of the expected codes - """ - if connection is None: - connection = self._get_random_connection(self._scamp_connections) - connection.send_scp_request(message) - def send_sdp_message(self, message, connection=None): """ Sends an SDP message using one of the connections. @@ -573,17 +548,6 @@ def add_scamp_connections(self, connections): self._scamp_connection_selector = MostDirectConnectionSelector( self._scamp_connections) - def get_connections(self): - """ - Get the currently known connections to the board, made up of those - passed in to the transceiver and those that are discovered during - calls to discover_connections. No further discovery is done here. - - :return: An iterable of connections known to the transceiver - :rtype: list(Connection) - """ - return self._all_connections - def get_machine_dimensions(self): """ Get the maximum chip X-coordinate and maximum chip Y-coordinate of @@ -646,21 +610,6 @@ def get_machine_details(self): logger.info(f"Detected {machine.summary_string()}") return machine - def is_connected(self, connection=None): - """ - Determines if the board can be contacted. - - :param Connection connection: - The connection which is to be tested. If `None`, - all connections will be tested, and the board will be considered - to be connected if any one connection works. - :return: True if the board can be contacted, False otherwise - :rtype: bool - """ - if connection is not None: - return connection.is_connected() - return any(c.is_connected() for c in self._scamp_connections) - def get_scamp_version( self, chip_x=AbstractSCPRequest.DEFAULT_DEST_X_COORD, chip_y=AbstractSCPRequest.DEFAULT_DEST_Y_COORD, @@ -1114,54 +1063,6 @@ def set_watch_dog_on_chip(self, x, y, watch_dog): address = SYSTEM_VARIABLE_BASE_ADDRESS + WATCHDOG.offset self.write_memory(x=x, y=y, base_address=address, data=data) - def set_watch_dog(self, watch_dog): - """ - Enable, disable or set the value of the watch dog timer. - - .. warning:: - This method is currently deprecated and untested as there is no - known use. Same functionality provided by ybug and bmpc. - Retained in case needed for hardware debugging. - - :param watch_dog: - Either a boolean indicating whether to enable (True) or - disable (False) the watch dog timer, or an int value to set the - timer count to. - :type watch_dog: bool or int - """ - warn_once(logger, "The set_watch_dog method is deprecated and " - "untested due to no known use.") - for x, y in SpiNNManDataView.get_machine().chip_coordinates: - self.set_watch_dog_on_chip(x, y, watch_dog) - - def get_iobuf_from_core(self, x, y, p): - """ - Get the contents of IOBUF for a given core. - - .. warning:: - This method is currently deprecated and likely to be removed. - - :param int x: The x-coordinate of the chip containing the processor - :param int y: The y-coordinate of the chip containing the processor - :param int p: The ID of the processor to get the IOBUF for - :return: An IOBUF buffer - :rtype: IOBuffer - :raise SpinnmanIOException: - If there is an error communicating with the board - :raise SpinnmanInvalidPacketException: - If a packet is received that is not in the valid format - :raise SpinnmanInvalidParameterException: - * If chip_and_cores contains invalid items - * If a packet is received that has invalid parameters - :raise SpinnmanUnexpectedResponseCodeException: - If a response indicates an error during the exchange - """ - warn_once(logger, "The get_iobuf_from_core method is deprecated and " - "likely to be removed.") - core_subsets = CoreSubsets() - core_subsets.add_processor(x, y, p) - return next(self.get_iobuf(core_subsets)) - def get_core_state_count(self, app_id, state): """ Get a count of the number of cores which have a given state. @@ -1186,68 +1087,6 @@ def get_core_state_count(self, app_id, state): response = process.execute(CountState(app_id, state)) return response.count # pylint: disable=no-member - def execute( - self, x, y, processors, executable, app_id, n_bytes=None, - wait=False, is_filename=False): - """ - Start an executable running on a single chip. - - .. warning:: - This method is currently deprecated and likely to be removed. - - :param int x: - The x-coordinate of the chip on which to run the executable - :param int y: - The y-coordinate of the chip on which to run the executable - :param list(int) processors: - The cores on the chip on which to run the application - :param executable: - The data that is to be executed. Should be one of the following: - - * An instance of RawIOBase - * A bytearray/bytes - * A filename of a file containing the executable (in which case - `is_filename` must be set to True) - :type executable: - ~io.RawIOBase or bytes or bytearray or str - :param int app_id: - The ID of the application with which to associate the executable - :param int n_bytes: - The size of the executable data in bytes. If not specified: - - * If executable is an RawIOBase, an error is raised - * If executable is a bytearray, the length of the bytearray will - be used - * If executable is an int, 4 will be used - * If executable is a str, the length of the file will be used - :param bool wait: - True if the binary should enter a "wait" state on loading - :param bool is_filename: True if executable is a filename - :raise SpinnmanIOException: - * If there is an error communicating with the board - * If there is an error reading the executable - :raise SpinnmanInvalidPacketException: - If a packet is received that is not in the valid format - :raise SpinnmanInvalidParameterException: - * If x, y, p does not lead to a valid core - * If app_id is an invalid application ID - * If a packet is received that has invalid parameters - :raise SpinnmanUnexpectedResponseCodeException: - If a response indicates an error during the exchange - """ - warn_once(logger, "The Transceiver's execute method is deprecated " - "likely to be removed.") - # Lock against updates - with self._chip_execute_lock(x, y): - # Write the executable - self.write_memory( - x, y, _EXECUTABLE_ADDRESS, executable, n_bytes, - is_filename=is_filename) - - # Request the start of the executable - process = SendSingleCommandProcess(self._scamp_connection_selector) - process.execute(ApplicationRun(app_id, x, y, processors, wait)) - def _get_next_nearest_neighbour_id(self): with self._nearest_neighbour_lock: next_nearest_neighbour_id = (self._nearest_neighbour_id + 1) % 127 @@ -1321,44 +1160,6 @@ def execute_flood( self._scamp_connection_selector) process.run(n_bytes, app_id, core_subsets, chksum, wait) - def execute_application(self, executable_targets, app_id): - """ - Execute a set of binaries that make up a complete application on - specified cores, wait for them to be ready and then start all of the - binaries. - - .. note:: - This will get the binaries into c_main but will not signal the - barrier. - - :param ExecutableTargets executable_targets: - The binaries to be executed and the cores to execute them on - :param int app_id: The app_id to give this application - """ - # Execute each of the binaries and get them in to a "wait" state - for binary in executable_targets.binaries: - core_subsets = executable_targets.get_cores_for_binary(binary) - self.execute_flood( - core_subsets, binary, app_id, wait=True, is_filename=True) - - # Sleep to allow cores to get going - time.sleep(0.5) - - # Check that the binaries have reached a wait state - count = self.get_core_state_count(app_id, CPUState.READY) - if count < executable_targets.total_processors: - cores_ready = self.get_cpu_infos( - executable_targets.all_core_subsets, [CPUState.READY], - include=False) - if len(cores_ready) > 0: - raise SpinnmanException( - f"Only {count} of {executable_targets.total_processors} " - "cores reached ready state: " - f"{cores_ready.get_status_string()}") - - # Send a signal telling the application to start - self.send_signal(app_id, Signal.START) - def power_on_machine(self): """ Power on the whole machine. @@ -1452,33 +1253,6 @@ def _power(self, power_command, boards=0, cabinet=0, frame=0): if not self._machine_off: time.sleep(BMP_POST_POWER_ON_SLEEP_TIME) - def set_led(self, led, action, board, cabinet, frame): - """ - Set the LED state of a board in the machine. - - .. warning:: - This method is currently deprecated and untested as there is no - known use. Same functionality provided by ybug and bmpc. - Retained in case needed for hardware debugging. - - :param led: - Number of the LED or an iterable of LEDs to set the state of (0-7) - :type led: int or iterable(int) - :param LEDAction action: - State to set the LED to, either on, off or toggle - :param board: Specifies the board to control the LEDs of. This may - also be an iterable of multiple boards (in the same frame). The - command will actually be sent to the first board in the iterable. - :type board: int or iterable(int) - :param int cabinet: the cabinet this is targeting - :param int frame: the frame this is targeting - """ - warn_once(logger, "The set_led method is deprecated and " - "untested due to no known use.") - process = SendSingleCommandProcess( - self._bmp_connection(cabinet, frame)) - process.execute(BMPSetLed(led, action, board)) - def read_fpga_register(self, fpga_num, register, cabinet, frame, board): """ Read a register on a FPGA of a board. The meaning of the @@ -1520,28 +1294,6 @@ def write_fpga_register(self, fpga_num, register, value, cabinet, frame, process.execute( WriteFPGARegister(fpga_num, register, value, board)) - def read_adc_data(self, board, cabinet, frame): - """ - Read the BMP ADC data. - - .. warning:: - This method is currently deprecated and untested as there is no - known use. Same functionality provided by ybug and bmpc. - Retained in case needed for hardware debugging. - - :param int cabinet: cabinet: the cabinet this is targeting - :param int frame: the frame this is targeting - :param int board: which board to request the ADC data from - :return: the FPGA's ADC data object - :rtype: ADCInfo - """ - warn_once(logger, "The read_adc_data method is deprecated and " - "untested due to no known use.") - process = SendSingleCommandProcess( - self._bmp_connection(cabinet, frame)) - response = process.execute(ReadADC(board)) - return response.adc_info # pylint: disable=no-member - def read_bmp_version(self, board, cabinet, frame): """ Read the BMP version. @@ -1652,74 +1404,6 @@ def write_user(self, x, y, p, user, value): addr = self.__get_user_register_address_from_core(p, user) self.write_memory(x, y, addr, int(value)) - def write_neighbour_memory(self, x, y, link, base_address, data, - n_bytes=None, offset=0, cpu=0): - """ - Write to the memory of a neighbouring chip using a LINK_READ SCP - command. If sent to a BMP, this command can be used to communicate - with the FPGAs' debug registers. - - .. warning:: - This method is deprecated and untested due to no known use. - - :param int x: - The x-coordinate of the chip whose neighbour is to be written to - :param int y: - The y-coordinate of the chip whose neighbour is to be written to - :param int link: - The link index to send the request to (or if BMP, the FPGA number) - :param int base_address: - The address in SDRAM where the region of memory is to be written - :param data: The data to write. Should be one of the following: - - * An instance of RawIOBase - * A bytearray/bytes - * A single integer; will be written in little-endian byte order - :type data: - ~io.RawIOBase or bytes or bytearray or int - :param int n_bytes: - The amount of data to be written in bytes. If not specified: - - * If `data` is an RawIOBase, an error is raised - * If `data` is a bytearray, the length of the bytearray will be - used - * If `data` is an int, 4 will be used - :param int offset: - The offset where the valid data starts (if `data` is - an int then offset will be ignored and used 0) - :param int cpu: - The CPU to use, typically 0 (or if a BMP, the slot number) - :raise SpinnmanIOException: - * If there is an error communicating with the board - * If there is an error reading the data - :raise SpinnmanInvalidPacketException: - If a packet is received that is not in the valid format - :raise SpinnmanInvalidParameterException: - * If `x, y` does not lead to a valid chip - * If a packet is received that has invalid parameters - * If `base_address` is not a positive integer - * If `data` is an RawIOBase but `n_bytes` is not specified - * If `data` is an int and `n_bytes` is more than 4 - * If `n_bytes` is less than 0 - :raise SpinnmanUnexpectedResponseCodeException: - If a response indicates an error during the exchange - """ - warn_once(logger, "The write_neighbour_memory method is deprecated " - "and untested due to no known use.") - process = WriteMemoryProcess(self._scamp_connection_selector) - if isinstance(data, io.RawIOBase): - process.write_link_memory_from_reader( - x, y, cpu, link, base_address, data, n_bytes) - elif isinstance(data, int): - data_to_write = _ONE_WORD.pack(data) - process.write_link_memory_from_bytearray( - x, y, cpu, link, base_address, data_to_write, 0, 4) - else: - if n_bytes is None: - n_bytes = len(data) - process.write_link_memory_from_bytearray( - x, y, cpu, link, base_address, data, offset, n_bytes) - def write_memory_flood( self, base_address, data, n_bytes=None, offset=0, is_filename=False): @@ -1854,50 +1538,6 @@ def read_word(self, x, y, base_address, cpu=0): logger.info(self.__where_is_xy(x, y)) raise - def read_neighbour_memory(self, x, y, link, base_address, length, cpu=0): - """ - Read some areas of memory on a neighbouring chip using a LINK_READ - SCP command. If sent to a BMP, this command can be used to - communicate with the FPGAs' debug registers. - - .. warning:: - This method is currently deprecated and untested as there is no - known use. Same functionality provided by ybug and bmpc. - Retained in case needed for hardware debugging. - - :param int x: - The x-coordinate of the chip whose neighbour is to be read from - :param int y: - The y-coordinate of the chip whose neighbour is to be read from - :param int cpu: - The CPU to use, typically 0 (or if a BMP, the slot number) - :param int link: - The link index to send the request to (or if BMP, the FPGA number) - :param int base_address: - The address in SDRAM where the region of memory to be read starts - :param int length: The length of the data to be read in bytes - :return: An iterable of chunks of data read in order - :rtype: bytes - :raise SpinnmanIOException: - If there is an error communicating with the board - :raise SpinnmanInvalidPacketException: - If a packet is received that is not in the valid format - :raise SpinnmanInvalidParameterException: - * If one of `x`, `y`, `cpu`, `base_address` or `length` is invalid - * If a packet is received that has invalid parameters - :raise SpinnmanUnexpectedResponseCodeException: - If a response indicates an error during the exchange - """ - try: - warn_once(logger, "The read_neighbour_memory method is deprecated " - "and untested due to no known use.") - process = ReadMemoryProcess(self._scamp_connection_selector) - return process.read_link_memory( - x, y, cpu, link, base_address, length) - except Exception: - logger.info(self.__where_is_xy(x, y)) - raise - def stop_application(self, app_id): """ Sends a stop request for an app_id. @@ -2057,37 +1697,6 @@ def send_signal(self, app_id, signal): process = SendSingleCommandProcess(self._scamp_connection_selector) process.execute(SendSignal(app_id, signal)) - def set_leds(self, x, y, cpu, led_states): - """ - Set LED states. - - .. warning:: - The set_leds is deprecated and untested due to no known use. - - :param int x: The x-coordinate of the chip on which to set the LEDs - :param int y: The x-coordinate of the chip on which to set the LEDs - :param int cpu: The CPU of the chip on which to set the LEDs - :param dict(int,int) led_states: - A dictionary mapping SetLED index to state with - 0 being off, 1 on and 2 inverted. - :raise SpinnmanIOException: - If there is an error communicating with the board - :raise SpinnmanInvalidPacketException: - If a packet is received that is not in the valid format - :raise SpinnmanInvalidParameterException: - If a packet is received that has invalid parameters - :raise SpinnmanUnexpectedResponseCodeException: - If a response indicates an error during the exchange - """ - try: - warn_once(logger, "The set_leds is deprecated and " - "untested due to no known use.") - process = SendSingleCommandProcess(self._scamp_connection_selector) - process.execute(SetLED(x, y, cpu, led_states)) - except Exception: - logger.info(self.__where_is_xy(x, y)) - raise - def locate_spinnaker_connection_for_board_address(self, board_address): """ Find a connection that matches the given board IP address. @@ -2298,52 +1907,6 @@ def malloc_sdram(self, x, y, size, app_id, tag=None): logger.info(self.__where_is_xy(x, y)) raise - def free_sdram(self, x, y, base_address, app_id): - """ - Free allocated SDRAM. - - .. warning:: - This method is currently deprecated and likely to be removed. - - :param int x: The x-coordinate of the chip onto which to ask for memory - :param int y: The y-coordinate of the chip onto which to ask for memory - :param int base_address: The base address of the allocated memory - :param int app_id: The app ID of the allocated memory - """ - try: - warn_once(logger, "The free_sdram method is deprecated and " - "likely to be removed.") - process = DeAllocSDRAMProcess(self._scamp_connection_selector) - process.de_alloc_sdram(x, y, app_id, base_address) - except Exception: - logger.info(self.__where_is_xy(x, y)) - raise - - def free_sdram_by_app_id(self, x, y, app_id): - """ - Free all SDRAM allocated to a given app ID. - - .. warning:: - This method is currently deprecated and untested as there is no - known use. Same functionality provided by ybug and bmpc. - Retained in case needed for hardware debugging. - - :param int x: The x-coordinate of the chip onto which to ask for memory - :param int y: The y-coordinate of the chip onto which to ask for memory - :param int app_id: The app ID of the allocated memory - :return: The number of blocks freed - :rtype: int - """ - try: - warn_once(logger, "The free_sdram_by_app_id method is deprecated " - "and untested due to no known use.") - process = DeAllocSDRAMProcess(self._scamp_connection_selector) - process.de_alloc_sdram(x, y, app_id) - return process.no_blocks_freed - except Exception: - logger.info(self.__where_is_xy(x, y)) - raise - def load_multicast_routes(self, x, y, routes, app_id): """ Load a set of multicast routes on to a chip. @@ -2564,47 +2127,6 @@ def __set_router_diagnostic_filter( process.execute(WriteMemory( x, y, memory_position, _ONE_WORD.pack(data_to_send))) - def get_router_diagnostic_filter(self, x, y, position): - """ - Gets a router diagnostic filter from a router. - - :param int x: - the X address of the router from which this filter is being - retrieved - :param int y: - the Y address of the router from which this filter is being - retrieved - :param int position: - the position in the list of filters to read the information from - :return: The diagnostic filter read - :rtype: DiagnosticFilter - :raise SpinnmanIOException: - * If there is an error communicating with the board - * If there is an error reading the data - :raise SpinnmanInvalidPacketException: - If a packet is received that is not in the valid format - :raise SpinnmanInvalidParameterException: - * If x, y does not lead to a valid chip - * If a packet is received that has invalid parameters - * If position is less than 0 or more than 15 - :raise SpinnmanUnexpectedResponseCodeException: - If a response indicates an error during the exchange - """ - try: - memory_position = ( - ROUTER_REGISTER_BASE_ADDRESS + ROUTER_FILTER_CONTROLS_OFFSET + - position * ROUTER_DIAGNOSTIC_FILTER_SIZE) - - process = SendSingleCommandProcess( - self._scamp_connection_selector) - response = process.execute(ReadMemory(x, y, memory_position, 4)) - return DiagnosticFilter.read_from_int(_ONE_WORD.unpack_from( - response.data, response.offset)[0]) - # pylint: disable=no-member - except Exception: - logger.info(self.__where_is_xy(x, y)) - raise - def clear_router_diagnostic_counters(self, x, y): """ Clear router diagnostic information on a chip. @@ -2630,25 +2152,6 @@ def clear_router_diagnostic_counters(self, x, y): logger.info(self.__where_is_xy(x, y)) raise - @property - def number_of_boards_located(self): - """ - The number of boards currently configured. - - .. warning:: - This property is currently deprecated and likely to be removed. - - :rtype: int - """ - warn_once(logger, "The number_of_boards_located method is deprecated " - "and likely to be removed.") - boards = 0 - for bmp_connection in self._bmp_connections: - boards += len(bmp_connection.boards) - - # if no BMPs are available, then there's still at least one board - return max(1, boards) - def close(self): """ Close the transceiver and any threads that are running. diff --git a/unittests/test_transceiver.py b/unittests/test_transceiver.py index 0aa55c7f1..a6c1f3b9d 100644 --- a/unittests/test_transceiver.py +++ b/unittests/test_transceiver.py @@ -18,6 +18,7 @@ from spinn_machine import virtual_machine from spinnman.config_setup import unittest_setup from spinnman.data.spinnman_data_writer import SpiNNManDataWriter +from spinnman.extended.extended_transceiver import ExtendedTransceiver from spinnman.transceiver import Transceiver from spinnman import constants from spinnman.messages.spinnaker_boot.system_variable_boot_values import ( @@ -25,6 +26,7 @@ from spinnman.connections.udp_packet_connections import ( BootConnection, SCAMPConnection) import spinnman.transceiver as transceiver +import spinnman.extended.extended_transceiver as extended from spinnman.board_test_configuration import BoardTestConfiguration board_config = BoardTestConfiguration() @@ -55,6 +57,10 @@ def close(self): pass +class MockExtendedTransceiver(MockWriteTransceiver, ExtendedTransceiver): + pass + + class TestTransceiver(unittest.TestCase): def setUp(self): @@ -74,7 +80,8 @@ def test_create_new_transceiver_one_connection(self): connections = set() connections.add(SCAMPConnection( remote_host=board_config.remotehost)) - with transceiver.Transceiver(ver, connections=connections) as trans: + with extended.ExtendedTransceiver( + ver, connections=connections) as trans: assert trans.get_connections() == connections def test_create_new_transceiver_from_list_connections(self): @@ -126,7 +133,7 @@ def test_boot_board(self): def test_set_watch_dog(self): connections = [] connections.append(SCAMPConnection(remote_host=None)) - tx = MockWriteTransceiver(version=5, connections=connections) + tx = MockExtendedTransceiver(version=5, connections=connections) SpiNNManDataWriter.mock().set_machine(tx.get_machine_details()) # All chips tx.set_watch_dog(True) From 44a58e4e92eca12e0b6bf708d9d4223ea9eee514 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 12:28:35 +0100 Subject: [PATCH 2/9] move Classes only used by ExtendedTranceiver --- spinnman/extended/__init__.py | 23 ++- .../scp/impl => extended}/bmp_set_led.py | 2 +- .../de_alloc_sdram_process.py | 2 +- spinnman/extended/extended_transceiver.py | 138 ++++++++++++------ .../scp/impl => extended}/read_adc.py | 0 .../scp/impl => extended}/set_led.py | 2 +- .../write_memory_flood_process.py | 2 +- spinnman/messages/scp/impl/__init__.py | 11 +- spinnman/processes/__init__.py | 6 +- spinnman/transceiver.py | 103 ++----------- 10 files changed, 136 insertions(+), 153 deletions(-) rename spinnman/{messages/scp/impl => extended}/bmp_set_led.py (96%) rename spinnman/{processes => extended}/de_alloc_sdram_process.py (95%) rename spinnman/{messages/scp/impl => extended}/read_adc.py (100%) rename spinnman/{messages/scp/impl => extended}/set_led.py (96%) rename spinnman/{processes => extended}/write_memory_flood_process.py (97%) diff --git a/spinnman/extended/__init__.py b/spinnman/extended/__init__.py index 8a28c5495..2cb63a7f3 100644 --- a/spinnman/extended/__init__.py +++ b/spinnman/extended/__init__.py @@ -1 +1,22 @@ -from .de_alloc_sdram_process import DeAllocSDRAMProcess \ No newline at end of file +# Copyright (c) 2023 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from .bmp_set_led import BMPSetLed +from .de_alloc_sdram_process import DeAllocSDRAMProcess +from .read_adc import ReadADC +from .set_led import SetLED +from .write_memory_flood_process import WriteMemoryFloodProcess + +__all__ = ["BMPSetLed", "DeAllocSDRAMProcess", "ReadADC", "SetLED", + "WriteMemoryFloodProcess"] diff --git a/spinnman/messages/scp/impl/bmp_set_led.py b/spinnman/extended/bmp_set_led.py similarity index 96% rename from spinnman/messages/scp/impl/bmp_set_led.py rename to spinnman/extended/bmp_set_led.py index c40c98225..c76f2d220 100644 --- a/spinnman/messages/scp/impl/bmp_set_led.py +++ b/spinnman/extended/bmp_set_led.py @@ -17,7 +17,7 @@ from spinnman.messages.scp.abstract_messages import ( AbstractSCPRequest, BMPRequest) from spinnman.messages.scp.enums import SCPCommand -from .check_ok_response import CheckOKResponse +from spinnman.messages.scp.impl.check_ok_response import CheckOKResponse class BMPSetLed(BMPRequest): diff --git a/spinnman/processes/de_alloc_sdram_process.py b/spinnman/extended/de_alloc_sdram_process.py similarity index 95% rename from spinnman/processes/de_alloc_sdram_process.py rename to spinnman/extended/de_alloc_sdram_process.py index 53b100828..6b6d6d08d 100644 --- a/spinnman/processes/de_alloc_sdram_process.py +++ b/spinnman/extended/de_alloc_sdram_process.py @@ -14,7 +14,7 @@ # limitations under the License. from spinnman.messages.scp.impl import SDRAMDeAlloc -from .abstract_multi_connection_process import AbstractMultiConnectionProcess +from spinnman.processes.abstract_multi_connection_process import AbstractMultiConnectionProcess class DeAllocSDRAMProcess(AbstractMultiConnectionProcess): diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index 5cbe6a7c4..e75eb576d 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -14,63 +14,32 @@ # pylint: disable=too-many-arguments import io -import os -import random import struct -from threading import Condition, RLock -from collections import defaultdict -from contextlib import contextmanager, suppress import logging -import socket import time -from spinn_utilities.config_holder import get_config_bool from spinn_utilities.log import FormatAdapter from spinn_utilities.logger_utils import warn_once from spinn_machine import CoreSubsets from spinnman.transceiver import Transceiver -from spinnman.constants import ( - BMP_POST_POWER_ON_SLEEP_TIME, BMP_POWER_ON_TIMEOUT, BMP_TIMEOUT, - CPU_MAX_USER, CPU_USER_OFFSET, CPU_USER_START_ADDRESS, - IPTAG_TIME_OUT_WAIT_TIMES, SCP_SCAMP_PORT, SYSTEM_VARIABLE_BASE_ADDRESS, - UDP_BOOT_CONNECTION_DEFAULT_PORT, NO_ROUTER_DIAGNOSTIC_FILTERS, - ROUTER_REGISTER_BASE_ADDRESS, ROUTER_DEFAULT_FILTERS_MAX_POSITION, - ROUTER_FILTER_CONTROLS_OFFSET, ROUTER_DIAGNOSTIC_FILTER_SIZE, N_RETRIES, - BOOT_RETRIES) +from spinnman.constants import (ROUTER_REGISTER_BASE_ADDRESS, + ROUTER_FILTER_CONTROLS_OFFSET, ROUTER_DIAGNOSTIC_FILTER_SIZE) from spinnman.data import SpiNNManDataView -from spinnman.exceptions import ( - SpinnmanInvalidParameterException, SpinnmanException, SpinnmanIOException, - SpinnmanTimeoutException, SpinnmanGenericProcessException, - SpinnmanUnexpectedResponseCodeException, - SpiNNManCoresNotInStateException) -from spinnman.model import DiagnosticFilter, MachineDimensions -from spinnman.model.enums import ( - CPUState, SDP_PORTS, SDP_RUNNING_MESSAGE_CODES) +from spinnman.exceptions import SpinnmanException +from spinnman.extended import ( + BMPSetLed, DeAllocSDRAMProcess, ReadADC, SetLED, WriteMemoryFloodProcess) +from spinnman.model import DiagnosticFilter +from spinnman.model.enums import CPUState from spinnman.messages.scp.enums import Signal -from spinnman.messages.scp.impl.get_chip_info import GetChipInfo -from spinnman.messages.sdp import SDPFlag, SDPHeader, SDPMessage -from spinnman.messages.spinnaker_boot import ( - SystemVariableDefinition, SpinnakerBootMessages) -from spinnman.messages.scp.enums import PowerCommand from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.messages.scp.impl import ( - BMPSetLed, BMPGetVersion, SetPower, ReadADC, ReadFPGARegister, - WriteFPGARegister, IPTagSetTTO, ReverseIPTagSet, ReadMemory, - CountState, WriteMemory, SetLED, ApplicationRun, SendSignal, AppStop, - IPTagSet, IPTagClear, RouterClear, DoSync) + ReadMemory, ApplicationRun) from spinnman.connections.udp_packet_connections import ( BMPConnection, BootConnection, SCAMPConnection) from spinnman.processes import ( - DeAllocSDRAMProcess, GetMachineProcess, GetVersionProcess, - MallocSDRAMProcess, WriteMemoryProcess, ReadMemoryProcess, - GetCPUInfoProcess, GetExcludeCPUInfoProcess, GetIncludeCPUInfoProcess, - ReadIOBufProcess, ApplicationRunProcess, GetHeapProcess, - LoadFixedRouteRoutingEntryProcess, FixedConnectionSelector, - ReadFixedRouteRoutingEntryProcess, WriteMemoryFloodProcess, - LoadMultiCastRoutesProcess, GetTagsProcess, GetMultiCastRoutesProcess, - SendSingleCommandProcess, ReadRouterDiagnosticsProcess, - MostDirectConnectionSelector, ApplicationCopyRunProcess) + GetHeapProcess, ReadMemoryProcess, SendSingleCommandProcess, + WriteMemoryProcess) from spinnman.utilities.utility_functions import ( - get_vcpu_address, work_out_bmp_from_machine_details) + work_out_bmp_from_machine_details) logger = FormatAdapter(logging.getLogger(__name__)) @@ -536,6 +505,73 @@ def read_neighbour_memory(self, x, y, link, base_address, length, cpu=0): logger.info(self.__where_is_xy(x, y)) raise + def write_memory_flood( + self, base_address, data, n_bytes=None, offset=0, + is_filename=False): + """ + Write to the SDRAM of all chips. + + :param int base_address: + The address in SDRAM where the region of memory is to be written + :param data: + The data that is to be written. Should be one of the following: + + * An instance of RawIOBase + * A byte-string + * A single integer + * A file name of a file to read (in which case `is_filename` + should be set to True) + :type data: + ~io.RawIOBase or bytes or bytearray or int or str + :param int n_bytes: + The amount of data to be written in bytes. If not specified: + + * If `data` is an RawIOBase, an error is raised + * If `data` is a bytearray or bytes, the length of the bytearray + will be used + * If `data` is an int, 4 will be used + * If `data` is a str, the size of the file will be used + :param int offset: + The offset where the valid data starts; if `data` is + an int, then the offset will be ignored and 0 is used. + :param bool is_filename: + True if `data` should be interpreted as a file name + :raise SpinnmanIOException: + * If there is an error communicating with the board + * If there is an error reading the executable + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + * If one of the specified chips is not valid + * If `app_id` is an invalid application ID + * If a packet is received that has invalid parameters + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + process = WriteMemoryFloodProcess(self._scamp_connection_selector) + # Ensure only one flood fill occurs at any one time + with self._flood_write_lock: + # Start the flood fill + nearest_neighbour_id = self._get_next_nearest_neighbour_id() + if isinstance(data, io.RawIOBase): + process.write_memory_from_reader( + nearest_neighbour_id, base_address, data, n_bytes) + elif isinstance(data, str) and is_filename: + if n_bytes is None: + n_bytes = os.stat(data).st_size + with open(data, "rb") as reader: + process.write_memory_from_reader( + nearest_neighbour_id, base_address, reader, n_bytes) + elif isinstance(data, int): + data_to_write = _ONE_WORD.pack(data) + process.write_memory_from_bytearray( + nearest_neighbour_id, base_address, data_to_write, 0) + else: + if n_bytes is None: + n_bytes = len(data) + process.write_memory_from_bytearray( + nearest_neighbour_id, base_address, data, offset, n_bytes) + def set_leds(self, x, y, cpu, led_states): """ Set LED states. @@ -686,3 +722,21 @@ def bmp_connection(self): warn_once(logger, "The bmp_connection property is deprecated and " "likely to be removed.") return self._bmp_connection_selectors + + def get_heap(self, x, y, heap=SystemVariableDefinition.sdram_heap_address): + """ + Get the contents of the given heap on a given chip. + + :param int x: The x-coordinate of the chip + :param int y: The y-coordinate of the chip + :param SystemVariableDefinition heap: + The SystemVariableDefinition which is the heap to read + :rtype: list(HeapElement) + """ + try: + process = GetHeapProcess(self._scamp_connection_selector) + return process.get_heap((x, y), heap) + except Exception: + logger.info(self.__where_is_xy(x, y)) + raise + diff --git a/spinnman/messages/scp/impl/read_adc.py b/spinnman/extended/read_adc.py similarity index 100% rename from spinnman/messages/scp/impl/read_adc.py rename to spinnman/extended/read_adc.py diff --git a/spinnman/messages/scp/impl/set_led.py b/spinnman/extended/set_led.py similarity index 96% rename from spinnman/messages/scp/impl/set_led.py rename to spinnman/extended/set_led.py index 046be4a47..220ae5695 100644 --- a/spinnman/messages/scp/impl/set_led.py +++ b/spinnman/extended/set_led.py @@ -17,7 +17,7 @@ from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.messages.scp.enums import SCPCommand from spinnman.messages.sdp import SDPFlag, SDPHeader -from .check_ok_response import CheckOKResponse +from spinnman.messages.scp.impl.check_ok_response import CheckOKResponse class SetLED(AbstractSCPRequest): diff --git a/spinnman/processes/write_memory_flood_process.py b/spinnman/extended/write_memory_flood_process.py similarity index 97% rename from spinnman/processes/write_memory_flood_process.py rename to spinnman/extended/write_memory_flood_process.py index fbe3b68b1..d84a8192d 100644 --- a/spinnman/processes/write_memory_flood_process.py +++ b/spinnman/extended/write_memory_flood_process.py @@ -15,7 +15,7 @@ import math from spinnman.messages.scp.impl import ( FloodFillEnd, FloodFillStart, FloodFillData) -from .abstract_multi_connection_process import AbstractMultiConnectionProcess +from spinnman.processes.abstract_multi_connection_process import AbstractMultiConnectionProcess from spinnman.constants import UDP_MESSAGE_MAX_SIZE diff --git a/spinnman/messages/scp/impl/__init__.py b/spinnman/messages/scp/impl/__init__.py index d058b6fe1..05c8fb667 100644 --- a/spinnman/messages/scp/impl/__init__.py +++ b/spinnman/messages/scp/impl/__init__.py @@ -16,7 +16,6 @@ from .app_copy_run import AppCopyRun from .application_run import ApplicationRun from .bmp_get_version import BMPGetVersion -from .bmp_set_led import BMPSetLed from .check_ok_response import CheckOKResponse from .count_state import CountState from .do_sync import DoSync @@ -31,7 +30,6 @@ from .iptag_get_info import IPTagGetInfo from .iptag_set import IPTagSet from .iptag_set_tto import IPTagSetTTO -from .read_adc import ReadADC from .read_fpga_register import ReadFPGARegister from .read_link import ReadLink from .read_memory import ReadMemory @@ -42,7 +40,6 @@ from .sdram_alloc import SDRAMAlloc from .sdram_de_alloc import SDRAMDeAlloc from .send_signal import SendSignal -from .set_led import SetLED from .set_power import SetPower from .write_fpga_register import WriteFPGARegister from .write_link import WriteLink @@ -51,15 +48,13 @@ from .fixed_route_read import FixedRouteRead __all__ = ["AppStop", "ApplicationRun", "AppCopyRun", - "BMPSetLed", "BMPGetVersion", - "CheckOKResponse", "GetChipInfo", "CountState", + "BMPGetVersion", "CheckOKResponse", "GetChipInfo", "CountState", "DoSync", "FloodFillData", "FillRequest", "FloodFillEnd", "FloodFillStart", "IPTagClear", "IPTagGet", "IPTagGetInfo", - "IPTagSet", "IPTagSetTTO", "SetLED", - "SetPower", "ReadADC", - "ReadFPGARegister", "ReadLink", + "IPTagSet", "IPTagSetTTO", + "SetPower", "ReadFPGARegister", "ReadLink", "ReadMemory", "ReverseIPTagSet", "RouterAlloc", "RouterClear", "RouterInit", "SDRAMAlloc", diff --git a/spinnman/processes/__init__.py b/spinnman/processes/__init__.py index cff96694f..3e11e3b14 100644 --- a/spinnman/processes/__init__.py +++ b/spinnman/processes/__init__.py @@ -39,7 +39,6 @@ from .read_router_diagnostics_process import ReadRouterDiagnosticsProcess from .round_robin_connection_selector import RoundRobinConnectionSelector from .send_single_command_process import SendSingleCommandProcess -from .write_memory_flood_process import WriteMemoryFloodProcess from .write_memory_process import WriteMemoryProcess __all__ = ["AbstractMultiConnectionProcessConnectionSelector", @@ -47,7 +46,7 @@ "RoundRobinConnectionSelector", "AbstractMultiConnectionProcess", "ApplicationRunProcess", "ApplicationCopyRunProcess", - "DeAllocSDRAMProcess", "GetCPUInfoProcess", + "GetCPUInfoProcess", "GetExcludeCPUInfoProcess", "GetIncludeCPUInfoProcess", "GetHeapProcess", "GetMachineProcess", "GetMultiCastRoutesProcess", "GetTagsProcess", @@ -55,5 +54,4 @@ "LoadMultiCastRoutesProcess", "MallocSDRAMProcess", "ReadFixedRouteRoutingEntryProcess", "ReadIOBufProcess", "ReadMemoryProcess", "ReadRouterDiagnosticsProcess", - "SendSingleCommandProcess", "WriteMemoryFloodProcess", - "WriteMemoryProcess"] + "SendSingleCommandProcess", "WriteMemoryProcess"] diff --git a/spinnman/transceiver.py b/spinnman/transceiver.py index 16cd2b385..0c5efeaef 100644 --- a/spinnman/transceiver.py +++ b/spinnman/transceiver.py @@ -42,10 +42,9 @@ SpinnmanTimeoutException, SpinnmanGenericProcessException, SpinnmanUnexpectedResponseCodeException, SpiNNManCoresNotInStateException) -from spinnman.model import DiagnosticFilter, MachineDimensions +from spinnman.model import MachineDimensions from spinnman.model.enums import ( CPUState, SDP_PORTS, SDP_RUNNING_MESSAGE_CODES) -from spinnman.messages.scp.enums import Signal from spinnman.messages.scp.impl.get_chip_info import GetChipInfo from spinnman.messages.sdp import SDPFlag, SDPHeader, SDPMessage from spinnman.messages.spinnaker_boot import ( @@ -53,19 +52,19 @@ from spinnman.messages.scp.enums import PowerCommand from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.messages.scp.impl import ( - BMPSetLed, BMPGetVersion, SetPower, ReadADC, ReadFPGARegister, - WriteFPGARegister, IPTagSetTTO, ReverseIPTagSet, ReadMemory, - CountState, WriteMemory, SetLED, ApplicationRun, SendSignal, AppStop, + BMPGetVersion, SetPower, ReadFPGARegister, + WriteFPGARegister, IPTagSetTTO, ReverseIPTagSet, + CountState, WriteMemory, SendSignal, AppStop, IPTagSet, IPTagClear, RouterClear, DoSync) from spinnman.connections.udp_packet_connections import ( BMPConnection, BootConnection, SCAMPConnection) from spinnman.processes import ( - DeAllocSDRAMProcess, GetMachineProcess, GetVersionProcess, + GetMachineProcess, GetVersionProcess, MallocSDRAMProcess, WriteMemoryProcess, ReadMemoryProcess, GetCPUInfoProcess, GetExcludeCPUInfoProcess, GetIncludeCPUInfoProcess, - ReadIOBufProcess, ApplicationRunProcess, GetHeapProcess, + ReadIOBufProcess, ApplicationRunProcess, LoadFixedRouteRoutingEntryProcess, FixedConnectionSelector, - ReadFixedRouteRoutingEntryProcess, WriteMemoryFloodProcess, + ReadFixedRouteRoutingEntryProcess, LoadMultiCastRoutesProcess, GetTagsProcess, GetMultiCastRoutesProcess, SendSingleCommandProcess, ReadRouterDiagnosticsProcess, MostDirectConnectionSelector, ApplicationCopyRunProcess) @@ -1404,73 +1403,6 @@ def write_user(self, x, y, p, user, value): addr = self.__get_user_register_address_from_core(p, user) self.write_memory(x, y, addr, int(value)) - def write_memory_flood( - self, base_address, data, n_bytes=None, offset=0, - is_filename=False): - """ - Write to the SDRAM of all chips. - - :param int base_address: - The address in SDRAM where the region of memory is to be written - :param data: - The data that is to be written. Should be one of the following: - - * An instance of RawIOBase - * A byte-string - * A single integer - * A file name of a file to read (in which case `is_filename` - should be set to True) - :type data: - ~io.RawIOBase or bytes or bytearray or int or str - :param int n_bytes: - The amount of data to be written in bytes. If not specified: - - * If `data` is an RawIOBase, an error is raised - * If `data` is a bytearray or bytes, the length of the bytearray - will be used - * If `data` is an int, 4 will be used - * If `data` is a str, the size of the file will be used - :param int offset: - The offset where the valid data starts; if `data` is - an int, then the offset will be ignored and 0 is used. - :param bool is_filename: - True if `data` should be interpreted as a file name - :raise SpinnmanIOException: - * If there is an error communicating with the board - * If there is an error reading the executable - :raise SpinnmanInvalidPacketException: - If a packet is received that is not in the valid format - :raise SpinnmanInvalidParameterException: - * If one of the specified chips is not valid - * If `app_id` is an invalid application ID - * If a packet is received that has invalid parameters - :raise SpinnmanUnexpectedResponseCodeException: - If a response indicates an error during the exchange - """ - process = WriteMemoryFloodProcess(self._scamp_connection_selector) - # Ensure only one flood fill occurs at any one time - with self._flood_write_lock: - # Start the flood fill - nearest_neighbour_id = self._get_next_nearest_neighbour_id() - if isinstance(data, io.RawIOBase): - process.write_memory_from_reader( - nearest_neighbour_id, base_address, data, n_bytes) - elif isinstance(data, str) and is_filename: - if n_bytes is None: - n_bytes = os.stat(data).st_size - with open(data, "rb") as reader: - process.write_memory_from_reader( - nearest_neighbour_id, base_address, reader, n_bytes) - elif isinstance(data, int): - data_to_write = _ONE_WORD.pack(data) - process.write_memory_from_bytearray( - nearest_neighbour_id, base_address, data_to_write, 0) - else: - if n_bytes is None: - n_bytes = len(data) - process.write_memory_from_bytearray( - nearest_neighbour_id, base_address, data, offset, n_bytes) - def read_memory(self, x, y, base_address, length, cpu=0): """ Read some areas of memory (usually SDRAM) from the board. @@ -1682,7 +1614,7 @@ def send_signal(self, app_id, signal): Send a signal to an application. :param int app_id: The ID of the application to send to - :param Signal signal: The signal to send + :param ~spinnman.messages.scp.enums.Signal signal: The signal to send :raise SpinnmanIOException: If there is an error communicating with the board :raise SpinnmanInvalidPacketException: @@ -2080,7 +2012,7 @@ def set_router_diagnostic_filter(self, x, y, position, diagnostic_filter): :param int position: The position in the list of filters where this filter is to be added. - :param DiagnosticFilter diagnostic_filter: + :param ~spinnman.model.DiagnosticFilter diagnostic_filter: The diagnostic filter being set in the placed, between 0 and 15. .. note:: @@ -2177,23 +2109,6 @@ def bmp_connection(self): "likely to be removed.") return self._bmp_connection_selectors - def get_heap(self, x, y, heap=SystemVariableDefinition.sdram_heap_address): - """ - Get the contents of the given heap on a given chip. - - :param int x: The x-coordinate of the chip - :param int y: The y-coordinate of the chip - :param SystemVariableDefinition heap: - The SystemVariableDefinition which is the heap to read - :rtype: list(HeapElement) - """ - try: - process = GetHeapProcess(self._scamp_connection_selector) - return process.get_heap((x, y), heap) - except Exception: - logger.info(self.__where_is_xy(x, y)) - raise - def control_sync(self, do_sync): """ Control the synchronisation of the chips. From 2d7f5de3c86ee9d1ca82be7b78b02a50b4900ac8 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 12:37:05 +0100 Subject: [PATCH 3/9] missing import --- spinnman/extended/extended_transceiver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index e75eb576d..82bb61577 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -33,6 +33,7 @@ from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.messages.scp.impl import ( ReadMemory, ApplicationRun) +from spinnman.messages.spinnaker_boot import SystemVariableDefinition from spinnman.connections.udp_packet_connections import ( BMPConnection, BootConnection, SCAMPConnection) from spinnman.processes import ( From 2cec186653fa5e8b9909c7f8fa7c7a73f4a74abf Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 12:43:09 +0100 Subject: [PATCH 4/9] flake8 --- spinnman/extended/de_alloc_sdram_process.py | 3 ++- spinnman/extended/extended_transceiver.py | 6 ++++-- spinnman/extended/write_memory_flood_process.py | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/spinnman/extended/de_alloc_sdram_process.py b/spinnman/extended/de_alloc_sdram_process.py index 6b6d6d08d..916a2500d 100644 --- a/spinnman/extended/de_alloc_sdram_process.py +++ b/spinnman/extended/de_alloc_sdram_process.py @@ -14,7 +14,8 @@ # limitations under the License. from spinnman.messages.scp.impl import SDRAMDeAlloc -from spinnman.processes.abstract_multi_connection_process import AbstractMultiConnectionProcess +from spinnman.processes.abstract_multi_connection_process import ( + AbstractMultiConnectionProcess) class DeAllocSDRAMProcess(AbstractMultiConnectionProcess): diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index 82bb61577..b094160cf 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -14,6 +14,7 @@ # pylint: disable=too-many-arguments import io +import os import struct import logging import time @@ -150,7 +151,9 @@ def send_scp_message(self, message, connection=None): """ Sends an SCP message, without expecting a response. - :param AbstractSCPRequest message: The message to send + :param message: The message to send + :type message: + spinnman.messages.scp.abstract_messages.AbstractSCPRequest :param SCAMPConnection connection: The connection to use (omit to pick a random one) :raise SpinnmanTimeoutException: @@ -740,4 +743,3 @@ def get_heap(self, x, y, heap=SystemVariableDefinition.sdram_heap_address): except Exception: logger.info(self.__where_is_xy(x, y)) raise - diff --git a/spinnman/extended/write_memory_flood_process.py b/spinnman/extended/write_memory_flood_process.py index d84a8192d..4ef491bf7 100644 --- a/spinnman/extended/write_memory_flood_process.py +++ b/spinnman/extended/write_memory_flood_process.py @@ -15,7 +15,8 @@ import math from spinnman.messages.scp.impl import ( FloodFillEnd, FloodFillStart, FloodFillData) -from spinnman.processes.abstract_multi_connection_process import AbstractMultiConnectionProcess +from spinnman.processes.abstract_multi_connection_process import ( + AbstractMultiConnectionProcess) from spinnman.constants import UDP_MESSAGE_MAX_SIZE From 161fed8d1fb7d58862dc69d4e88ae068005cdc25 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 12:46:58 +0100 Subject: [PATCH 5/9] more flake8 --- spinnman/extended/extended_transceiver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index b094160cf..cbe8ed624 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -22,8 +22,9 @@ from spinn_utilities.logger_utils import warn_once from spinn_machine import CoreSubsets from spinnman.transceiver import Transceiver -from spinnman.constants import (ROUTER_REGISTER_BASE_ADDRESS, - ROUTER_FILTER_CONTROLS_OFFSET, ROUTER_DIAGNOSTIC_FILTER_SIZE) +from spinnman.constants import ( + ROUTER_REGISTER_BASE_ADDRESS, ROUTER_FILTER_CONTROLS_OFFSET, + ROUTER_DIAGNOSTIC_FILTER_SIZE) from spinnman.data import SpiNNManDataView from spinnman.exceptions import SpinnmanException from spinnman.extended import ( @@ -31,7 +32,6 @@ from spinnman.model import DiagnosticFilter from spinnman.model.enums import CPUState from spinnman.messages.scp.enums import Signal -from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.messages.scp.impl import ( ReadMemory, ApplicationRun) from spinnman.messages.spinnaker_boot import SystemVariableDefinition From 27d755a0999e8c8d89b1f97a1c2d51772b1d59c6 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 13:13:03 +0100 Subject: [PATCH 6/9] move methods only need by extended --- spinnman/extended/extended_transceiver.py | 39 +++++++++++++++++++++++ spinnman/transceiver.py | 38 ---------------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index cbe8ed624..457ac223e 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -13,6 +13,7 @@ # limitations under the License. # pylint: disable=too-many-arguments +from contextlib import contextmanager import io import os import struct @@ -248,6 +249,38 @@ def get_iobuf_from_core(self, x, y, p): core_subsets.add_processor(x, y, p) return next(self.get_iobuf(core_subsets)) + @contextmanager + def _chip_execute_lock(self, x, y): + """ + Get a lock for executing an executable on a chip. + + .. warning:: + This method is currently deprecated and untested as there is no + known use except for execute, which is itself deprecated. + + :param int x: + :param int y: + """ + # Check if there is a lock for the given chip + with self._chip_execute_lock_condition: + chip_lock = self._chip_execute_locks[x, y] + # Acquire the lock for the chip + chip_lock.acquire() + + # Increment the lock counter (used for the flood lock) + with self._chip_execute_lock_condition: + self._n_chip_execute_locks += 1 + + try: + yield chip_lock + finally: + with self._chip_execute_lock_condition: + # Release the chip lock + chip_lock.release() + # Decrement the lock and notify + self._n_chip_execute_locks -= 1 + self._chip_execute_lock_condition.notify_all() + def execute( self, x, y, processors, executable, app_id, n_bytes=None, wait=False, is_filename=False): @@ -509,6 +542,12 @@ def read_neighbour_memory(self, x, y, link, base_address, length, cpu=0): logger.info(self.__where_is_xy(x, y)) raise + def _get_next_nearest_neighbour_id(self): + with self._nearest_neighbour_lock: + next_nearest_neighbour_id = (self._nearest_neighbour_id + 1) % 127 + self._nearest_neighbour_id = next_nearest_neighbour_id + return next_nearest_neighbour_id + def write_memory_flood( self, base_address, data, n_bytes=None, offset=0, is_filename=False): diff --git a/spinnman/transceiver.py b/spinnman/transceiver.py index 0c5efeaef..a4af88183 100644 --- a/spinnman/transceiver.py +++ b/spinnman/transceiver.py @@ -379,38 +379,6 @@ def _check_connection( break return None - @contextmanager - def _chip_execute_lock(self, x, y): - """ - Get a lock for executing an executable on a chip. - - .. warning:: - This method is currently deprecated and untested as there is no - known use except for execute, which is itself deprecated. - - :param int x: - :param int y: - """ - # Check if there is a lock for the given chip - with self._chip_execute_lock_condition: - chip_lock = self._chip_execute_locks[x, y] - # Acquire the lock for the chip - chip_lock.acquire() - - # Increment the lock counter (used for the flood lock) - with self._chip_execute_lock_condition: - self._n_chip_execute_locks += 1 - - try: - yield chip_lock - finally: - with self._chip_execute_lock_condition: - # Release the chip lock - chip_lock.release() - # Decrement the lock and notify - self._n_chip_execute_locks -= 1 - self._chip_execute_lock_condition.notify_all() - @contextmanager def _flood_execute_lock(self): """ @@ -1086,12 +1054,6 @@ def get_core_state_count(self, app_id, state): response = process.execute(CountState(app_id, state)) return response.count # pylint: disable=no-member - def _get_next_nearest_neighbour_id(self): - with self._nearest_neighbour_lock: - next_nearest_neighbour_id = (self._nearest_neighbour_id + 1) % 127 - self._nearest_neighbour_id = next_nearest_neighbour_id - return next_nearest_neighbour_id - def execute_flood( self, core_subsets, executable, app_id, n_bytes=None, wait=False, is_filename=False): From 2001bb8295791a7e55bfae682f1886e3eadde7dc Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 13:35:50 +0100 Subject: [PATCH 7/9] move slots only used in Extended --- spinnman/extended/extended_transceiver.py | 67 ++++++++++++++++++++++- spinnman/transceiver.py | 46 +--------------- 2 files changed, 66 insertions(+), 47 deletions(-) diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index 457ac223e..1a14108a4 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -18,10 +18,12 @@ import os import struct import logging +from threading import Condition, RLock import time from spinn_utilities.log import FormatAdapter from spinn_utilities.logger_utils import warn_once from spinn_machine import CoreSubsets +from spinnman.constants import SYSTEM_VARIABLE_BASE_ADDRESS from spinnman.transceiver import Transceiver from spinnman.constants import ( ROUTER_REGISTER_BASE_ADDRESS, ROUTER_FILTER_CONTROLS_OFFSET, @@ -146,7 +148,35 @@ class ExtendedTransceiver(Transceiver): the multiple calls may be made separately over the set of given connections. """ - __slots__ = [] + __slots__ = ["_flood_write_lock", "_nearest_neighbour_id", + "_nearest_neighbour_lock"] + + def __init__(self, version, connections=None): + """ + :param int version: The version of the board being connected to + :param list(Connection) connections: + An iterable of connections to the board. If not specified, no + communication will be possible until connections are found. + :raise SpinnmanIOException: + If there is an error communicating with the board, or if no + connections to the board can be found (if connections is ``None``) + :raise SpinnmanInvalidPacketException: + If a packet is received that is not in the valid format + :raise SpinnmanInvalidParameterException: + If a packet is received that has invalid parameters + :raise SpinnmanUnexpectedResponseCodeException: + If a response indicates an error during the exchange + """ + super().__init__(version, connections) + + # A lock against multiple flood fill writes - needed as SCAMP cannot + # cope with this + self._flood_write_lock = Condition() + + + # The nearest neighbour start ID and lock + self._nearest_neighbour_id = 1 + self._nearest_neighbour_lock = RLock() def send_scp_message(self, message, connection=None): """ @@ -201,6 +231,39 @@ def is_connected(self, connection=None): return connection.is_connected() return any(c.is_connected() for c in self._scamp_connections) + def __set_watch_dog_on_chip(self, x, y, watch_dog): + """ + Enable, disable or set the value of the watch dog timer on a + specific chip. + + .. warning:: + This method is currently deprecated and untested as there is no + known use. Same functionality provided by ybug and bmpc. + Retained in case needed for hardware debugging. + + :param int x: chip X coordinate to write new watchdog parameter to + :param int y: chip Y coordinate to write new watchdog parameter to + :param watch_dog: + Either a boolean indicating whether to enable (True) or + disable (False) the watchdog timer, or an int value to set the + timer count to + :type watch_dog: bool or int + """ + # build what we expect it to be + warn_once(logger, "The set_watch_dog_on_chip method is deprecated " + "and untested due to no known use.") + value_to_set = watch_dog + watchdog = SystemVariableDefinition.software_watchdog_count + if isinstance(watch_dog, bool): + value_to_set = watchdog.default if watch_dog else 0 + + # build data holder + data = _ONE_BYTE.pack(value_to_set) + + # write data + address = SYSTEM_VARIABLE_BASE_ADDRESS + watchdog.offset + self.write_memory(x=x, y=y, base_address=address, data=data) + def set_watch_dog(self, watch_dog): """ Enable, disable or set the value of the watch dog timer. @@ -219,7 +282,7 @@ def set_watch_dog(self, watch_dog): warn_once(logger, "The set_watch_dog method is deprecated and " "untested due to no known use.") for x, y in SpiNNManDataView.get_machine().chip_coordinates: - self.set_watch_dog_on_chip(x, y, watch_dog) + self.__set_watch_dog_on_chip(x, y, watch_dog) def get_iobuf_from_core(self, x, y, p): """ diff --git a/spinnman/transceiver.py b/spinnman/transceiver.py index a4af88183..3e410781a 100644 --- a/spinnman/transceiver.py +++ b/spinnman/transceiver.py @@ -17,7 +17,7 @@ import os import random import struct -from threading import Condition, RLock +from threading import Condition from collections import defaultdict from contextlib import contextmanager, suppress import logging @@ -180,13 +180,10 @@ class Transceiver(AbstractContextManager): "_boot_send_connection", "_chip_execute_lock_condition", "_chip_execute_locks", - "_flood_write_lock", "_height", "_iobuf_size", "_machine_off", "_n_chip_execute_locks", - "_nearest_neighbour_id", - "_nearest_neighbour_lock", "_scamp_connection_selector", "_scamp_connections", "_udp_scamp_connections", @@ -245,14 +242,6 @@ def __init__( self._scamp_connection_selector = \ self._identify_connections(connections) - # The nearest neighbour start ID and lock - self._nearest_neighbour_id = 1 - self._nearest_neighbour_lock = RLock() - - # A lock against multiple flood fill writes - needed as SCAMP cannot - # cope with this - self._flood_write_lock = Condition() - # A lock against single chip executions (entry is (x, y)) # The condition should be acquired before the locks are # checked or updated @@ -997,39 +986,6 @@ def get_iobuf(self, core_subsets=None): process = ReadIOBufProcess(self._scamp_connection_selector) return process.read_iobuf(self._iobuf_size, core_subsets) - def set_watch_dog_on_chip(self, x, y, watch_dog): - """ - Enable, disable or set the value of the watch dog timer on a - specific chip. - - .. warning:: - This method is currently deprecated and untested as there is no - known use. Same functionality provided by ybug and bmpc. - Retained in case needed for hardware debugging. - - :param int x: chip X coordinate to write new watchdog parameter to - :param int y: chip Y coordinate to write new watchdog parameter to - :param watch_dog: - Either a boolean indicating whether to enable (True) or - disable (False) the watchdog timer, or an int value to set the - timer count to - :type watch_dog: bool or int - """ - # build what we expect it to be - warn_once(logger, "The set_watch_dog_on_chip method is deprecated " - "and untested due to no known use.") - value_to_set = watch_dog - WATCHDOG = SystemVariableDefinition.software_watchdog_count - if isinstance(watch_dog, bool): - value_to_set = WATCHDOG.default if watch_dog else 0 - - # build data holder - data = _ONE_BYTE.pack(value_to_set) - - # write data - address = SYSTEM_VARIABLE_BASE_ADDRESS + WATCHDOG.offset - self.write_memory(x=x, y=y, base_address=address, data=data) - def get_core_state_count(self, app_id, state): """ Get a count of the number of cores which have a given state. From 2d316506a493ef12fbe5d0e7e289039a33575fdf Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 28 Jul 2023 14:02:13 +0100 Subject: [PATCH 8/9] use Transciver constants --- spinnman/extended/extended_transceiver.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index 1a14108a4..09edde82b 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -16,7 +16,6 @@ from contextlib import contextmanager import io import os -import struct import logging from threading import Condition, RLock import time @@ -43,27 +42,12 @@ from spinnman.processes import ( GetHeapProcess, ReadMemoryProcess, SendSingleCommandProcess, WriteMemoryProcess) +from spinnman.transceiver import _EXECUTABLE_ADDRESS, _ONE_BYTE, _ONE_WORD from spinnman.utilities.utility_functions import ( work_out_bmp_from_machine_details) logger = FormatAdapter(logging.getLogger(__name__)) -_SCAMP_NAME = "SC&MP" -_SCAMP_VERSION = (3, 0, 1) - -_BMP_NAME = "BC&MP" -_BMP_MAJOR_VERSIONS = [1, 2] - -_CONNECTION_CHECK_RETRIES = 3 -INITIAL_FIND_SCAMP_RETRIES_COUNT = 3 - -_ONE_BYTE = struct.Struct("B") -_TWO_BYTES = struct.Struct(" Date: Fri, 28 Jul 2023 14:07:47 +0100 Subject: [PATCH 9/9] flake8 --- spinnman/extended/extended_transceiver.py | 1 - 1 file changed, 1 deletion(-) diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index 09edde82b..44b8178c3 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -157,7 +157,6 @@ def __init__(self, version, connections=None): # cope with this self._flood_write_lock = Condition() - # The nearest neighbour start ID and lock self._nearest_neighbour_id = 1 self._nearest_neighbour_lock = RLock()