From 4dd9b5f60b091da217bcafceeeaf2d5875197bfa Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 12 Jul 2023 13:10:17 +0100 Subject: [PATCH 01/24] get n_cores from Version classes --- spinn_machine/data/machine_data_view.py | 18 ++++++ spinn_machine/full_wrap_machine.py | 5 +- spinn_machine/machine.py | 38 ------------ spinn_machine/no_wrap_machine.py | 3 +- spinn_machine/spinn_machine.cfg | 4 ++ spinn_machine/version/__init__.py | 17 ++++++ spinn_machine/version/abstract_version.py | 70 +++++++++++++++++++++++ spinn_machine/version/version_3.py | 32 +++++++++++ spinn_machine/version/version_5.py | 32 +++++++++++ spinn_machine/version/version_factory.py | 38 ++++++++++++ spinn_machine/version/version_spin1.py | 28 +++++++++ unittests/test_machine.py | 15 ----- unittests/version/__init__.py | 13 +++++ unittests/version/test_version5.py | 36 ++++++++++++ 14 files changed, 294 insertions(+), 55 deletions(-) create mode 100644 spinn_machine/version/__init__.py create mode 100644 spinn_machine/version/abstract_version.py create mode 100644 spinn_machine/version/version_3.py create mode 100644 spinn_machine/version/version_5.py create mode 100644 spinn_machine/version/version_factory.py create mode 100644 spinn_machine/version/version_spin1.py create mode 100644 unittests/version/__init__.py create mode 100644 unittests/version/test_version5.py diff --git a/spinn_machine/data/machine_data_view.py b/spinn_machine/data/machine_data_view.py index 13acc81e..f1f6f47e 100644 --- a/spinn_machine/data/machine_data_view.py +++ b/spinn_machine/data/machine_data_view.py @@ -13,6 +13,7 @@ # limitations under the License. from spinn_utilities.data import UtilsDataView +from spinn_machine.version import version_factory # pylint: disable=protected-access @@ -37,6 +38,7 @@ class _MachineDataModel(object): # Data values cached "_machine", "_machine_generator", + "_machine_version", "_user_accessed_machine" ] @@ -55,6 +57,7 @@ def _clear(self): """ self._hard_reset() self._machine_generator = None + self._machine_version = None def _hard_reset(self): """ @@ -217,3 +220,18 @@ def where_is_chip(cls, chip): if cls.__data._machine is None: return "Chip is from a previous machine" return str(ex) + + @classmethod + def get_machine_version(cls): + """ + Returns the Machine Version if it has or can be set. + +` May call version_factory to create the version + + :return: A superclass of AbstractVersion + :rtype: ~spinn_machine.version.abstract_version.py + :raises SpinnMachineException: If the cfg version is not set correctly + """ + if cls.__data._machine_version is None: + cls.__data._machine_version = version_factory() + return cls.__data._machine_version diff --git a/spinn_machine/full_wrap_machine.py b/spinn_machine/full_wrap_machine.py index e95a2c08..d0dfa3fa 100644 --- a/spinn_machine/full_wrap_machine.py +++ b/spinn_machine/full_wrap_machine.py @@ -13,6 +13,7 @@ # limitations under the License. from spinn_utilities.overrides import overrides +from spinn_machine.data import MachineDataView from .machine import Machine @@ -32,7 +33,9 @@ def get_xys_by_ethernet(self, ethernet_x, ethernet_y): @overrides(Machine.get_xy_cores_by_ethernet) def get_xy_cores_by_ethernet(self, ethernet_x, ethernet_y): if (self._width == self._height == 2): - n_cores = Machine.max_cores_per_chip() + version = MachineDataView.get_machine_version() + n_cores = version.max_cores_per_chip + n_cores = MachineDataView.get_machine_version().max_cores_per_chip for (x, y) in self._local_xys: # if ethernet_x/y != 0 GIGO mode so ignore ethernet yield (x, y), n_cores diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index c4fde88f..9d5f8f38 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -40,7 +40,6 @@ class Machine(object, metaclass=AbstractBase): # current opinions is that the Ethernet connected chip can handle 10 # UDP packets per millisecond - DEFAULT_MAX_CORES_PER_CHIP = 18 NON_USER_CORES = 1 DEFAULT_SDRAM_BYTES = 123469792 __max_cores = None @@ -86,43 +85,6 @@ class Machine(object, metaclass=AbstractBase): "_width" ) - @staticmethod - def max_cores_per_chip(): - """ - Gets the max core per chip for the while system. - - There is no guarantee that there will be any Chips with this many - cores, only that there will be no cores with more. - - :return: the default cores per chip unless overridden by set - """ - if Machine.__max_cores is None: - Machine.__max_cores = Machine.DEFAULT_MAX_CORES_PER_CHIP - return Machine.__max_cores - - @staticmethod - def set_max_cores_per_chip(new_max): - """ - Allows setting the max number of cores per chip for the whole system. - - Allows virtual machines to go higher than normal. - - Real machines can only be capped never increased beyond what they - actually have. - - :param int new_max: New value to use for the max - :raises SpinnMachineException: if `max_cores_per_chip` has already been - used and is now being changed. - This exception also happens if the value is set twice to different - values. For example in the script and in the configuration file. - """ - if Machine.__max_cores is None: - Machine.__max_cores = new_max - elif Machine.__max_cores != new_max: - raise SpinnMachineException( - "max_cores_per_chip has already been accessed " - "so can not be changed.") - def __init__(self, width, height, chips=None, origin=None): """ :param int width: The width of the machine excluding diff --git a/spinn_machine/no_wrap_machine.py b/spinn_machine/no_wrap_machine.py index 7546e381..e1f6e966 100644 --- a/spinn_machine/no_wrap_machine.py +++ b/spinn_machine/no_wrap_machine.py @@ -14,6 +14,7 @@ from .machine import Machine from spinn_utilities.overrides import overrides +from spinn_machine.data import MachineDataView class NoWrapMachine(Machine): @@ -36,7 +37,7 @@ def get_xy_cores_by_ethernet(self, ethernet_x, ethernet_y): yield ((x + ethernet_x, y + ethernet_y), n_cores) else: # covers weird sizes - n_cores = Machine.max_cores_per_chip() + n_cores = MachineDataView.get_machine_version().max_cores_per_chip for (x, y) in self._local_xys: yield ((x, y), n_cores) diff --git a/spinn_machine/spinn_machine.cfg b/spinn_machine/spinn_machine.cfg index 55e3db54..e1f99881 100644 --- a/spinn_machine/spinn_machine.cfg +++ b/spinn_machine/spinn_machine.cfg @@ -32,3 +32,7 @@ repair_machine = False down_cores = None down_chips = None down_links = None + +# Allows the setting of max number of cores per chip +# Set to None to use the default value. +max_machine_core = None \ No newline at end of file diff --git a/spinn_machine/version/__init__.py b/spinn_machine/version/__init__.py new file mode 100644 index 00000000..0c88d8bb --- /dev/null +++ b/spinn_machine/version/__init__.py @@ -0,0 +1,17 @@ +# 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 .version_factory import version_factory + +__all__ = ["version_factory"] diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py new file mode 100644 index 00000000..a7aa1314 --- /dev/null +++ b/spinn_machine/version/abstract_version.py @@ -0,0 +1,70 @@ +# 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. + +import logging +from spinn_utilities.abstract_base import ( + AbstractBase, abstractproperty, abstractmethod) +from spinn_utilities.log import FormatAdapter +from spinn_utilities.config_holder import ( + config_options, load_config, get_config_bool, get_config_int, + get_config_str, get_config_str_list, set_config) + +logger = FormatAdapter(logging.getLogger(__name__)) + + +class AbstractVersion(object, metaclass=AbstractBase): + """ + Properties for sa spec + """ + + __slots__ = [ + # the board address associated with this tag + "_max_cores_per_chip", + ] + + def __init__(self, max_cores_per_chip): + self._max_cores_per_chip = max_cores_per_chip + max_machine_core = get_config_int("Machine", "max_machine_core") + if max_machine_core is not None: + if max_machine_core > self._max_cores_per_chip: + logger.info( + f"Ignoring csg setting [Machine]max_machine_core " + f"{max_machine_core} as it is larger than " + f"{self._max_cores_per_chip} which is the default for a " + f"{self.name} board ") + if max_machine_core < self._max_cores_per_chip: + logger.warning( + f"Max cores per chip reduced to {max_machine_core} " + f"due to cfg setting [Machine]max_machine_core") + self._max_cores_per_chip = max_machine_core + + @abstractproperty + def name(self): + """ + The name of the Specific version + + :rtype: str + """ + + @property + def max_cores_per_chip(self): + """ + Gets the max core per chip for the whole system. + + There is no guarantee that there will be any Chips with this many + cores, only that there will be no cores with more. + + :return: the default cores per chip + """ + return self._max_cores_per_chip diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py new file mode 100644 index 00000000..b1d98e74 --- /dev/null +++ b/spinn_machine/version/version_3.py @@ -0,0 +1,32 @@ +# 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 spinn_utilities.abstract_base import AbstractBase, abstractproperty +from spinn_utilities.overrides import overrides +from .version_spin1 import VersionSpin1 + + +class Version3(VersionSpin1): + """ + Code for the small Spin1 4 Chip boards + + Covers versions 2 and 3 + """ + + __slots__ = [] + + @property + @overrides(VersionSpin1.name) + def name(self): + return "Spin1 4 Chip" \ No newline at end of file diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py new file mode 100644 index 00000000..95771555 --- /dev/null +++ b/spinn_machine/version/version_5.py @@ -0,0 +1,32 @@ +# 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 spinn_utilities.abstract_base import AbstractBase, abstractproperty +from spinn_utilities.overrides import overrides +from .version_spin1 import VersionSpin1 + + +class Version5(VersionSpin1): + """ + Code for the large Spin1 48 Chip boards + + Covers versions 4 and 5 + """ + + __slots__ = [] + + @property + @overrides(VersionSpin1.name) + def name(self): + return "Spin1 48 Chip" \ No newline at end of file diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py new file mode 100644 index 00000000..437b0095 --- /dev/null +++ b/spinn_machine/version/version_factory.py @@ -0,0 +1,38 @@ +# 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 spinn_utilities.config_holder import get_config_int +from spinn_machine.exceptions import SpinnMachineException +from .version_3 import Version3 +from .version_5 import Version5 + + +def version_factory(): + """ + Creates a Machine Version class based on cfg settings. + + :return: A superclass of AbstractVersion + :rtype: ~spinn_machine.version.abstract_version.py + :raises SpinnMachineException: If the cfg version is not set correctly + """ + version = get_config_int("Machine", "version") + if version in [2, 3]: + return Version3() + elif version in [4, 5]: + return Version5() + elif version is None: + # TODO raise an error once unittest set cfg + return Version5() + else: + return SpinnMachineException("Unexpected cfg [Machine]version") diff --git a/spinn_machine/version/version_spin1.py b/spinn_machine/version/version_spin1.py new file mode 100644 index 00000000..cc266478 --- /dev/null +++ b/spinn_machine/version/version_spin1.py @@ -0,0 +1,28 @@ +# 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 spinn_utilities.abstract_base import AbstractBase, abstractproperty +from spinn_utilities.overrides import overrides +from .abstract_version import AbstractVersion + + +class VersionSpin1(AbstractVersion, metaclass=AbstractBase): + """ + Shared code for all Spin1 board versions + """ + + __slots__ = [] + + def __init__(self): + super().__init__(max_cores_per_chip=18) diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 5b732260..5d308dff 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -322,21 +322,6 @@ def test_get_global_xy(self): self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 0)) self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (25, 4)) - def test_max_cores_per_chip(self): - """ - Test set_max_cores_per_chip - - Note: Method tested here may not be - :return: - """ - Machine.set_max_cores_per_chip(10) - self.assertEqual(Machine.max_cores_per_chip(), 10) - with self.assertRaises(SpinnMachineException): - Machine.set_max_cores_per_chip(11) - # hack to set back to None to not break other tests - Machine._Machine__max_cores = None - self.assertEqual(Machine.max_cores_per_chip(), 18) - def test_no_boot(self): machine = machine_from_size(8, 8) with self.assertRaises(SpinnMachineException): diff --git a/unittests/version/__init__.py b/unittests/version/__init__.py new file mode 100644 index 00000000..91eaa0c5 --- /dev/null +++ b/unittests/version/__init__.py @@ -0,0 +1,13 @@ +# 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. diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py new file mode 100644 index 00000000..1c95ac3a --- /dev/null +++ b/unittests/version/test_version5.py @@ -0,0 +1,36 @@ +# Copyright (c) 2015 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. + +""" +Testing Version5 +""" +import unittest +from spinn_machine.version.version_5 import Version5 +from spinn_machine.config_setup import unittest_setup + + +class TestVersion5(unittest.TestCase): + """ Tests of IPTag + """ + def setUp(self): + unittest_setup() + + def test_version(self): + version = Version5() + a = version.max_cores_per_chip + self.assertEqual(18, version.max_cores_per_chip) + + +if __name__ == '__main__': + unittest.main() From de201500f5423b4163b6bff77e8e32b5f505d9b7 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 12 Jul 2023 13:32:52 +0100 Subject: [PATCH 02/24] n_non_user_cores via Version --- spinn_machine/chip.py | 6 ++++-- spinn_machine/machine.py | 2 -- spinn_machine/version/abstract_version.py | 9 +++++++++ spinn_machine/version/version_spin1.py | 5 +++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/spinn_machine/chip.py b/spinn_machine/chip.py index 45fb913c..1452cf63 100644 --- a/spinn_machine/chip.py +++ b/spinn_machine/chip.py @@ -13,6 +13,7 @@ # limitations under the License. from spinn_utilities.ordered_set import OrderedSet +from spinn_machine.data import MachineDataView from .machine import Machine from .processor import Processor @@ -112,8 +113,9 @@ def __generate_processors(self, n_processors, down_cores): for i in range(1, n_processors): if i not in down_cores: processors[i] = Processor.factory(i) - self._n_user_processors = \ - n_processors - Machine.NON_USER_CORES - len(down_cores) + self._n_user_processors = ( + n_processors - len(down_cores) - + MachineDataView.get_machine_version().n_non_user_cores) return processors def is_processor_with_id(self, processor_id): diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 9d5f8f38..ef146679 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -40,9 +40,7 @@ class Machine(object, metaclass=AbstractBase): # current opinions is that the Ethernet connected chip can handle 10 # UDP packets per millisecond - NON_USER_CORES = 1 DEFAULT_SDRAM_BYTES = 123469792 - __max_cores = None MAX_CHIPS_PER_48_BOARD = 48 # other useful magic numbers for machines diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index a7aa1314..10e4b250 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -66,5 +66,14 @@ def max_cores_per_chip(self): cores, only that there will be no cores with more. :return: the default cores per chip + :rtype: int """ return self._max_cores_per_chip + + @property + def n_non_user_cores(self): + """ + The number of user cores per chip + + :rtype: int + """ diff --git a/spinn_machine/version/version_spin1.py b/spinn_machine/version/version_spin1.py index cc266478..6e891f4f 100644 --- a/spinn_machine/version/version_spin1.py +++ b/spinn_machine/version/version_spin1.py @@ -26,3 +26,8 @@ class VersionSpin1(AbstractVersion, metaclass=AbstractBase): def __init__(self): super().__init__(max_cores_per_chip=18) + + @property + @overrides(AbstractVersion.n_non_user_cores) + def n_non_user_cores(self): + return 1 From 293131807e65fbd0d99ba87465e1b8d05dedaf5f Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 12 Jul 2023 15:11:53 +0100 Subject: [PATCH 03/24] max_sdram_per_chip via version --- spinn_machine/__init__.py | 4 +- spinn_machine/machine.py | 10 +- spinn_machine/machine_factory.py | 39 +---- spinn_machine/version/abstract_version.py | 40 ++++- spinn_machine/version/version_3.py | 1 - spinn_machine/version/version_5.py | 1 - spinn_machine/version/version_spin1.py | 4 +- spinn_machine/virtual_machine.py | 11 +- unittests/test_machine.py | 195 +++++++--------------- unittests/version/test_version5.py | 3 +- 10 files changed, 111 insertions(+), 197 deletions(-) diff --git a/spinn_machine/__init__.py b/spinn_machine/__init__.py index 5eb696fb..1cbad651 100644 --- a/spinn_machine/__init__.py +++ b/spinn_machine/__init__.py @@ -87,10 +87,10 @@ from .spinnaker_triad_geometry import SpiNNakerTriadGeometry from .virtual_machine import virtual_machine from .fixed_route_entry import FixedRouteEntry -from .machine_factory import machine_from_chips, machine_from_size +from .machine_factory import machine_from_size __all__ = ["Chip", "CoreSubset", "CoreSubsets", "FixedRouteEntry", "Link", "Machine", "MulticastRoutingEntry", "Processor", "Router", "SpiNNakerTriadGeometry", - "virtual_machine", "machine_from_chips", "machine_from_size"] + "virtual_machine", "machine_from_size"] diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index ef146679..140617bf 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -38,9 +38,6 @@ class Machine(object, metaclass=AbstractBase): to determine the correct machine class. """ - # current opinions is that the Ethernet connected chip can handle 10 - # UDP packets per millisecond - DEFAULT_SDRAM_BYTES = 123469792 MAX_CHIPS_PER_48_BOARD = 48 # other useful magic numbers for machines @@ -83,17 +80,18 @@ class Machine(object, metaclass=AbstractBase): "_width" ) - def __init__(self, width, height, chips=None, origin=None): + def __init__(self, width, height, origin=None): """ :param int width: The width of the machine excluding :param int height: The height of the machine - :param iterable(Chip) chips: An iterable of chips in the machine :param str origin: Extra information about how this machine was created to be used in the str method. Example "``Virtual``" or "``Json``" :raise SpinnMachineAlreadyExistsException: If any two chips have the same x and y coordinates """ + if origin is not None: + assert isinstance(origin, str) self._width = width self._height = height @@ -120,8 +118,6 @@ def __init__(self, width, height, chips=None, origin=None): # The dictionary of chips self._chips = dict() - if chips is not None: - self.add_chips(chips) if origin is None: self._origin = "" diff --git a/spinn_machine/machine_factory.py b/spinn_machine/machine_factory.py index 32fe46ff..d5a7623f 100644 --- a/spinn_machine/machine_factory.py +++ b/spinn_machine/machine_factory.py @@ -51,7 +51,7 @@ "spinnakerusers@googlegroups.com \n\n") -def machine_from_size(width, height, chips=None, origin=None): +def machine_from_size(width, height, origin=None): """ Create a machine with the assumed wrap-around based on the sizes. @@ -64,51 +64,24 @@ def machine_from_size(width, height, chips=None, origin=None): :param int width: The width of the machine excluding any virtual chips :param int height: The height of the machine excluding any virtual chips - :param chips: Any chips to be added. - :type chips: list(Chip) or None :param origin: Extra information about how this machine was created to be used in the str method. Example "``Virtual``" or "``Json``" :type origin: str or None :return: A subclass of Machine :rtype: Machine """ - if chips is None: - chips = [] if width == 2 and height == 2: - return FullWrapMachine(width, height, chips, origin) + return FullWrapMachine(width, height, origin) if width % 12 == 0: if height % 12 == 0: - return FullWrapMachine(width, height, chips, origin) + return FullWrapMachine(width, height, origin) else: - return HorizontalWrapMachine(width, height, chips, origin) + return HorizontalWrapMachine(width, height, origin) else: if height % 12 == 0: - return VerticalWrapMachine(width, height, chips, origin) + return VerticalWrapMachine(width, height, origin) else: - return NoWrapMachine(width, height, chips, origin) - - -def machine_from_chips(chips): - """ - Create a machine with the assumed wrap-around based on the sizes. - - The size of the machine is calculated from the list of chips. - - :param chips: Full list of all chips on this machine. - Or at least a list which includes a chip with the highest X and - one with the highest Y (excluding any virtual chips) - :type chips: list(Chip) - :return: A subclass of Machine - :rtype: Machine - """ - max_x = 0 - max_y = 0 - for chip in chips: - if chip.x > max_x: - max_x = chip.x - if chip.y > max_y: - max_y = chip.y - return machine_from_size(max_x + 1, max_y + 1, chips) + return NoWrapMachine(width, height, origin) def _machine_ignore(original, dead_chips, dead_links): diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 10e4b250..ede1181c 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -13,12 +13,9 @@ # limitations under the License. import logging -from spinn_utilities.abstract_base import ( - AbstractBase, abstractproperty, abstractmethod) +from spinn_utilities.abstract_base import (AbstractBase, abstractproperty) from spinn_utilities.log import FormatAdapter -from spinn_utilities.config_holder import ( - config_options, load_config, get_config_bool, get_config_int, - get_config_str, get_config_str_list, set_config) +from spinn_utilities.config_holder import get_config_int logger = FormatAdapter(logging.getLogger(__name__)) @@ -31,9 +28,10 @@ class AbstractVersion(object, metaclass=AbstractBase): __slots__ = [ # the board address associated with this tag "_max_cores_per_chip", + "_max_sdram_per_chip" ] - def __init__(self, max_cores_per_chip): + def __init__(self, max_cores_per_chip, max_sdram_per_chip): self._max_cores_per_chip = max_cores_per_chip max_machine_core = get_config_int("Machine", "max_machine_core") if max_machine_core is not None: @@ -49,6 +47,21 @@ def __init__(self, max_cores_per_chip): f"due to cfg setting [Machine]max_machine_core") self._max_cores_per_chip = max_machine_core + self._max_sdram_per_chip = max_sdram_per_chip + max_sdram = get_config_int("Machine", "max_sdram_allowed_per_chip") + if max_sdram is not None: + if max_sdram > self._max_sdram_per_chip: + logger.info( + f"Ignoring csg setting [Machine]max_sdram_allowed_per_chip " + f"{max_sdram} as it is larger than " + f"{self._max_sdram_per_chip} which is the default for a " + f"{self.name} board ") + if max_sdram < self._max_cores_per_chip: + logger.warning( + f"Max sdram per chip reduced to {max_sdram_per_chip} " + f"due to cfg setting [Machine]max_sdram_allowed_per_chip") + self._max_sdram_per_chip = max_sdram_per_chip + @abstractproperty def name(self): """ @@ -70,10 +83,23 @@ def max_cores_per_chip(self): """ return self._max_cores_per_chip - @property + @abstractproperty def n_non_user_cores(self): """ The number of user cores per chip :rtype: int """ + + @property + def max_sdram_per_chip(self): + """ + Gets the max sdram per chip for the whole system. + + While it is likely that all Chips will have this sdram + this should not be counted on. Ask each Chip for its sdram. + + :return: the default sdram per chip + :rtype: int + """ + return self._max_sdram_per_chip diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index b1d98e74..05b9d452 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from spinn_utilities.abstract_base import AbstractBase, abstractproperty from spinn_utilities.overrides import overrides from .version_spin1 import VersionSpin1 diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index 95771555..057b0b2c 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from spinn_utilities.abstract_base import AbstractBase, abstractproperty from spinn_utilities.overrides import overrides from .version_spin1 import VersionSpin1 diff --git a/spinn_machine/version/version_spin1.py b/spinn_machine/version/version_spin1.py index 6e891f4f..ca21cd87 100644 --- a/spinn_machine/version/version_spin1.py +++ b/spinn_machine/version/version_spin1.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from spinn_utilities.abstract_base import AbstractBase, abstractproperty +from spinn_utilities.abstract_base import AbstractBase from spinn_utilities.overrides import overrides from .abstract_version import AbstractVersion @@ -25,7 +25,7 @@ class VersionSpin1(AbstractVersion, metaclass=AbstractBase): __slots__ = [] def __init__(self): - super().__init__(max_cores_per_chip=18) + super().__init__(max_cores_per_chip=18, max_sdram_per_chip=123469792) @property @overrides(AbstractVersion.n_non_user_cores) diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index c3266a31..629adbe7 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -23,6 +23,7 @@ from .spinnaker_triad_geometry import SpiNNakerTriadGeometry from .machine_factory import machine_from_size from spinn_machine import Machine +from spinn_machine.data import MachineDataView from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink logger = FormatAdapter(logging.getLogger(__name__)) @@ -83,7 +84,6 @@ class _VirtualMachine(object): "_unused_cores", "_unused_links", "_machine", - "_sdram_per_chip", "_with_monitors") _4_chip_down_links = { @@ -99,12 +99,6 @@ def __init__( _verify_width_height(width, height) self._machine = machine_from_size(width, height, origin=self.ORIGIN) - # Store the details - self._sdram_per_chip = get_config_int( - "Machine", "max_sdram_allowed_per_chip") - if self._sdram_per_chip is None: - self._sdram_per_chip = Machine.DEFAULT_SDRAM_BYTES - # Store the down items unused_chips = [] for down_chip in IgnoreChip.parse_string(get_config_str( @@ -191,8 +185,9 @@ def _create_chip(self, x, y, configured_chips, ip_address=None): (eth_x, eth_y, n_cores) = configured_chips[(x, y)] down_cores = self._unused_cores.get((x, y), None) + sdram = MachineDataView.get_machine_version().max_sdram_per_chip return Chip( - x, y, n_cores, chip_router, self._sdram_per_chip, eth_x, eth_y, + x, y, n_cores, chip_router, sdram, eth_x, eth_y, ip_address, down_cores=down_cores) def _calculate_links(self, x, y, configured_chips): diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 5d308dff..54e03b90 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -17,7 +17,8 @@ """ import unittest from spinn_machine import ( - Link, Router, Chip, Machine, machine_from_chips, machine_from_size) + Link, Router, Chip, machine_from_size) +from spinn_machine import virtual_machine from spinn_machine.config_setup import unittest_setup from spinn_machine.exceptions import ( SpinnMachineAlreadyExistsException, SpinnMachineException) @@ -30,7 +31,7 @@ class SpinnMachineTestCase(unittest.TestCase): def setUp(self): unittest_setup() - self._sdram = 128 + self._sdram = 123469792 links = list() links.append(Link(0, 0, 0, 1, 1)) @@ -52,44 +53,36 @@ def _create_chip(self, x, y): self._nearest_ethernet_chip[0], self._nearest_ethernet_chip[1], None) - def _create_chips(self): - chips = list() - for x in range(5): - for y in range(5): - chips.append(self._create_chip(x, y)) - return chips - def test_create_new_machine(self): """ test creating a new machine """ - chips = self._create_chips() - - new_machine = machine_from_chips(chips) + new_machine = virtual_machine(8, 8) - self.assertEqual(new_machine.width, 5) - self.assertEqual(new_machine.height, 5) + self.assertEqual(new_machine.width, 8) + self.assertEqual(new_machine.height, 8) for c in new_machine.chips: if (c.x == c.y == 0): - self.assertEqual(c.ip_address, self._ip) + self.assertEqual(c.ip_address, "127.0.0.0") else: self.assertIsNone(c.ip_address) - self.assertEqual(c.sdram, self._sdram) - self.assertEqual(c.router, self._router) - - self.assertEqual(new_machine.total_cores, 450) - self.assertEqual(new_machine.total_available_user_cores, 425) - self.assertEqual(new_machine.boot_chip.ip_address, self._ip) - self.assertEqual(new_machine.n_chips, 25) - self.assertEqual(len(new_machine), 25) - self.assertEqual(next(x[1].ip_address for x in new_machine), self._ip) + self.assertEqual(123469792, c.sdram) + self.assertIsNotNone(c.router) + + self.assertEqual(new_machine.total_cores, 856) + self.assertEqual(new_machine.total_available_user_cores, 856 - 48) + self.assertEqual(new_machine.boot_chip.ip_address, "127.0.0.0") + self.assertEqual(new_machine.n_chips, 48) + self.assertEqual(len(new_machine), 48) + self.assertEqual(next(x[1].ip_address for x in new_machine), "127.0.0.0") self.assertEqual(next(new_machine.chip_coordinates), (0, 0)) - self.assertEqual(new_machine.cores_and_link_output_string(), - "450 cores and 50.0 links") - self.assertEqual("[NoWrapMachine: width=5, height=5, n_chips=25]", - new_machine.__repr__()) - self.assertEqual(list(new_machine.spinnaker_links), []) + self.assertEqual("856 cores and 120.0 links", + new_machine.cores_and_link_output_string()) + self.assertEqual( + "[VirtualNoWrapMachine: width=8, height=8, n_chips=48]", + new_machine.__repr__()) + self.assertEqual(2, len(list(new_machine.spinnaker_links))) def test_create_new_machine_with_invalid_chips(self): """ @@ -97,13 +90,12 @@ def test_create_new_machine_with_invalid_chips(self): :rtype: None """ - chips = self._create_chips() - chips.append(Chip( - 0, 0, 18, self._router, self._sdram, - self._nearest_ethernet_chip[0], - self._nearest_ethernet_chip[1], self._ip)) + machine = virtual_machine(8, 8) with self.assertRaises(SpinnMachineAlreadyExistsException): - machine_from_chips(chips) + machine.add_chip(Chip( + 0, 0, 18, self._router, self._sdram, + self._nearest_ethernet_chip[0], + self._nearest_ethernet_chip[1], self._ip)) def test_machine_add_chip(self): """ @@ -111,17 +103,17 @@ def test_machine_add_chip(self): :rtype: None """ - new_machine = machine_from_size(6, 5, self._create_chips()) + new_machine = virtual_machine(8, 8) extra_chip = self._create_chip(5, 0) new_machine.add_chip(extra_chip) for c in new_machine.chips: if (c.x == c.y == 0): - self.assertEqual(c.ip_address, self._ip) + self.assertEqual(c.ip_address, "127.0.0.0") else: self.assertIsNone(c.ip_address) self.assertEqual(c.sdram, self._sdram) - self.assertEqual(c.router, self._router) + self.assertIsNotNone(c.router) def test_machine_add_duplicate_chip(self): """ @@ -129,52 +121,9 @@ def test_machine_add_duplicate_chip(self): :rtype: None """ - chips = self._create_chips() - new_machine = machine_from_chips(chips) - with self.assertRaises(SpinnMachineAlreadyExistsException): - new_machine.add_chip(chips[3]) - - def test_machine_add_chips(self): - """ - check that adding range of chips works - - :rtype: None - """ - chips = self._create_chips() - new_machine = machine_from_size(6, 5, chips) - - extra_chips = list() - extra_chips.append(self._create_chip(5, 0)) - extra_chips.append(self._create_chip(5, 1)) - extra_chips.append(self._create_chip(5, 2)) - extra_chips.append(self._create_chip(5, 3)) - - new_machine.add_chips(extra_chips) - - for c in new_machine.chips: - if (c.x == c.y == 0): - self.assertEqual(c.ip_address, self._ip) - else: - self.assertIsNone(c.ip_address) - self.assertEqual(c.sdram, self._sdram) - self.assertEqual(c.router, self._router) - - def test_machine_add_duplicate_chips(self): - """ - test the add_chips method of the machine with duplicate chips. - should produce an error - - :rtype: None - """ - chips = self._create_chips() - new_machine = machine_from_size(7, 5, chips) - - extra_chips = list() - extra_chips.append(self._create_chip(6, 0)) - extra_chips.append(chips[3]) - + new_machine = virtual_machine(8, 8) with self.assertRaises(SpinnMachineAlreadyExistsException): - new_machine.add_chips(extra_chips) + new_machine.add_chip(new_machine.get_chip_at(1, 1)) def test_machine_get_chip_at(self): """ @@ -182,9 +131,9 @@ def test_machine_get_chip_at(self): :rtype: None """ - chips = self._create_chips() - new_machine = machine_from_chips(chips) - self.assertEqual(chips[0], new_machine.get_chip_at(0, 0)) + new_machine = virtual_machine(8, 8) + self.assertEqual(2, new_machine.get_chip_at(2, 3).x) + self.assertEqual(3, new_machine.get_chip_at(2, 3).y) def test_machine_big_x(self): """ @@ -227,9 +176,7 @@ def test_machine_get_chip_at_invalid_location(self): :rtype: None """ - chips = self._create_chips() - - new_machine = machine_from_chips(chips) + new_machine = virtual_machine(8, 8) self.assertEqual(None, new_machine.get_chip_at(10, 0)) def test_machine_is_chip_at_true(self): @@ -239,9 +186,7 @@ def test_machine_is_chip_at_true(self): :rtype: None """ - chips = self._create_chips() - - new_machine = machine_from_chips(chips) + new_machine = virtual_machine(8, 8) self.assertTrue(new_machine.is_chip_at(3, 0)) def test_machine_is_chip_at_false(self): @@ -251,24 +196,21 @@ def test_machine_is_chip_at_false(self): :rtype: None """ - chips = self._create_chips() - new_machine = machine_from_chips(chips) + new_machine = virtual_machine(8, 8) self.assertFalse(new_machine.is_chip_at(10, 0)) def test_machine_get_chips_on_board(self): - chips = self._create_chips() - new_machine = machine_from_size(8, 8, chips) + new_machine = virtual_machine(8, 8) for eth_chip in new_machine._ethernet_connected_chips: chips_in_machine = list( new_machine.get_existing_xys_on_board(eth_chip)) # _create_chips made a 5*5 grid of 25 chips, # but (0,4) is not on a standard 48-node board - self.assertEqual(len(chips), 25) - self.assertEqual(len(chips_in_machine), 24) + self.assertEqual(len(chips_in_machine), 48) with self.assertRaises(KeyError): new_machine.get_spinnaker_link_with_id(1) with self.assertRaises(KeyError): - self.assertIsNone(new_machine.get_fpga_link_with_id(1, 0)) + new_machine.get_fpga_link_with_id(3, 3) def test_x_y_over_link(self): """ @@ -328,68 +270,51 @@ def test_no_boot(self): machine.validate() def test_negative_x(self): - chips = self._create_chips() - chips[3]._x = -1 - machine = machine_from_chips(chips) + machine = machine_from_size(8, 8) + chip = self._create_chip(2, -1) + machine.add_chip(chip) with self.assertRaises(SpinnMachineException): machine.validate() def test_negative_y(self): - chips = self._create_chips() - chips[3]._y = -1 - machine = machine_from_chips(chips) + machine = machine_from_size(8, 8) + chip = self._create_chip(-1, 3) + machine.add_chip(chip) with self.assertRaises(SpinnMachineException): machine.validate() def test_big_x(self): - chips = self._create_chips() - machine = machine_from_chips(chips) - chips[3]._x = 9 + machine = virtual_machine(8, 8) + machine.get_chip_at(1, 1)._x = 9 with self.assertRaises(SpinnMachineException): machine.validate() def test_big_y(self): - chips = self._create_chips() - machine = machine_from_chips(chips) - chips[3]._y = 9 + machine = virtual_machine(8, 8) + machine.get_chip_at(1, 1)._y = 9 with self.assertRaises(SpinnMachineException): machine.validate() def test_weird_ethernet1(self): - chips = self._create_chips() - machine = machine_from_chips(chips) - # chips[8] = x;1 y3 - chips[8]._ip_address = "1.2.3.4" - with self.assertRaises(SpinnMachineException): - machine.validate() - - def test_weird_ethernet2(self): - chips = self._create_chips() - machine = machine_from_chips(chips) - # chips[1] = x:0 y:1 - chips[1]._ip_address = "1.2.3.4" + machine = virtual_machine(8, 8) + machine.get_chip_at(1, 3)._ip_address = "1.2.3.4" with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_x(self): - chips = self._create_chips() - machine = machine_from_chips(chips) - # chips[1] = x:0 y:1 - chips[1]._nearest_ethernet_x = 1 + machine = virtual_machine(8, 8) + machine.get_chip_at(0, 1)._nearest_ethernet_x = 1 with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_no_chip(self): - chips = self._create_chips() - machine = machine_from_chips(chips) - # chips[1] = x:0 y:1 - chips[1]._nearest_ethernet_x = 12 + machine = virtual_machine(8, 8) + machine.get_chip_at(0, 1)._nearest_ethernet_x = 12 with self.assertRaises(SpinnMachineException): machine.validate() def test_getitem(self): - chips = self._create_chips() - machine = machine_from_chips(chips) + machine = virtual_machine(8, 8) chip12 = machine[(1, 2)] self.assertEqual(chip12.x, 1) self.assertEqual(chip12.y, 2) @@ -397,8 +322,8 @@ def test_getitem(self): self.assertFalse((1, 9) in machine) def test_concentric_xys(self): - chips = self._create_chips() - machine = machine_from_chips(chips) + machine = virtual_machine(8, 8) + machine.get_chip_at(1, 3) found = list(machine.concentric_xys(2, (2, 2))) expected = [ (2, 2), diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index 1c95ac3a..4e4532ea 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -28,8 +28,9 @@ def setUp(self): def test_version(self): version = Version5() - a = version.max_cores_per_chip self.assertEqual(18, version.max_cores_per_chip) + self.assertEqual(123469792, version.max_sdram_per_chip) + self.assertEqual(1, version.n_non_user_cores) if __name__ == '__main__': From 9a99a8dcaf64f654e27314da29776f34bb2d699a Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 12 Jul 2023 17:20:54 +0100 Subject: [PATCH 04/24] move remote_spinnaker_url and spalloc_server cfgs --- spinn_machine/spinn_machine.cfg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spinn_machine/spinn_machine.cfg b/spinn_machine/spinn_machine.cfg index e1f99881..8a0a6f60 100644 --- a/spinn_machine/spinn_machine.cfg +++ b/spinn_machine/spinn_machine.cfg @@ -35,4 +35,8 @@ down_links = None # Allows the setting of max number of cores per chip # Set to None to use the default value. -max_machine_core = None \ No newline at end of file +max_machine_core = None + +# Urls for servers +remote_spinnaker_url = None +spalloc_server = None From 7a5958c6696d5b40e9d968e7f79f3e25877f7548 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 12 Jul 2023 17:24:25 +0100 Subject: [PATCH 05/24] require something in cfg to dettermine version --- spinn_machine/version/version_factory.py | 33 +++++++++++++++++++----- unittests/data/test_data.py | 3 +++ unittests/test_json_machine.py | 1 + unittests/test_machine.py | 3 +++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index 437b0095..2f67f457 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -12,11 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -from spinn_utilities.config_holder import get_config_int +import logging +from spinn_utilities.config_holder import get_config_int, get_config_str +from spinn_utilities.log import FormatAdapter from spinn_machine.exceptions import SpinnMachineException from .version_3 import Version3 from .version_5 import Version5 +logger = FormatAdapter(logging.getLogger(__name__)) + def version_factory(): """ @@ -29,10 +33,27 @@ def version_factory(): version = get_config_int("Machine", "version") if version in [2, 3]: return Version3() - elif version in [4, 5]: + + if version in [4, 5]: return Version5() - elif version is None: - # TODO raise an error once unittest set cfg + + spalloc_server = get_config_str("Machine", "spalloc_server") + if spalloc_server is not None: + return Version5() + + remote_spinnaker_url = get_config_str("Machine", "remote_spinnaker_url") + if remote_spinnaker_url is not None: return Version5() - else: - return SpinnMachineException("Unexpected cfg [Machine]version") + + height = get_config_int("Machine", "height") + width = get_config_int("Machine", "width") + if height is not None and width is not None: + if height == width == 2: + logger.info("Your cfg file does not have a ") + return Version3() + return Version5() + + if version is None: + raise SpinnMachineException("cfg [Machine]version {version} is None") + + raise SpinnMachineException(f"Unexpected cfg [Machine]version {version}") diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index 5fa051b5..7f4dfc2a 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -13,6 +13,7 @@ # limitations under the License. import unittest +from spinn_utilities.config_holder import set_config from spinn_utilities.exceptions import (DataNotYetAvialable) from spinn_machine import virtual_machine from spinn_machine.config_setup import unittest_setup @@ -24,6 +25,7 @@ class TestSimulatorData(unittest.TestCase): def setUp(cls): unittest_setup() + set_config("Machine", "version", 5) def test_setup(self): # What happens before setup depends on the previous test @@ -41,6 +43,7 @@ def test_mock(self): def test_machine(self): writer = MachineDataWriter.setup() + with self.assertRaises(DataNotYetAvialable): MachineDataView.get_machine() self.assertFalse(MachineDataWriter.has_machine()) diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index ef22f63c..4a1ce600 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -25,6 +25,7 @@ class TestJsonMachine(unittest.TestCase): def setUp(self): unittest_setup() + set_config("Machine", "version", 5) def test_json_version_5_hole(self): set_config("Machine", "down_chips", "3,3") diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 54e03b90..cfc41ac9 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -16,6 +16,7 @@ test for testing the python representation of a spinnaker machine """ import unittest +from spinn_utilities.config_holder import set_config from spinn_machine import ( Link, Router, Chip, machine_from_size) from spinn_machine import virtual_machine @@ -31,6 +32,8 @@ class SpinnMachineTestCase(unittest.TestCase): def setUp(self): unittest_setup() + set_config("Machine", "version", 5) + self._sdram = 123469792 links = list() From c2eb4abcf457b396458d743a342045e9983b6de2 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 06:50:31 +0100 Subject: [PATCH 06/24] set_config("Machine", "version", 5) --- unittests/test_virtual_machine.py | 1 + 1 file changed, 1 insertion(+) diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index a4f46877..72ccf74f 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -32,6 +32,7 @@ class TestVirtualMachine(unittest.TestCase): def setUp(self): unittest_setup() + set_config("Machine", "version", 5) def _create_chip(self, x, y): # Create a list of processors. From b8a566e428f3d0e1791a9ac2f6e55beefd0d07cb Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 10:01:50 +0100 Subject: [PATCH 07/24] move verify machine size and pick Machine type to Version classes --- spinn_machine/__init__.py | 3 +- spinn_machine/data/machine_data_view.py | 17 ++++- spinn_machine/json_machine.py | 4 +- spinn_machine/machine_factory.py | 37 +-------- spinn_machine/version/__init__.py | 4 - spinn_machine/version/abstract_version.py | 92 ++++++++++++++++++++++- spinn_machine/version/version_3.py | 15 +++- spinn_machine/version/version_5.py | 35 ++++++++- spinn_machine/version/version_factory.py | 6 +- spinn_machine/virtual_machine.py | 34 +-------- unittests/data/test_data.py | 1 + unittests/test_machine.py | 42 ++++++----- unittests/test_virtual_machine.py | 11 +-- 13 files changed, 191 insertions(+), 110 deletions(-) diff --git a/spinn_machine/__init__.py b/spinn_machine/__init__.py index 1cbad651..a4e05bff 100644 --- a/spinn_machine/__init__.py +++ b/spinn_machine/__init__.py @@ -87,10 +87,9 @@ from .spinnaker_triad_geometry import SpiNNakerTriadGeometry from .virtual_machine import virtual_machine from .fixed_route_entry import FixedRouteEntry -from .machine_factory import machine_from_size __all__ = ["Chip", "CoreSubset", "CoreSubsets", "FixedRouteEntry", "Link", "Machine", "MulticastRoutingEntry", "Processor", "Router", "SpiNNakerTriadGeometry", - "virtual_machine", "machine_from_size"] + "virtual_machine"] diff --git a/spinn_machine/data/machine_data_view.py b/spinn_machine/data/machine_data_view.py index f1f6f47e..c86d3a40 100644 --- a/spinn_machine/data/machine_data_view.py +++ b/spinn_machine/data/machine_data_view.py @@ -13,7 +13,7 @@ # limitations under the License. from spinn_utilities.data import UtilsDataView -from spinn_machine.version import version_factory +from spinn_machine.version.version_factory import version_factory # pylint: disable=protected-access @@ -97,11 +97,26 @@ def has_machine(cls): """ Reports if a machine is currently set or can be mocked. + Unlike has_existing_machine for unittests this will return True even + if a Machine has not yet been created + :rtype: bool """ return (cls.__data._machine is not None or cls._is_mocked()) + @classmethod + def has_existing_machine(cls): + """ + Reports if a machine is currently already created. + + Unlike has_machine this method returns false if a machine could be + mocked + + :rtype: bool + """ + return cls.__data._machine + @classmethod def get_machine(cls): """ diff --git a/spinn_machine/json_machine.py b/spinn_machine/json_machine.py index 34938bbe..a3a02535 100644 --- a/spinn_machine/json_machine.py +++ b/spinn_machine/json_machine.py @@ -20,7 +20,6 @@ from .chip import Chip from .router import Router from .link import Link -from .machine_factory import machine_from_size logger = FormatAdapter(logging.getLogger(__name__)) @@ -58,7 +57,8 @@ def machine_from_json(j_machine): width = j_machine["width"] height = j_machine["height"] - machine = machine_from_size(width, height, origin="Json") + machine = MachineDataView.get_machine_version().create_machine( + width, height, origin="Json") s_monitors = j_machine["standardResources"]["monitors"] s_router_entries = j_machine["standardResources"]["routerEntries"] s_sdram = j_machine["standardResources"]["sdram"] diff --git a/spinn_machine/machine_factory.py b/spinn_machine/machine_factory.py index d5a7623f..d2229e30 100644 --- a/spinn_machine/machine_factory.py +++ b/spinn_machine/machine_factory.py @@ -17,6 +17,7 @@ from spinn_utilities.config_holder import get_config_bool from spinn_utilities.log import FormatAdapter from spinn_machine import (Chip, Router) +from spinn_machine.data import MachineDataView from .no_wrap_machine import NoWrapMachine from .horizontal_wrap_machine import HorizontalWrapMachine from .vertical_wrap_machine import VerticalWrapMachine @@ -51,39 +52,6 @@ "spinnakerusers@googlegroups.com \n\n") -def machine_from_size(width, height, origin=None): - """ - Create a machine with the assumed wrap-around based on the sizes. - - This could include a machine with no wrap-arounds, only vertical ones, - only horizontal ones or both. - - .. note:: - If the sizes do not match the ones for a known wrap-around machine, - a machine with no wrap-arounds is assumed. - - :param int width: The width of the machine excluding any virtual chips - :param int height: The height of the machine excluding any virtual chips - :param origin: Extra information about how this machine was created - to be used in the str method. Example "``Virtual``" or "``Json``" - :type origin: str or None - :return: A subclass of Machine - :rtype: Machine - """ - if width == 2 and height == 2: - return FullWrapMachine(width, height, origin) - if width % 12 == 0: - if height % 12 == 0: - return FullWrapMachine(width, height, origin) - else: - return HorizontalWrapMachine(width, height, origin) - else: - if height % 12 == 0: - return VerticalWrapMachine(width, height, origin) - else: - return NoWrapMachine(width, height, origin) - - def _machine_ignore(original, dead_chips, dead_links): """ Creates a near copy of the machine without the dead bits. @@ -108,7 +76,8 @@ def _machine_ignore(original, dead_chips, dead_links): :type dead_links: Collection of (int, int, int) :return: A New Machine object """ - new_machine = machine_from_size(original.width, original.height) + new_machine = MachineDataView.get_machine_version().create_machine( + original.width, original.height, "Fixed") links_map = defaultdict(set) for x, y, d, _ in dead_links: links_map[(x, y)].add(d) diff --git a/spinn_machine/version/__init__.py b/spinn_machine/version/__init__.py index 0c88d8bb..91eaa0c5 100644 --- a/spinn_machine/version/__init__.py +++ b/spinn_machine/version/__init__.py @@ -11,7 +11,3 @@ # 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 .version_factory import version_factory - -__all__ = ["version_factory"] diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index ede1181c..0e972192 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -13,9 +13,11 @@ # limitations under the License. import logging -from spinn_utilities.abstract_base import (AbstractBase, abstractproperty) +from spinn_utilities.abstract_base import ( + AbstractBase, abstractmethod, abstractproperty) from spinn_utilities.log import FormatAdapter from spinn_utilities.config_holder import get_config_int +from spinn_machine.exceptions import SpinnMachineException logger = FormatAdapter(logging.getLogger(__name__)) @@ -32,6 +34,33 @@ class AbstractVersion(object, metaclass=AbstractBase): ] def __init__(self, max_cores_per_chip, max_sdram_per_chip): + self.__verify_config_width_height() + self.__set_max_cores_per_chip(max_cores_per_chip) + self.__set_max_sdram_per_chip(max_sdram_per_chip) + + def __verify_config_width_height(self): + """ + Check that if there is a cfg width or height the values are valid + + :raises SpinnMachineException: + If the cfg width or height is unexpected + """ + width = get_config_int("Machine", "width") + height = get_config_int("Machine", "height") + if width is None: + if height is None: + pass + else: + raise SpinnMachineException( + f"the cfg has a [Machine]width {width} but a no height") + else: + if height is None: + raise SpinnMachineException( + f"the cfg has a [Machine]height {width} but a no width") + else: + self.verify_size(width, height) + + def __set_max_cores_per_chip(self, max_cores_per_chip): self._max_cores_per_chip = max_cores_per_chip max_machine_core = get_config_int("Machine", "max_machine_core") if max_machine_core is not None: @@ -47,6 +76,7 @@ def __init__(self, max_cores_per_chip, max_sdram_per_chip): f"due to cfg setting [Machine]max_machine_core") self._max_cores_per_chip = max_machine_core + def __set_max_sdram_per_chip(self, max_sdram_per_chip): self._max_sdram_per_chip = max_sdram_per_chip max_sdram = get_config_int("Machine", "max_sdram_allowed_per_chip") if max_sdram is not None: @@ -103,3 +133,63 @@ def max_sdram_per_chip(self): :rtype: int """ return self._max_sdram_per_chip + + def verify_size(self, width, height): + """ + Checks that the width and height are allowed for this version + + :param int width: + :param int height: + :raise SpinnMachineException: If the size is unexpected + """ + if width is None: + raise SpinnMachineException("Width can not be None") + if height is None: + raise SpinnMachineException("Height can not be None") + if width <= 0: + raise SpinnMachineException("Unexpected {width=}") + if height <= 0: + raise SpinnMachineException("Unexpected {height=}") + self._verify_size(width, height) + + @abstractmethod + def _verify_size(self, width, height): + """ + Adds the width and height checks that depend on the version + + :param int width: + :param int height: + :raise SpinnMachineException: + If the size is unexpected + """ + + def create_machine(self, width, height, origin): + """ + Creates a new Empty machine based on the width, height and version + + :param int width: The width of the machine excluding any virtual chips + :param int height: The height of the machine excluding any virtual chips + :param origin: Extra information about how this machine was created + to be used in the str method. Example "``Virtual``" or "``Json``" + :type origin: str or None + :return: A subclass of Machine with no Chips in it + :rtype: ~spinn_machine.Machine + :raises SpinnMachineInvalidParameterException: + If the size is unexpected + """ + self.verify_size(width, height) + return self._create_machine(width, height, origin) + + @abstractmethod + def _create_machine(self, width, height, origin): + """ + Creates a new Empty machine based on the width, height and version + + :param int width: The width of the machine excluding any virtual chips + :param int height: The height of the machine excluding any virtual chips + :param origin: Extra information about how this machine was created + to be used in the str method. Example "``Virtual``" or "``Json``" + :type origin: str or None + :return: A subclass of Machine with no Chips in it + :rtype: ~spinn_machine.Machine + """ diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index 05b9d452..00c2bcf0 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -14,6 +14,8 @@ from spinn_utilities.overrides import overrides from .version_spin1 import VersionSpin1 +from spinn_machine.full_wrap_machine import FullWrapMachine +from spinn_machine.exceptions import SpinnMachineException class Version3(VersionSpin1): @@ -28,4 +30,15 @@ class Version3(VersionSpin1): @property @overrides(VersionSpin1.name) def name(self): - return "Spin1 4 Chip" \ No newline at end of file + return "Spin1 4 Chip" + + @overrides(VersionSpin1._verify_size) + def _verify_size(self, width, height): + if width != 2: + raise SpinnMachineException("Unexpected {width=}") + if height != 2: + raise SpinnMachineException("Unexpected {height=}") + + @overrides(VersionSpin1._create_machine) + def _create_machine(self, width, height, origin): + return FullWrapMachine(width, height, origin) diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index 057b0b2c..09c4513e 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -13,6 +13,12 @@ # limitations under the License. from spinn_utilities.overrides import overrides +from spinn_machine.exceptions import SpinnMachineException +from spinn_machine.full_wrap_machine import FullWrapMachine +from spinn_machine.horizontal_wrap_machine import HorizontalWrapMachine +from spinn_machine.no_wrap_machine import NoWrapMachine +from spinn_machine.vertical_wrap_machine import VerticalWrapMachine + from .version_spin1 import VersionSpin1 @@ -28,4 +34,31 @@ class Version5(VersionSpin1): @property @overrides(VersionSpin1.name) def name(self): - return "Spin1 48 Chip" \ No newline at end of file + return "Spin1 48 Chip" + + @overrides(VersionSpin1._verify_size) + def _verify_size(self, width, height): + if width == height == 8: + # 1 board + return + if width % 12 not in [0, 4]: + raise SpinnMachineException( + f"{width=} must be a multiple of 12 " + f"or a multiple of 12 plus 4") + if height % 12 not in [0, 4]: + raise SpinnMachineException( + f"{height=} must be a multiple of 12 " + f"or a multiple of 12 plus 4") + + @overrides(VersionSpin1._create_machine) + def _create_machine(self, width, height, origin): + if width % 12 == 0: + if height % 12 == 0: + return FullWrapMachine(width, height, origin) + else: + return HorizontalWrapMachine(width, height, origin) + else: + if height % 12 == 0: + return VerticalWrapMachine(width, height, origin) + else: + return NoWrapMachine(width, height, origin) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index 2f67f457..3233b35a 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -16,8 +16,6 @@ from spinn_utilities.config_holder import get_config_int, get_config_str from spinn_utilities.log import FormatAdapter from spinn_machine.exceptions import SpinnMachineException -from .version_3 import Version3 -from .version_5 import Version5 logger = FormatAdapter(logging.getLogger(__name__)) @@ -30,6 +28,10 @@ def version_factory(): :rtype: ~spinn_machine.version.abstract_version.py :raises SpinnMachineException: If the cfg version is not set correctly """ + # Delayed import to avoid circular imports + from .version_3 import Version3 + from .version_5 import Version5 + version = get_config_int("Machine", "version") if version in [2, 3]: return Version3() diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index 629adbe7..363731f6 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -21,7 +21,6 @@ from .router import Router from .link import Link from .spinnaker_triad_geometry import SpiNNakerTriadGeometry -from .machine_factory import machine_from_size from spinn_machine import Machine from spinn_machine.data import MachineDataView from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink @@ -29,35 +28,6 @@ logger = FormatAdapter(logging.getLogger(__name__)) -def _verify_width_height(width, height): - try: - if width < 0 or height < 0: - raise SpinnMachineInvalidParameterException( - "width or height", f"{width} and {height}", - "Negative dimensions are not supported") - except TypeError as original: - if width is None or height is None: - raise SpinnMachineInvalidParameterException( - "width or height", f"{width} and {height}", - "parameter required") from original - raise - - if width == height == 2: - return - if width == height == 8: - return - if width % 12 != 0 and (width - 4) % 12 != 0: - raise SpinnMachineInvalidParameterException( - "width", width, - "A virtual machine must have a width that is divisible by 12 or " - "width - 4 that is divisible by 12") - if height % 12 != 0 and (height - 4) % 12 != 0: - raise SpinnMachineInvalidParameterException( - "height", height, - "A virtual machine must have a height that is divisible by 12 or " - "height - 4 that is divisible by 12") - - def virtual_machine( width, height, n_cpus_per_chip=None, validate=True): """ @@ -96,8 +66,8 @@ class _VirtualMachine(object): def __init__( self, width, height, n_cpus_per_chip=None, validate=True): - _verify_width_height(width, height) - self._machine = machine_from_size(width, height, origin=self.ORIGIN) + self._machine = MachineDataView.get_machine_version().create_machine( + width, height, origin=self.ORIGIN) # Store the down items unused_chips = [] diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index 7f4dfc2a..7617fec4 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -42,6 +42,7 @@ def test_mock(self): self.assertEqual(48, MachineDataView.get_machine().n_chips) def test_machine(self): + set_config("Machine", "version", 3) writer = MachineDataWriter.setup() with self.assertRaises(DataNotYetAvialable): diff --git a/unittests/test_machine.py b/unittests/test_machine.py index cfc41ac9..3d24d80b 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -21,6 +21,7 @@ Link, Router, Chip, machine_from_size) from spinn_machine import virtual_machine from spinn_machine.config_setup import unittest_setup +from spinn_machine.data import MachineDataView from spinn_machine.exceptions import ( SpinnMachineAlreadyExistsException, SpinnMachineException) @@ -145,7 +146,7 @@ def test_machine_big_x(self): :rtype: None """ - new_machine = machine_from_size(8, 8) + new_machine = MachineDataView.get_machine_version().create_machine(8, 8) new_machine.add_chip(self._create_chip(0, 0)) # the add does not have the safety code new_machine.add_chip(self._create_chip(10, 2)) @@ -162,7 +163,8 @@ def test_machine_big_y(self): :rtype: None """ - new_machine = machine_from_size(8, 8) + version = MachineDataView.get_machine_version() + new_machine = version.create_machine(8, 8) new_machine.add_chip(self._create_chip(0, 0)) # the add does not have the safety code new_machine.add_chip(self._create_chip(2, 10)) @@ -223,22 +225,22 @@ def test_x_y_over_link(self): :return: """ # full wrap around - machine = machine_from_size(24, 24) + machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.xy_over_link(0, 0, 4), (23, 23)) self.assertEqual(machine.xy_over_link(23, 23, 1), (0, 0)) self.assertEqual(machine.wrap, "Wrapped") # no wrap around' - machine = machine_from_size(16, 16) + machine = MachineDataView.get_machine_version().create_machine(16, 16) self.assertEqual(machine.xy_over_link(0, 0, 4), (-1, -1)) self.assertEqual(machine.xy_over_link(15, 15, 1), (16, 16)) self.assertEqual(machine.wrap, "NoWrap") # Horizontal wrap arounds - machine = machine_from_size(24, 16) + machine = MachineDataView.get_machine_version().create_machine(24, 16) self.assertEqual(machine.xy_over_link(0, 0, 4), (23, -1)) self.assertEqual(machine.xy_over_link(23, 15, 1), (0, 16)) self.assertEqual(machine.wrap, "HorWrap") # Vertical wrap arounds - machine = machine_from_size(16, 24) + machine = MachineDataView.get_machine_version().create_machine(16, 24) self.assertEqual(machine.xy_over_link(0, 0, 4), (-1, 23)) self.assertEqual(machine.xy_over_link(15, 23, 1), (16, 0)) self.assertEqual(machine.wrap, "VerWrap") @@ -251,73 +253,73 @@ def test_get_global_xy(self): :return: """ # full wrap around - machine = machine_from_size(24, 24) + machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 0)) self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (1, 4)) # no wrap around' - machine = machine_from_size(28, 28) + machine = MachineDataView.get_machine_version().create_machine(28, 28) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 24)) self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (25, 4)) # Horizontal wrap arounds - machine = machine_from_size(24, 28) + machine = MachineDataView.get_machine_version().create_machine(24, 28) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 24)) self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (1, 4)) # Vertical wrap arounds - machine = machine_from_size(28, 24) + machine = MachineDataView.get_machine_version().create_machine(28, 24) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 0)) self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (25, 4)) def test_no_boot(self): - machine = machine_from_size(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) with self.assertRaises(SpinnMachineException): machine.validate() def test_negative_x(self): - machine = machine_from_size(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) chip = self._create_chip(2, -1) machine.add_chip(chip) with self.assertRaises(SpinnMachineException): machine.validate() def test_negative_y(self): - machine = machine_from_size(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) chip = self._create_chip(-1, 3) machine.add_chip(chip) with self.assertRaises(SpinnMachineException): machine.validate() def test_big_x(self): - machine = virtual_machine(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) machine.get_chip_at(1, 1)._x = 9 with self.assertRaises(SpinnMachineException): machine.validate() def test_big_y(self): - machine = virtual_machine(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) machine.get_chip_at(1, 1)._y = 9 with self.assertRaises(SpinnMachineException): machine.validate() def test_weird_ethernet1(self): - machine = virtual_machine(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) machine.get_chip_at(1, 3)._ip_address = "1.2.3.4" with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_x(self): - machine = virtual_machine(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) machine.get_chip_at(0, 1)._nearest_ethernet_x = 1 with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_no_chip(self): - machine = virtual_machine(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) machine.get_chip_at(0, 1)._nearest_ethernet_x = 12 with self.assertRaises(SpinnMachineException): machine.validate() def test_getitem(self): - machine = virtual_machine(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) chip12 = machine[(1, 2)] self.assertEqual(chip12.x, 1) self.assertEqual(chip12.y, 2) @@ -325,7 +327,7 @@ def test_getitem(self): self.assertFalse((1, 9) in machine) def test_concentric_xys(self): - machine = virtual_machine(8, 8) + machine = MachineDataView.get_machine_version().create_machine(8, 8) machine.get_chip_at(1, 3) found = list(machine.concentric_xys(2, (2, 2))) expected = [ diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index 72ccf74f..9e6df3f7 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -15,8 +15,7 @@ import unittest from spinn_utilities.config_holder import set_config from spinn_machine.config_setup import unittest_setup -from spinn_machine import (Chip, Link, Machine, machine_from_size, Router, - virtual_machine) +from spinn_machine import (Chip, Link, Machine, Router, virtual_machine) from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException, SpinnMachineInvalidParameterException) @@ -1051,14 +1050,6 @@ def test_n_cores_2_2(self): n_cores = sum(chip.n_processors for chip in machine.chips) self.assertEqual(n_cores, 4 * 18) - def test_n_cores_weird(self): - # Can not do a weird VirtualMachine so use an empty one - machine = machine_from_size(5, 5) - n_cores = sum( - cores for (_, cores) in machine.get_xy_cores_by_ethernet(0, 0)) - self.assertEqual(n_cores, 5 * 5 * 18) - # Machine is empty so can not do sum of actual processors - if __name__ == '__main__': unittest.main() From 51d1ec1d457f6670c25715ccbed1618ce14722a1 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 10:17:58 +0100 Subject: [PATCH 08/24] minor fixes --- spinn_machine/version/abstract_version.py | 2 +- unittests/test_machine.py | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 0e972192..c869c1e2 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -163,7 +163,7 @@ def _verify_size(self, width, height): If the size is unexpected """ - def create_machine(self, width, height, origin): + def create_machine(self, width, height, origin=None): """ Creates a new Empty machine based on the width, height and version diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 3d24d80b..214bad4e 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -17,8 +17,7 @@ """ import unittest from spinn_utilities.config_holder import set_config -from spinn_machine import ( - Link, Router, Chip, machine_from_size) +from spinn_machine import Link, Router, Chip from spinn_machine import virtual_machine from spinn_machine.config_setup import unittest_setup from spinn_machine.data import MachineDataView @@ -289,37 +288,37 @@ def test_negative_y(self): machine.validate() def test_big_x(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine = virtual_machine(8, 8) machine.get_chip_at(1, 1)._x = 9 with self.assertRaises(SpinnMachineException): machine.validate() def test_big_y(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine = virtual_machine(8, 8) machine.get_chip_at(1, 1)._y = 9 with self.assertRaises(SpinnMachineException): machine.validate() def test_weird_ethernet1(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine = virtual_machine(8, 8) machine.get_chip_at(1, 3)._ip_address = "1.2.3.4" with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_x(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine = virtual_machine(8, 8) machine.get_chip_at(0, 1)._nearest_ethernet_x = 1 with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_no_chip(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine =virtual_machine(8, 8) machine.get_chip_at(0, 1)._nearest_ethernet_x = 12 with self.assertRaises(SpinnMachineException): machine.validate() def test_getitem(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine = virtual_machine(8, 8) chip12 = machine[(1, 2)] self.assertEqual(chip12.x, 1) self.assertEqual(chip12.y, 2) @@ -327,7 +326,7 @@ def test_getitem(self): self.assertFalse((1, 9) in machine) def test_concentric_xys(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine = virtual_machine(8, 8) machine.get_chip_at(1, 3) found = list(machine.concentric_xys(2, (2, 2))) expected = [ From 1ba147eeb9469cecdc487e75614abb009902606e Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 10:45:02 +0100 Subject: [PATCH 09/24] fix tests --- unittests/test_virtual_machine.py | 89 +++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index 9e6df3f7..0cc98278 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -31,7 +31,6 @@ class TestVirtualMachine(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) def _create_chip(self, x, y): # Create a list of processors. @@ -59,14 +58,16 @@ def _create_chip(self, x, y): nearest_ethernet_chip[1], None) def test_illegal_vms(self): - with self.assertRaises(SpinnMachineInvalidParameterException): + set_config("Machine", "version", 5) + with self.assertRaises(SpinnMachineException): virtual_machine(width=-1, height=2) - with self.assertRaises(SpinnMachineInvalidParameterException): + with self.assertRaises(SpinnMachineException): virtual_machine(width=2, height=-1) - with self.assertRaises(SpinnMachineInvalidParameterException): + with self.assertRaises(SpinnMachineException): virtual_machine(width=15, height=15) def test_version_2(self): + set_config("Machine", "version", 2) vm = virtual_machine(width=2, height=2) self.assertEqual(4, vm.n_chips) self.assertTrue(vm.is_chip_at(0, 0)) @@ -114,17 +115,8 @@ def test_version_2(self): self.assertEqual(4, count) self.assertEqual((2, 0), vm.get_unused_xy()) - def test_version_5(self): - vm = virtual_machine(width=8, height=8, validate=True) - self.assertEqual(48, vm.n_chips) - self.assertEqual(1, len(vm.ethernet_connected_chips)) - self.assertTrue(vm.is_chip_at(4, 4)) - self.assertFalse(vm.is_chip_at(0, 4)) - count = sum(1 for _chip in vm.chips for _link in _chip.router.links) - self.assertEqual(240, count) - self.assertEqual((0, 4), vm.get_unused_xy()) - - def test_8_by_8(self): + def test_version_5_8_by_8(self): + set_config("Machine", "version", 5) vm = virtual_machine(width=8, height=8, validate=True) self.assertEqual(48, vm.n_chips) self.assertEqual(1, len(vm.ethernet_connected_chips)) @@ -134,7 +126,8 @@ def test_8_by_8(self): count = sum(1 for _chip in vm.chips for _link in _chip.router.links) self.assertEqual(240, count) - def test_version_5_guess_12x12(self): + def test_version_5_12_by_12(self): + set_config("Machine", "version", 5) vm = virtual_machine(height=12, width=12, validate=True) self.assertEqual(144, vm.n_chips) self.assertEqual(3, len(vm.ethernet_connected_chips)) @@ -146,14 +139,8 @@ def test_version_5_guess_12x12(self): self.assertEqual(48, count) self.assertEqual((12, 0), vm.get_unused_xy()) - def test_version_5_guess_8x8(self): - vm = virtual_machine(height=8, width=8, validate=True) - self.assertEqual(48, vm.n_chips) - self.assertEqual(1, len(vm.ethernet_connected_chips)) - count = sum(1 for _chip in vm.chips for _link in _chip.router.links) - self.assertEqual(240, count) - def test_version_5_hole(self): + set_config("Machine", "version", 5) set_config("Machine", "down_chips", "3,3") vm = virtual_machine(height=8, width=8, validate=True) self.assertEqual(47, vm.n_chips) @@ -166,6 +153,7 @@ def test_version_5_hole(self): self.assertEqual(48, len(vm.local_xys)) def test_version_5_hole2(self): + set_config("Machine", "version", 5) set_config("Machine", "down_chips", "0,3") vm = virtual_machine(height=8, width=8, validate=True) self.assertEqual(47, vm.n_chips) @@ -179,6 +167,7 @@ def test_version_5_hole2(self): self.assertEqual((0, 4), vm.get_unused_xy()) def test_new_vm_with_monitor(self): + set_config("Machine", "version", 2) n_cpus = 13 vm = virtual_machine(2, 2, n_cpus_per_chip=n_cpus, validate=True) _chip = vm.get_chip_at(1, 1) @@ -194,6 +183,7 @@ def test_new_vm_with_monitor(self): self.assertEqual(1, monitors) def test_iter_chips(self): + set_config("Machine", "version", 2) vm = virtual_machine(2, 2) self.assertEqual(4, vm.n_chips) count = 0 @@ -202,6 +192,7 @@ def test_iter_chips(self): self.assertEqual(4, count) def test_down_chip(self): + set_config("Machine", "version", 2) down_chips = set() down_chips.add((1, 1)) set_config("Machine", "down_chips", "1,1") @@ -214,42 +205,47 @@ def test_down_chip(self): self.assertEqual(3, count) def test_add_existing_chip(self): + set_config("Machine", "version", 2) vm = virtual_machine(2, 2) _chip = self._create_chip(1, 1) with self.assertRaises(SpinnMachineAlreadyExistsException): vm.add_chip(_chip) def test_weird_size(self): - with self.assertRaises(SpinnMachineInvalidParameterException): + with self.assertRaises(SpinnMachineException): virtual_machine(5, 7) def test_12_n_plus4_12_m_4(self): + set_config("Machine", "version", 5) size_x = 12 * 5 size_y = 12 * 7 vm = virtual_machine(size_x + 4, size_y + 4, validate=True) self.assertEqual(size_x * size_y, vm.n_chips) def test_12_n_12_m(self): + set_config("Machine", "version", 5) size_x = 12 * 5 size_y = 12 * 7 vm = virtual_machine(size_x, size_y, validate=True) self.assertEqual(size_x * size_y, vm.n_chips) def test_bad_size(self): + set_config("Machine", "version", 5) size_x = 12 * 5 size_y = 12 * 7 - with self.assertRaises(SpinnMachineInvalidParameterException): + with self.assertRaises(SpinnMachineException): virtual_machine(size_x + 1, size_y, validate=True) def test_none_size(self): + set_config("Machine", "version", 5) size_x = 12 * 5 size_y = None - with self.assertRaises(SpinnMachineInvalidParameterException): + with self.assertRaises(SpinnMachineException): virtual_machine(size_x, size_y, validate=True) def test_add__chip(self): + set_config("Machine", "version", 2) vm = virtual_machine(2, 2) - _chip = self._create_chip(2, 2) vm.add_chip(_chip) self.assertEqual(5, vm.n_chips) @@ -267,6 +263,7 @@ def test_add__chip(self): self.assertEqual(5, count) def test_add_high_chip_with_down(self): + set_config("Machine", "version", 2) set_config("Machine", "down_chips", "1,1") vm = virtual_machine(2, 2) self.assertEqual(3, vm.n_chips) @@ -291,6 +288,7 @@ def test_add_high_chip_with_down(self): self.assertEqual(4, count) def test_add_low_chip_with_down(self): + set_config("Machine", "version", 2) set_config("Machine", "down_chips", "1,1") vm = virtual_machine(2, 2) self.assertEqual(3, vm.n_chips) @@ -313,6 +311,7 @@ def test_add_low_chip_with_down(self): self.assertEqual(4, count) def test_chips(self): + set_config("Machine", "version", 2) vm = virtual_machine(2, 2) count = 0 for _chip in vm.chips: @@ -320,6 +319,7 @@ def test_chips(self): self.assertEqual(count, 4) def test_ethernet_chips_exist(self): + set_config("Machine", "version", 5) vm = virtual_machine(width=48, height=24) for eth_chip in vm._ethernet_connected_chips: self.assertTrue(vm.get_chip_at(eth_chip.x, eth_chip.y), @@ -328,10 +328,12 @@ def test_ethernet_chips_exist(self): .format(eth_chip.x, eth_chip.y)) def test_boot_chip(self): + set_config("Machine", "version", 2) vm = virtual_machine(2, 2) self.assertNotEqual(vm.boot_chip, None) def test_get_chips_on_boards(self): + set_config("Machine", "version", 5) vm = virtual_machine(width=24, height=36) # check each chip appears only once on the entire board count00 = 0 @@ -365,6 +367,7 @@ def _assert_fpga_link(machine, fpga, fpga_link, x, y, link_id, ip=None): assert link.connected_link == link_id def test_fpga_links_single_board(self): + set_config("Machine", "version", 5) machine = virtual_machine(width=8, height=8) machine.add_fpga_links() self._assert_fpga_link(machine, 0, 0, 7, 3, 0) @@ -422,6 +425,7 @@ def test_fpga_links_single_board(self): self._assert_fpga_link(machine, 2, 15, 7, 3, 1) def test_fpga_links_3_board(self): + set_config("Machine", "version", 5) # A List of links, one for each side of each board in a 3-board toroid fpga_links = [("127.0.0.0", 0, 5, 5, 1, 5), ("127.0.0.0", 0, 12, 2, 0, 4), @@ -451,10 +455,12 @@ def test_fpga_links_3_board(self): self._assert_fpga_link(machine, fpga, fpga_link, x, y, link, ip) def test_big(self): + set_config("Machine", "version", 5) virtual_machine( width=240, height=240, validate=True) def test_size_2_2(self): + set_config("Machine", "version", 2) machine = virtual_machine(2, 2, validate=True) ethernet = machine.get_chip_at(0, 0) chips = set(machine.get_existing_xys_on_board(ethernet)) @@ -474,6 +480,7 @@ def test_size_2_2(self): self.assertEqual(4, len(machine.local_xys)) def test_48_28(self): + set_config("Machine", "version", 5) machine = virtual_machine(48, 24, validate=True) global_xys = set() for chip in machine.chips: @@ -488,6 +495,7 @@ def test_48_28(self): self.assertEqual(48, len(machine.local_xys)) def test_48_24(self): + set_config("Machine", "version", 5) machine = virtual_machine(48, 24, validate=True) global_xys = set() for chip in machine.chips: @@ -502,6 +510,7 @@ def test_48_24(self): self.assertEqual(48, len(machine.local_xys)) def test_52_28(self): + set_config("Machine", "version", 5) machine = virtual_machine(48, 24, validate=True) global_xys = set() for chip in machine.chips: @@ -516,6 +525,7 @@ def test_52_28(self): self.assertEqual(48, len(machine.local_xys)) def test_52_24(self): + set_config("Machine", "version", 5) machine = virtual_machine(48, 24, validate=True) global_xys = set() for chip in machine.chips: @@ -530,6 +540,7 @@ def test_52_24(self): self.assertEqual(48, len(machine.local_xys)) def test_size_2_2_hole(self): + set_config("Machine", "version", 2) hole = [(1, 1)] set_config("Machine", "down_chips", "1,1") machine = virtual_machine(2, 2, validate=True) @@ -547,6 +558,7 @@ def test_size_2_2_hole(self): self.assertEqual(3, count) def test_fullwrap_holes(self): + set_config("Machine", "version", 5) hole = [(1, 1), (7, 7), (8, 1), (8, 10), (1, 8), (9, 6)] hole_str = ":".join([f"{x},{y}" for x, y in hole]) set_config("Machine", "down_chips", hole_str) @@ -597,6 +609,7 @@ def test_fullwrap_holes(self): self.assertEqual(46, count) def test_horizontal_wrap_holes(self): + set_config("Machine", "version", 5) hole = [(1, 1), (7, 7), (8, 13), (8, 10), (1, 8), (9, 6)] hole_str = ":".join([f"{x},{y}" for x, y in hole]) set_config("Machine", "down_chips", hole_str) @@ -647,6 +660,7 @@ def test_horizontal_wrap_holes(self): self.assertEqual(46, count) def test_vertical_wrap_holes(self): + set_config("Machine", "version", 5) hole = [(1, 1), (7, 7), (8, 1), (8, 10), (13, 8), (9, 6)] hole_str = ":".join([f"{x},{y}" for x, y in hole]) set_config("Machine", "down_chips", hole_str) @@ -697,6 +711,7 @@ def test_vertical_wrap_holes(self): self.assertEqual(46, count) def test_no_wrap_holes(self): + set_config("Machine", "version", 5) hole = [(1, 1), (7, 7), (8, 13), (8, 10), (13, 8), (9, 6)] hole_str = ":".join([f"{x},{y}" for x, y in hole]) set_config("Machine", "down_chips", hole_str) @@ -752,6 +767,7 @@ def _check_path(self, source, target, path, width, height): self.assertEqual(target, new_target, "{}{}".format(source, path)) def test_nowrap_shortest_path(self): + set_config("Machine", "version", 5) machine = virtual_machine(16, 28, validate=True) for source in machine.chip_coordinates: for target in machine.chip_coordinates: @@ -765,6 +781,7 @@ def test_nowrap_shortest_path(self): self._check_path(source, target, path, 1000000, 1000000) def test_fullwrap_shortest_path(self): + set_config("Machine", "version", 5) width = 12 height = 24 machine = virtual_machine(width, height, validate=True) @@ -781,6 +798,7 @@ def test_fullwrap_shortest_path(self): self._check_path(source, target, path, width, height) def test_hoizontal_wrap_shortest_path(self): + set_config("Machine", "version", 5) width = 12 height = 16 machine = virtual_machine(width, height, validate=False) @@ -805,6 +823,7 @@ def test_hoizontal_wrap_shortest_path(self): self._check_path(source, target, path, width, height) def test_vertical_wrap_shortest_path(self): + set_config("Machine", "version", 5) width = 16 height = 12 machine = virtual_machine(width, height, validate=False) @@ -829,6 +848,7 @@ def test_vertical_wrap_shortest_path(self): self._check_path(source, target, path, width, height) def test_minimize(self): + set_config("Machine", "version", 3) machine = virtual_machine(2, 2, validate=False) for x in range(-3, 3): for y in range(-3, 3): @@ -837,6 +857,7 @@ def test_minimize(self): self.assertEqual(min1, min2) def test_unreachable_incoming_chips(self): + set_config("Machine", "version", 5) machine = virtual_machine(8, 8) # Delete links incoming to 3, 3 @@ -849,6 +870,7 @@ def test_unreachable_incoming_chips(self): self.assertListEqual([(3, 3)], unreachable) def test_unreachable_outgoing_chips(self): + set_config("Machine", "version", 5) machine = virtual_machine(8, 8) # Delete links outgoing from 3, 3 @@ -859,6 +881,7 @@ def test_unreachable_outgoing_chips(self): self.assertListEqual([(3, 3)], unreachable) def test_unreachable_incoming_local_chips(self): + set_config("Machine", "version", 5) down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) set_config("Machine", "down_chips", down_str) @@ -867,6 +890,7 @@ def test_unreachable_incoming_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_unreachable_outgoing_local_chips(self): + set_config("Machine", "version", 5) down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) set_config("Machine", "down_chips", down_str) @@ -875,6 +899,7 @@ def test_unreachable_outgoing_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_repair_with_local_orphan(self): + set_config("Machine", "version", 5) down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) set_config("Machine", "down_chips", down_str) @@ -888,6 +913,7 @@ def test_repair_with_local_orphan(self): self.assertFalse(repaired.is_chip_at(8, 7)) def test_repair_with_one_way_links_different_boards(self): + set_config("Machine", "version", 5) machine = virtual_machine(12, 12) # Delete some links between boards down_links = [ @@ -902,6 +928,7 @@ def test_repair_with_one_way_links_different_boards(self): self.assertIsNotNone(new_machine) def test_oneway_link_no_repair(self): + set_config("Machine", "version", 5) machine = virtual_machine(8, 8) # Delete some random links @@ -918,6 +945,7 @@ def test_oneway_link_no_repair(self): self.assertIsNotNone(new_machine) def test_removed_chip_repair(self): + set_config("Machine", "version", 5) machine = virtual_machine(8, 8) del machine._chips[(3, 3)] @@ -927,6 +955,7 @@ def test_removed_chip_repair(self): self.assertFalse(new_machine.is_link_at(2, 2, 1)) def test_ignores(self): + set_config("Machine", "version", 5) set_config("Machine", "down_chips", "2,2:4,4:6,6,ignored_ip") set_config("Machine", "down_cores", "1,1,1:3,3,3: 5,5,-5:7,7,7,ignored_ip:0,0,5-10") @@ -988,6 +1017,7 @@ def test_bad_ignores(self): self.assertTrue("downed_link" in str(ex)) def test_n_cores_full_wrap(self): + set_config("Machine", "version", 5) machine = virtual_machine(12, 12) n_cores = sum( n_cores @@ -997,6 +1027,7 @@ def test_n_cores_full_wrap(self): self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) def test_n_cores_no_wrap(self): + set_config("Machine", "version", 5) machine = virtual_machine(16, 16) n_cores = sum( n_cores @@ -1019,6 +1050,7 @@ def test_n_cores_no_wrap(self): self.assertEqual(where, 'No chip 15, 15 found') def test_n_cores_horizontal_wrap(self): + set_config("Machine", "version", 5) machine = virtual_machine(12, 16) n_cores = sum( n_cores @@ -1028,6 +1060,7 @@ def test_n_cores_horizontal_wrap(self): self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) def test_n_cores_vertical_wrap(self): + set_config("Machine", "version", 5) machine = virtual_machine(12, 16) n_cores = sum(chip.n_processors for chip in machine.chips) self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) @@ -1035,6 +1068,7 @@ def test_n_cores_vertical_wrap(self): self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) def test_n_cores_8_8(self): + set_config("Machine", "version", 5) machine = virtual_machine(8, 8) n_cores = sum( cores for (_, cores) in machine.get_xy_cores_by_ethernet(0, 0)) @@ -1043,6 +1077,7 @@ def test_n_cores_8_8(self): self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD) def test_n_cores_2_2(self): + set_config("Machine", "version", 2) machine = virtual_machine(2, 2) n_cores = sum( cores for (_, cores) in machine.get_xy_cores_by_ethernet(0, 0)) From 8165462961f6945f146139143dacdea6a7f416a4 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 11:00:52 +0100 Subject: [PATCH 10/24] flake8 --- spinn_machine/chip.py | 1 - spinn_machine/machine_factory.py | 4 ---- spinn_machine/version/abstract_version.py | 13 ++++++++----- spinn_machine/virtual_machine.py | 6 ++---- unittests/test_machine.py | 13 +++++++------ unittests/test_virtual_machine.py | 3 +-- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/spinn_machine/chip.py b/spinn_machine/chip.py index 1452cf63..17acb8ca 100644 --- a/spinn_machine/chip.py +++ b/spinn_machine/chip.py @@ -14,7 +14,6 @@ from spinn_utilities.ordered_set import OrderedSet from spinn_machine.data import MachineDataView -from .machine import Machine from .processor import Processor standard_processors = {} diff --git a/spinn_machine/machine_factory.py b/spinn_machine/machine_factory.py index d2229e30..d71d155a 100644 --- a/spinn_machine/machine_factory.py +++ b/spinn_machine/machine_factory.py @@ -18,10 +18,6 @@ from spinn_utilities.log import FormatAdapter from spinn_machine import (Chip, Router) from spinn_machine.data import MachineDataView -from .no_wrap_machine import NoWrapMachine -from .horizontal_wrap_machine import HorizontalWrapMachine -from .vertical_wrap_machine import VerticalWrapMachine -from .full_wrap_machine import FullWrapMachine from .exceptions import SpinnMachineException logger = FormatAdapter(logging.getLogger(__name__)) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index c869c1e2..63f96bdb 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -82,7 +82,8 @@ def __set_max_sdram_per_chip(self, max_sdram_per_chip): if max_sdram is not None: if max_sdram > self._max_sdram_per_chip: logger.info( - f"Ignoring csg setting [Machine]max_sdram_allowed_per_chip " + f"Ignoring csg setting " + f"[Machine]max_sdram_allowed_per_chip " f"{max_sdram} as it is larger than " f"{self._max_sdram_per_chip} which is the default for a " f"{self.name} board ") @@ -157,8 +158,8 @@ def _verify_size(self, width, height): """ Adds the width and height checks that depend on the version - :param int width: - :param int height: + :param int width: + :param int height: :raise SpinnMachineException: If the size is unexpected """ @@ -168,7 +169,8 @@ def create_machine(self, width, height, origin=None): Creates a new Empty machine based on the width, height and version :param int width: The width of the machine excluding any virtual chips - :param int height: The height of the machine excluding any virtual chips + :param int height: + The height of the machine excluding any virtual chips :param origin: Extra information about how this machine was created to be used in the str method. Example "``Virtual``" or "``Json``" :type origin: str or None @@ -186,7 +188,8 @@ def _create_machine(self, width, height, origin): Creates a new Empty machine based on the width, height and version :param int width: The width of the machine excluding any virtual chips - :param int height: The height of the machine excluding any virtual chips + :param int height: + The height of the machine excluding any virtual chips :param origin: Extra information about how this machine was created to be used in the str method. Example "``Virtual``" or "``Json``" :type origin: str or None diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index 363731f6..745a7252 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -14,14 +14,12 @@ from collections import defaultdict import logging -from spinn_utilities.config_holder import get_config_int, get_config_str +from spinn_utilities.config_holder import get_config_str from spinn_utilities.log import FormatAdapter from .chip import Chip -from .exceptions import SpinnMachineInvalidParameterException from .router import Router from .link import Link from .spinnaker_triad_geometry import SpiNNakerTriadGeometry -from spinn_machine import Machine from spinn_machine.data import MachineDataView from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink @@ -38,7 +36,7 @@ def virtual_machine( :param int n_cpus_per_chip: The number of CPUs to put on each chip :param bool validate: if True will call the machine validate function :returns: a virtual machine (that cannot execute code) - :rtype: Machine + :rtype: ~spinn_machine.Machine """ factory = _VirtualMachine(width, height, n_cpus_per_chip, validate) diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 214bad4e..cae7a75a 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -78,7 +78,8 @@ def test_create_new_machine(self): self.assertEqual(new_machine.boot_chip.ip_address, "127.0.0.0") self.assertEqual(new_machine.n_chips, 48) self.assertEqual(len(new_machine), 48) - self.assertEqual(next(x[1].ip_address for x in new_machine), "127.0.0.0") + self.assertEqual( + next(x[1].ip_address for x in new_machine), "127.0.0.0") self.assertEqual(next(new_machine.chip_coordinates), (0, 0)) self.assertEqual("856 cores and 120.0 links", new_machine.cores_and_link_output_string()) @@ -145,13 +146,13 @@ def test_machine_big_x(self): :rtype: None """ - new_machine = MachineDataView.get_machine_version().create_machine(8, 8) - new_machine.add_chip(self._create_chip(0, 0)) + machine = MachineDataView.get_machine_version().create_machine(8, 8) + machine.add_chip(self._create_chip(0, 0)) # the add does not have the safety code - new_machine.add_chip(self._create_chip(10, 2)) + machine.add_chip(self._create_chip(10, 2)) # however the validate does try: - new_machine.validate() + machine.validate() except SpinnMachineException as ex: self.assertIn("has an x larger than width 8", str(ex)) @@ -312,7 +313,7 @@ def test_bad_ethernet_chip_x(self): machine.validate() def test_bad_ethernet_chip_no_chip(self): - machine =virtual_machine(8, 8) + machine = virtual_machine(8, 8) machine.get_chip_at(0, 1)._nearest_ethernet_x = 12 with self.assertRaises(SpinnMachineException): machine.validate() diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index 0cc98278..7782ff3d 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -17,8 +17,7 @@ from spinn_machine.config_setup import unittest_setup from spinn_machine import (Chip, Link, Machine, Router, virtual_machine) from spinn_machine.exceptions import ( - SpinnMachineException, SpinnMachineAlreadyExistsException, - SpinnMachineInvalidParameterException) + SpinnMachineException, SpinnMachineAlreadyExistsException) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink from spinn_machine.machine_factory import machine_repair from .geometry import (to_xyz, shortest_mesh_path_length, From d2a5394b40521866ce3e7d055356f80131dba041 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 11:21:54 +0100 Subject: [PATCH 11/24] Version n_chips_per_board --- spinn_machine/machine.py | 2 -- spinn_machine/version/abstract_version.py | 10 ++++++++++ spinn_machine/version/version_3.py | 4 ++++ spinn_machine/version/version_5.py | 4 ++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 140617bf..92f32a4d 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -38,8 +38,6 @@ class Machine(object, metaclass=AbstractBase): to determine the correct machine class. """ - MAX_CHIPS_PER_48_BOARD = 48 - # other useful magic numbers for machines SIZE_X_OF_ONE_BOARD = 8 SIZE_Y_OF_ONE_BOARD = 8 diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 63f96bdb..6486dbb1 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -135,6 +135,16 @@ def max_sdram_per_chip(self): """ return self._max_sdram_per_chip + @abstractproperty + def n_chips_per_board(self): + """ + The normal number of Chips on each board of this version + + Remember that will the board may have dead or excluded chips + + :rtype: int + """ + def verify_size(self, width, height): """ Checks that the width and height are allowed for this version diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index 00c2bcf0..ad89272d 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -32,6 +32,10 @@ class Version3(VersionSpin1): def name(self): return "Spin1 4 Chip" + @overrides(VersionSpin1.n_chips_per_board) + def n_chips_per_board(self): + return 4 + @overrides(VersionSpin1._verify_size) def _verify_size(self, width, height): if width != 2: diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index 09c4513e..e0cd33cc 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -36,6 +36,10 @@ class Version5(VersionSpin1): def name(self): return "Spin1 48 Chip" + @overrides(VersionSpin1.n_chips_per_board) + def n_chips_per_board(self): + return 48 + @overrides(VersionSpin1._verify_size) def _verify_size(self, width, height): if width == height == 8: From 5359dcc60de79db0afadd6cb18080dbb2a2636f4 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 12:59:02 +0100 Subject: [PATCH 12/24] Version n_chips_per_board --- spinn_machine/full_wrap_machine.py | 20 ++++-------- spinn_machine/horizontal_wrap_machine.py | 8 ++--- spinn_machine/machine.py | 40 ++++++----------------- spinn_machine/no_wrap_machine.py | 19 ++++------- spinn_machine/version/abstract_version.py | 23 ++++++++++++- spinn_machine/version/version_3.py | 11 ++++--- spinn_machine/version/version_5.py | 28 ++++++++++++---- spinn_machine/vertical_wrap_machine.py | 8 ++--- unittests/test_virtual_machine.py | 23 ++++++------- 9 files changed, 92 insertions(+), 88 deletions(-) diff --git a/spinn_machine/full_wrap_machine.py b/spinn_machine/full_wrap_machine.py index d0dfa3fa..4923d438 100644 --- a/spinn_machine/full_wrap_machine.py +++ b/spinn_machine/full_wrap_machine.py @@ -25,28 +25,20 @@ def multiple_48_chip_boards(self): @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_x = (x + ethernet_x) % self._width chip_y = (y + ethernet_y) % self._height yield (chip_x, chip_y) @overrides(Machine.get_xy_cores_by_ethernet) def get_xy_cores_by_ethernet(self, ethernet_x, ethernet_y): - if (self._width == self._height == 2): - version = MachineDataView.get_machine_version() - n_cores = version.max_cores_per_chip - n_cores = MachineDataView.get_machine_version().max_cores_per_chip - for (x, y) in self._local_xys: - # if ethernet_x/y != 0 GIGO mode so ignore ethernet - yield (x, y), n_cores - else: - for (x, y), n_cores in self.CHIPS_PER_BOARD.items(): - yield (((x + ethernet_x) % self._width, - (y + ethernet_y) % self._height), n_cores) + for (x, y), n_cores in self._chip_core_map.items(): + yield (((x + ethernet_x) % self._width, + (y + ethernet_y) % self._height), n_cores) @overrides(Machine.get_existing_xys_by_ethernet) def get_existing_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = ((x + ethernet_x) % self._width, (y + ethernet_y) % self._height) if chip_xy in self._chips: @@ -54,7 +46,7 @@ def get_existing_xys_by_ethernet(self, ethernet_x, ethernet_y): @overrides(Machine.get_down_xys_by_ethernet) def get_down_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = ((x + ethernet_x) % self._width, (y + ethernet_y) % self._height) if (chip_xy) not in self._chips: diff --git a/spinn_machine/horizontal_wrap_machine.py b/spinn_machine/horizontal_wrap_machine.py index ff993148..f5bbd242 100644 --- a/spinn_machine/horizontal_wrap_machine.py +++ b/spinn_machine/horizontal_wrap_machine.py @@ -24,19 +24,19 @@ def multiple_48_chip_boards(self): @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_x = (x + ethernet_x) % self._width chip_y = (y + ethernet_y) yield (chip_x, chip_y) @overrides(Machine.get_xy_cores_by_ethernet) def get_xy_cores_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y), n_cores in self.CHIPS_PER_BOARD.items(): + for (x, y), n_cores in self._chip_core_map.items(): yield ((x + ethernet_x) % self._width, (y + ethernet_y)), n_cores @overrides(Machine.get_existing_xys_by_ethernet) def get_existing_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = ((x + ethernet_x) % self._width, (y + ethernet_y)) if chip_xy in self._chips: @@ -44,7 +44,7 @@ def get_existing_xys_by_ethernet(self, ethernet_x, ethernet_y): @overrides(Machine.get_down_xys_by_ethernet) def get_down_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = ((x + ethernet_x) % self._width, (y + ethernet_y)) if (chip_xy) not in self._chips: diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 92f32a4d..0e834abe 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -31,11 +31,6 @@ class Machine(object, metaclass=AbstractBase): * ``y`` is the y-coordinate of a chip, * ``chip`` is the chip with the given ``(x, y)`` coordinates. - Use - :py:func:`~spinn_machine.machine_from_chips` - and - :py:func:`~spinn_machine.machine_from_size` - to determine the correct machine class. """ # other useful magic numbers for machines @@ -46,29 +41,19 @@ class Machine(object, metaclass=AbstractBase): # coordinates down the given link (0-5) LINK_ADD_TABLE = [(1, 0), (1, 1), (0, 1), (-1, 0), (-1, -1), (0, -1)] - CHIPS_PER_BOARD = { - (0, 0): 18, (0, 1): 18, (0, 2): 18, (0, 3): 18, (1, 0): 18, (1, 1): 17, - (1, 2): 18, (1, 3): 17, (1, 4): 18, (2, 0): 18, (2, 1): 18, (2, 2): 18, - (2, 3): 18, (2, 4): 18, (2, 5): 18, (3, 0): 18, (3, 1): 17, (3, 2): 18, - (3, 3): 17, (3, 4): 18, (3, 5): 17, (3, 6): 18, (4, 0): 18, (4, 1): 18, - (4, 2): 18, (4, 3): 18, (4, 4): 18, (4, 5): 18, (4, 6): 18, (4, 7): 18, - (5, 1): 18, (5, 2): 17, (5, 3): 18, (5, 4): 17, (5, 5): 18, (5, 6): 17, - (5, 7): 18, (6, 2): 18, (6, 3): 18, (6, 4): 18, (6, 5): 18, (6, 6): 18, - (6, 7): 18, (7, 3): 18, (7, 4): 18, (7, 5): 18, (7, 6): 18, (7, 7): 18 - } - BOARD_48_CHIPS = list(CHIPS_PER_BOARD.keys()) ROUTER_ENTRIES = 1023 __slots__ = ( "_boot_ethernet_address", + # A map off the expected x, y coordinates on a standard board to + # the most likely number of cores on that chip. + "_chip_core_map", "_chips", "_ethernet_connected_chips", "_fpga_links", # Declared height of the machine # This can not be changed "_height", - # List of the possible chips (x,y) on each board of the machine - "_local_xys", # Extra information about how this machine was created # to be used in the str method "_origin", @@ -78,11 +63,14 @@ class Machine(object, metaclass=AbstractBase): "_width" ) - def __init__(self, width, height, origin=None): + def __init__(self, width, height, chip_core_map, origin=None): """ :param int width: The width of the machine excluding :param int height: The height of the machine + :param dict((int, int), int) chip_core_map: + A map off the expected x,y coordinates on a standard board to + the most likely number of cores on that chip. :param str origin: Extra information about how this machine was created to be used in the str method. Example "``Virtual``" or "``Json``" :raise SpinnMachineAlreadyExistsException: @@ -92,15 +80,7 @@ def __init__(self, width, height, origin=None): assert isinstance(origin, str) self._width = width self._height = height - - if (self._width == self._height == 8) or \ - self.multiple_48_chip_boards(): - self._local_xys = self.BOARD_48_CHIPS - else: - self._local_xys = [] - for x in range(width): - for y in range(height): - self._local_xys.append((x, y)) + self._chip_core_map = chip_core_map # The list of chips with Ethernet connections self._ethernet_connected_chips = list() @@ -510,7 +490,7 @@ def validate(self): raise SpinnMachineException( f"{chip} has an invalid ethernet chip") local_xy = self.get_local_xy(chip) - if local_xy not in self._local_xys: + if local_xy not in self._chip_core_map: raise SpinnMachineException( f"{chip} has an unexpected local xy of {local_xy}") @@ -1172,7 +1152,7 @@ def local_xys(self): :rtype: iterable(tuple(int,int)) """ - return self._local_xys + return self._chip_core_map.keys() def get_unused_xy(self): """ diff --git a/spinn_machine/no_wrap_machine.py b/spinn_machine/no_wrap_machine.py index e1f6e966..37d59ec3 100644 --- a/spinn_machine/no_wrap_machine.py +++ b/spinn_machine/no_wrap_machine.py @@ -25,32 +25,25 @@ def multiple_48_chip_boards(self): @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: yield (x + ethernet_x, y + ethernet_y) @overrides(Machine.get_xy_cores_by_ethernet) def get_xy_cores_by_ethernet(self, ethernet_x, ethernet_y): - if (self._width == self._height == 8) or \ - self.multiple_48_chip_boards(): - for (x, y), n_cores in self.CHIPS_PER_BOARD.items(): - # if ethernet_x/y != 0 GIGO mode so ignore ethernet - yield ((x + ethernet_x, y + ethernet_y), n_cores) - else: - # covers weird sizes - n_cores = MachineDataView.get_machine_version().max_cores_per_chip - for (x, y) in self._local_xys: - yield ((x, y), n_cores) + for (x, y), n_cores in self._chip_core_map.items(): + # if ethernet_x/y != 0 GIGO mode so ignore ethernet + yield ((x + ethernet_x, y + ethernet_y), n_cores) @overrides(Machine.get_existing_xys_by_ethernet) def get_existing_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = (x + ethernet_x, y + ethernet_y) if chip_xy in self._chips: yield chip_xy @overrides(Machine.get_down_xys_by_ethernet) def get_down_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = ((x + ethernet_x), (y + ethernet_y)) if (chip_xy) not in self._chips: diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 6486dbb1..7fe36eb1 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -135,7 +135,7 @@ def max_sdram_per_chip(self): """ return self._max_sdram_per_chip - @abstractproperty + @property def n_chips_per_board(self): """ The normal number of Chips on each board of this version @@ -144,6 +144,27 @@ def n_chips_per_board(self): :rtype: int """ + return len(self.chip_core_map) + + @property + def expected_xys(self): + """ + List of the standard xy coordinates of Chips for this version + + Remember that will the board may have dead or excluded chips + + :return: + """ + return list(self.chip_core_map.keys()) + + @abstractproperty + def chip_core_map(self): + """ + A map off the expected x,y coordinates on a standard board to + the most likely number of cores on that chip. + + :rtype: dict((int, int), int) + """ def verify_size(self, width, height): """ diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index ad89272d..5188e262 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -17,6 +17,8 @@ from spinn_machine.full_wrap_machine import FullWrapMachine from spinn_machine.exceptions import SpinnMachineException +CHIPS_PER_BOARD = {(0, 0): 18, (0, 1): 18, (1, 0): 18, (1, 1): 18} + class Version3(VersionSpin1): """ @@ -32,9 +34,10 @@ class Version3(VersionSpin1): def name(self): return "Spin1 4 Chip" - @overrides(VersionSpin1.n_chips_per_board) - def n_chips_per_board(self): - return 4 + @property + @overrides(VersionSpin1.chip_core_map) + def chip_core_map(self): + return CHIPS_PER_BOARD @overrides(VersionSpin1._verify_size) def _verify_size(self, width, height): @@ -45,4 +48,4 @@ def _verify_size(self, width, height): @overrides(VersionSpin1._create_machine) def _create_machine(self, width, height, origin): - return FullWrapMachine(width, height, origin) + return FullWrapMachine(width, height, CHIPS_PER_BOARD, origin) diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index e0cd33cc..db11ac0f 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -21,6 +21,17 @@ from .version_spin1 import VersionSpin1 +CHIPS_PER_BOARD = { + (0, 0): 18, (0, 1): 18, (0, 2): 18, (0, 3): 18, (1, 0): 18, (1, 1): 17, + (1, 2): 18, (1, 3): 17, (1, 4): 18, (2, 0): 18, (2, 1): 18, (2, 2): 18, + (2, 3): 18, (2, 4): 18, (2, 5): 18, (3, 0): 18, (3, 1): 17, (3, 2): 18, + (3, 3): 17, (3, 4): 18, (3, 5): 17, (3, 6): 18, (4, 0): 18, (4, 1): 18, + (4, 2): 18, (4, 3): 18, (4, 4): 18, (4, 5): 18, (4, 6): 18, (4, 7): 18, + (5, 1): 18, (5, 2): 17, (5, 3): 18, (5, 4): 17, (5, 5): 18, (5, 6): 17, + (5, 7): 18, (6, 2): 18, (6, 3): 18, (6, 4): 18, (6, 5): 18, (6, 6): 18, + (6, 7): 18, (7, 3): 18, (7, 4): 18, (7, 5): 18, (7, 6): 18, (7, 7): 18 +} + class Version5(VersionSpin1): """ @@ -36,9 +47,10 @@ class Version5(VersionSpin1): def name(self): return "Spin1 48 Chip" - @overrides(VersionSpin1.n_chips_per_board) - def n_chips_per_board(self): - return 48 + @property + @overrides(VersionSpin1.chip_core_map) + def chip_core_map(self): + return CHIPS_PER_BOARD @overrides(VersionSpin1._verify_size) def _verify_size(self, width, height): @@ -58,11 +70,13 @@ def _verify_size(self, width, height): def _create_machine(self, width, height, origin): if width % 12 == 0: if height % 12 == 0: - return FullWrapMachine(width, height, origin) + return FullWrapMachine(width, height, CHIPS_PER_BOARD, origin) else: - return HorizontalWrapMachine(width, height, origin) + return HorizontalWrapMachine( + width, height, CHIPS_PER_BOARD, origin) else: if height % 12 == 0: - return VerticalWrapMachine(width, height, origin) + return VerticalWrapMachine( + width, height, CHIPS_PER_BOARD, origin) else: - return NoWrapMachine(width, height, origin) + return NoWrapMachine(width, height, CHIPS_PER_BOARD, origin) diff --git a/spinn_machine/vertical_wrap_machine.py b/spinn_machine/vertical_wrap_machine.py index 79ad5588..a90aed1e 100644 --- a/spinn_machine/vertical_wrap_machine.py +++ b/spinn_machine/vertical_wrap_machine.py @@ -24,19 +24,19 @@ def multiple_48_chip_boards(self): @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_x = (x + ethernet_x) chip_y = (y + ethernet_y) % self._height yield (chip_x, chip_y) @overrides(Machine.get_xy_cores_by_ethernet) def get_xy_cores_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y), n_cores in self.CHIPS_PER_BOARD.items(): + for (x, y), n_cores in self._chip_core_map.items(): yield ((x + ethernet_x), (y + ethernet_y) % self._height), n_cores @overrides(Machine.get_existing_xys_by_ethernet) def get_existing_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = ((x + ethernet_x), (y + ethernet_y) % self._height) if chip_xy in self._chips: @@ -44,7 +44,7 @@ def get_existing_xys_by_ethernet(self, ethernet_x, ethernet_y): @overrides(Machine.get_down_xys_by_ethernet) def get_down_xys_by_ethernet(self, ethernet_x, ethernet_y): - for (x, y) in self._local_xys: + for (x, y) in self._chip_core_map: chip_xy = ((x + ethernet_x), (y + ethernet_y) % self._height) if (chip_xy) not in self._chips: diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index 7782ff3d..daefcb55 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -20,13 +20,14 @@ SpinnMachineException, SpinnMachineAlreadyExistsException) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink from spinn_machine.machine_factory import machine_repair +from spinn_machine.version.version_5 import CHIPS_PER_BOARD from .geometry import (to_xyz, shortest_mesh_path_length, shortest_torus_path_length, minimise_xyz) class TestVirtualMachine(unittest.TestCase): - TYPICAL_N_CORES_PER_BOARD = sum(Machine.CHIPS_PER_BOARD.values()) + VERSION_5_N_CORES_PER_BOARD = sum(CHIPS_PER_BOARD.values()) def setUp(self): unittest_setup() @@ -1021,9 +1022,9 @@ def test_n_cores_full_wrap(self): n_cores = sum( n_cores for (_, n_cores) in machine.get_xy_cores_by_ethernet(0, 0)) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD) n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD * 3) def test_n_cores_no_wrap(self): set_config("Machine", "version", 5) @@ -1031,9 +1032,9 @@ def test_n_cores_no_wrap(self): n_cores = sum( n_cores for (_, n_cores) in machine.get_xy_cores_by_ethernet(0, 0)) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD) n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD * 3) chip34 = machine.get_chip_at(3, 4) where = machine.where_is_chip(chip34) self.assertEqual( @@ -1054,26 +1055,26 @@ def test_n_cores_horizontal_wrap(self): n_cores = sum( n_cores for (_, n_cores) in machine.get_xy_cores_by_ethernet(0, 0)) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD) n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD * 3) def test_n_cores_vertical_wrap(self): set_config("Machine", "version", 5) machine = virtual_machine(12, 16) n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD * 3) n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD * 3) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD * 3) def test_n_cores_8_8(self): set_config("Machine", "version", 5) machine = virtual_machine(8, 8) n_cores = sum( cores for (_, cores) in machine.get_xy_cores_by_ethernet(0, 0)) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD) n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, self.TYPICAL_N_CORES_PER_BOARD) + self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD) def test_n_cores_2_2(self): set_config("Machine", "version", 2) From 6e8eae6d585159b3dd9077b458bb01a443cf967b Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 13:30:02 +0100 Subject: [PATCH 13/24] version.get_potential_ethernet_chip --- spinn_machine/version/abstract_version.py | 16 ++++++++++++++++ spinn_machine/version/version_3.py | 4 ++++ spinn_machine/version/version_5.py | 7 ++++++- spinn_machine/virtual_machine.py | 9 +++------ 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 7fe36eb1..eecc8835 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -166,6 +166,22 @@ def chip_core_map(self): :rtype: dict((int, int), int) """ + @abstractmethod + def get_potential_ethernet_chips(self, width, height): + """ + Get the coordinates of chips that should be Ethernet chips + + This may well be passed down to SpiNNakerTriadGeometry + + .. note:: + This methods assumes that width and height would pass verify_size. + It not the results may be wrong + + :param int width: The width of the machine to find the chips in + :param int height: The height of the machine to find the chips in + :rtype: list(tuple(int, int)) + """ + def verify_size(self, width, height): """ Checks that the width and height are allowed for this version diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index 5188e262..6f8440cd 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -39,6 +39,10 @@ def name(self): def chip_core_map(self): return CHIPS_PER_BOARD + @overrides(VersionSpin1.get_potential_ethernet_chips) + def get_potential_ethernet_chips(self, width, height): + return [(0, 0)] + @overrides(VersionSpin1._verify_size) def _verify_size(self, width, height): if width != 2: diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index db11ac0f..c3e68271 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -18,7 +18,7 @@ from spinn_machine.horizontal_wrap_machine import HorizontalWrapMachine from spinn_machine.no_wrap_machine import NoWrapMachine from spinn_machine.vertical_wrap_machine import VerticalWrapMachine - +from spinn_machine import SpiNNakerTriadGeometry from .version_spin1 import VersionSpin1 CHIPS_PER_BOARD = { @@ -52,6 +52,11 @@ def name(self): def chip_core_map(self): return CHIPS_PER_BOARD + @overrides(VersionSpin1.get_potential_ethernet_chips) + def get_potential_ethernet_chips(self, width, height): + geometry = SpiNNakerTriadGeometry.get_spinn5_geometry() + return geometry.get_potential_ethernet_chips(width, height) + @overrides(VersionSpin1._verify_size) def _verify_size(self, width, height): if width == height == 8: diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index 745a7252..c4bb4eee 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -19,7 +19,6 @@ from .chip import Chip from .router import Router from .link import Link -from .spinnaker_triad_geometry import SpiNNakerTriadGeometry from spinn_machine.data import MachineDataView from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink @@ -64,7 +63,8 @@ class _VirtualMachine(object): def __init__( self, width, height, n_cpus_per_chip=None, validate=True): - self._machine = MachineDataView.get_machine_version().create_machine( + version = MachineDataView.get_machine_version() + self._machine = version.create_machine( width, height, origin=self.ORIGIN) # Store the down items @@ -102,10 +102,7 @@ def __init__( if width == 2: # Already checked height is now also 2 self._unused_links.update(_VirtualMachine._4_chip_down_links) - # Calculate the Ethernet connections in the machine, assuming 48-node - # boards - geometry = SpiNNakerTriadGeometry.get_spinn5_geometry() - ethernet_chips = geometry.get_potential_ethernet_chips(width, height) + ethernet_chips = version.get_potential_ethernet_chip(width, height) # Compute list of chips that are possible based on configuration # If there are no wrap arounds, and the the size is not 2 * 2, From 9a1cd3ebcf41e86de3a7932b17ec17a417fb6f48 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 13 Jul 2023 13:38:49 +0100 Subject: [PATCH 14/24] width heigt 8 constants moved to geometry --- spinn_machine/machine.py | 4 ---- spinn_machine/spinnaker_triad_geometry.py | 15 +++++++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 0e834abe..8ad9487a 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -33,10 +33,6 @@ class Machine(object, metaclass=AbstractBase): """ - # other useful magic numbers for machines - SIZE_X_OF_ONE_BOARD = 8 - SIZE_Y_OF_ONE_BOARD = 8 - # Table of the amount to add to the x and y coordinates to get the # coordinates down the given link (0-5) LINK_ADD_TABLE = [(1, 0), (1, 1), (0, 1), (-1, 0), (-1, -1), (0, -1)] diff --git a/spinn_machine/spinnaker_triad_geometry.py b/spinn_machine/spinnaker_triad_geometry.py index 3dd8a60a..fe813d4d 100644 --- a/spinn_machine/spinnaker_triad_geometry.py +++ b/spinn_machine/spinnaker_triad_geometry.py @@ -31,6 +31,8 @@ class SpiNNakerTriadGeometry(object): "_ethernet_offset", "_triad_height", "_triad_width", + "_board_height", + "_board_width", "_roots") # Stored singleton @@ -48,13 +50,16 @@ def get_spinn5_geometry(): if SpiNNakerTriadGeometry.spinn5_triad_geometry is None: SpiNNakerTriadGeometry.spinn5_triad_geometry = \ SpiNNakerTriadGeometry( - 12, 12, [(0, 0), (4, 8), (8, 4)], (3.6, 3.4)) + 12, 12, 8, 8, [(0, 0), (4, 8), (8, 4)], (3.6, 3.4)) return SpiNNakerTriadGeometry.spinn5_triad_geometry - def __init__(self, triad_width, triad_height, roots, centre): + def __init__(self, triad_width, triad_height, board_width, board_height, + roots, centre): """ :param int triad_width: width of a triad in chips :param int triad_height: height of a triad in chips + :param int board_width: width of a board in chips + :param int board_height: height of a board in chips :param roots: locations of the Ethernet connected chips :type roots: list(tuple(int, int)) :param centre: @@ -63,6 +68,8 @@ def __init__(self, triad_width, triad_height, roots, centre): """ self._triad_width = triad_width self._triad_height = triad_height + self._board_width = board_width + self._board_height = board_height self._roots = roots # Copy the Ethernet locations to surrounding triads to make the @@ -207,11 +214,11 @@ def get_potential_ethernet_chips(self, width, height): if width % self._triad_width == 0: eth_width = width else: - eth_width = width - Machine.SIZE_X_OF_ONE_BOARD + 1 + eth_width = width - self._board_width + 1 if height % self._triad_height == 0: eth_height = height else: - eth_height = height - Machine.SIZE_Y_OF_ONE_BOARD + 1 + eth_height = height - self._board_height + 1 # special case for single boards like the 2,2 if (eth_width <= 0 or eth_height <= 0): return [(0, 0)] From 77358acfc6e1c5c526b65b4ff9bdb02f1f17e8c4 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 14 Jul 2023 08:17:20 +0100 Subject: [PATCH 15/24] n_router_entries from Version and machine object --- spinn_machine/machine.py | 42 ++++++++++++++++++----- spinn_machine/machine_factory.py | 2 +- spinn_machine/router.py | 3 +- spinn_machine/version/abstract_version.py | 11 ++++++ spinn_machine/version/version_spin1.py | 6 ++++ spinn_machine/virtual_machine.py | 9 +++-- unittests/test_machine.py | 1 + 7 files changed, 59 insertions(+), 15 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 8ad9487a..1d6e7606 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections import Counter from .exceptions import ( SpinnMachineAlreadyExistsException, SpinnMachineException) from spinn_machine.link_data_objects import FPGALinkData, SpinnakerLinkData @@ -37,8 +38,6 @@ class Machine(object, metaclass=AbstractBase): # coordinates down the given link (0-5) LINK_ADD_TABLE = [(1, 0), (1, 1), (0, 1), (-1, 0), (-1, -1), (0, -1)] - ROUTER_ENTRIES = 1023 - __slots__ = ( "_boot_ethernet_address", # A map off the expected x, y coordinates on a standard board to @@ -50,10 +49,19 @@ class Machine(object, metaclass=AbstractBase): # Declared height of the machine # This can not be changed "_height", + # A Counter of the number of cores on each Chip + "_n_cores_counter", + # A Counter of links on each Chip + # Counts each direction so the n_links is half the total + "n_links_counter" + # A Counter for the number of router entries on each Chip + "_n_router_entries_counter", # Extra information about how this machine was created # to be used in the str method "_origin", "_spinnaker_links", + # A Counter for sdram on each Chip + "_sdram_counter", # Declared width of the machine # This can not be changed "_width" @@ -98,6 +106,11 @@ def __init__(self, width, height, chip_core_map, origin=None): else: self._origin = origin + self._n_cores_counter = Counter() + self._n_links_counter = Counter() + self._n_router_entries_counter = Counter() + self._sdram_counter = Counter() + @abstractmethod def multiple_48_chip_boards(self): """ @@ -513,6 +526,13 @@ def add_chip(self, chip): self._chips[chip_id] = chip + # keep some stats about the + self._n_cores_counter[chip.n_processors] += 1 + self._n_links_counter[len(chip.router)] += 1 + self._n_router_entries_counter[ + chip.router.n_available_multicast_entries] += 1 + self._sdram_counter[chip.sdram] += 1 + if chip.ip_address is not None: self._ethernet_connected_chips.append(chip) if (chip.x == 0) and (chip.y == 0): @@ -908,13 +928,17 @@ def get_cores_and_link_count(self): :return: tuple of (n_cores, n_links) :rtype: tuple(int,int) """ - cores = 0 - total_links = 0 - for chip_key in self._chips: - chip = self._chips[chip_key] - cores += chip.n_processors - total_links += len(chip.router) - return cores, total_links / 2 + return (sum(n * count for n, count in self._n_cores_counter.items()), + sum(n * count for n, count in self._n_links_counter.items()) + / 2) + + @property + def min_n_router_enteries(self): + """ + The minumum number of router_enteries found on any Chip + :return: + """ + return sorted(self._n_router_entries_counter.keys())[-1] def cores_and_link_output_string(self): """ diff --git a/spinn_machine/machine_factory.py b/spinn_machine/machine_factory.py index d71d155a..ca5354d1 100644 --- a/spinn_machine/machine_factory.py +++ b/spinn_machine/machine_factory.py @@ -85,7 +85,7 @@ def _machine_ignore(original, dead_chips, dead_links): for link in chip.router.links: if link.source_link_id not in links_map[(chip.x, chip.y)]: links.append(link) - router = Router(links) + router = Router(links, chip.router.n_available_multicast_entries) chip = Chip( chip.x, chip.y, chip.n_processors, router, chip.sdram, chip.nearest_ethernet_x, chip.nearest_ethernet_y, diff --git a/spinn_machine/router.py b/spinn_machine/router.py index 18bf9ab9..e1103c05 100644 --- a/spinn_machine/router.py +++ b/spinn_machine/router.py @@ -37,8 +37,7 @@ class Router(object): __slots__ = ("_links", "_n_available_multicast_entries") - def __init__( - self, links, n_available_multicast_entries=Machine.ROUTER_ENTRIES): + def __init__(self, links, n_available_multicast_entries): """ :param iterable(~spinn_machine.Link) links: iterable of links :param int n_available_multicast_entries: diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index eecc8835..56b8577d 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -146,6 +146,17 @@ def n_chips_per_board(self): """ return len(self.chip_core_map) + @abstractproperty + def n_router_entries(self): + """ + The standard number of router entires in a router table. + + While it is likely that all Chips will have this number it should + not be counted on. Ask each Chip's Router for the correct value + + :rtype: int + """ + @property def expected_xys(self): """ diff --git a/spinn_machine/version/version_spin1.py b/spinn_machine/version/version_spin1.py index ca21cd87..827c501a 100644 --- a/spinn_machine/version/version_spin1.py +++ b/spinn_machine/version/version_spin1.py @@ -31,3 +31,9 @@ def __init__(self): @overrides(AbstractVersion.n_non_user_cores) def n_non_user_cores(self): return 1 + + + @property + @overrides(AbstractVersion.n_router_entries) + def n_router_entries(self): + return 1023 diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index c4bb4eee..2db77406 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -51,7 +51,9 @@ class _VirtualMachine(object): "_unused_cores", "_unused_links", "_machine", - "_with_monitors") + "_with_monitors", + "_n_router_entries" + ) _4_chip_down_links = { (0, 0, 3), (0, 0, 4), (0, 1, 3), (0, 1, 4), @@ -64,6 +66,7 @@ def __init__( self, width, height, n_cpus_per_chip=None, validate=True): version = MachineDataView.get_machine_version() + self._n_router_entries = version.n_router_entries self._machine = version.create_machine( width, height, origin=self.ORIGIN) @@ -102,7 +105,7 @@ def __init__( if width == 2: # Already checked height is now also 2 self._unused_links.update(_VirtualMachine._4_chip_down_links) - ethernet_chips = version.get_potential_ethernet_chip(width, height) + ethernet_chips = version.get_potential_ethernet_chips(width, height) # Compute list of chips that are possible based on configuration # If there are no wrap arounds, and the the size is not 2 * 2, @@ -145,7 +148,7 @@ def machine(self): def _create_chip(self, x, y, configured_chips, ip_address=None): chip_links = self._calculate_links(x, y, configured_chips) - chip_router = Router(chip_links) + chip_router = Router(chip_links, self._n_router_entries) (eth_x, eth_y, n_cores) = configured_chips[(x, y)] diff --git a/unittests/test_machine.py b/unittests/test_machine.py index cae7a75a..fd90f578 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -87,6 +87,7 @@ def test_create_new_machine(self): "[VirtualNoWrapMachine: width=8, height=8, n_chips=48]", new_machine.__repr__()) self.assertEqual(2, len(list(new_machine.spinnaker_links))) + self.assertEqual(1023, new_machine.min_n_router_enteries) def test_create_new_machine_with_invalid_chips(self): """ From d3bb69af8e6ea2220b20d32bdc2e5340363e5d6a Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 14 Jul 2023 12:21:45 +0100 Subject: [PATCH 16/24] machine summary string --- spinn_machine/machine.py | 80 ++++++++++++++++++++++++++----- unittests/test_machine.py | 7 ++- unittests/test_virtual_machine.py | 3 +- 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 1d6e7606..feb3f566 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -15,6 +15,7 @@ from collections import Counter from .exceptions import ( SpinnMachineAlreadyExistsException, SpinnMachineException) +from spinn_machine.data import MachineDataView from spinn_machine.link_data_objects import FPGALinkData, SpinnakerLinkData from spinn_utilities.abstract_base import ( AbstractBase, abstractproperty, abstractmethod) @@ -53,7 +54,7 @@ class Machine(object, metaclass=AbstractBase): "_n_cores_counter", # A Counter of links on each Chip # Counts each direction so the n_links is half the total - "n_links_counter" + "_n_links_counter", # A Counter for the number of router entries on each Chip "_n_router_entries_counter", # Extra information about how this machine was created @@ -916,21 +917,28 @@ def __str__(self): def __repr__(self): return self.__str__() - def get_cores_and_link_count(self): + def get_cores_count(self): """ - Get the number of cores and links from the machine. + Get the number of cores from the machine. + + :return: n_cores + :rtype: int + """ + return sum(n * count for n, count in self._n_cores_counter.items()) + + def get_links_count(self): + """ + Get the number of links from the machine. Links are assumed to be bidirectional so the total links counted is half of the unidirectional links found. SpiNNaker and FPGA links are not included. - :return: tuple of (n_cores, n_links) - :rtype: tuple(int,int) + :return: n_links + :rtype: int """ - return (sum(n * count for n, count in self._n_cores_counter.items()), - sum(n * count for n, count in self._n_links_counter.items()) - / 2) + return sum(n * count for n, count in self._n_links_counter.items()) / 2 @property def min_n_router_enteries(self): @@ -940,14 +948,60 @@ def min_n_router_enteries(self): """ return sorted(self._n_router_entries_counter.keys())[-1] - def cores_and_link_output_string(self): + def summary_string(self): """ - Get a string detailing the number of cores and links. + Gets a summary of the Machine and logs warnings for weirdness - :rtype: str + :return: """ - cores, links = self.get_cores_and_link_count() - return f"{cores} cores and {links} links" + version = MachineDataView.get_machine_version() + + sdram = sorted(self._sdram_counter.keys()) + if len(sdram) == 1: + if sdram[0] != version.max_sdram_per_chip: + logger.warning( + f"The sdram per chip of {sdram[0]} was differemt to the " + f"expected value of {version.max_sdram_per_chip} " + f"for board Version {version.name}") + sdram_st = f"sdram of {sdram[0]} bytes" + else: + sdram_st = "sdram of between {sdram[0]} and {sdram[-1]} bytes" + logger.warning (f"Not all Chips have the same sdram. " + f"The counts where {self._sdram_counter}.") + + routers = sorted(self._n_router_entries_counter.keys()) + if len(routers) == 1: + if routers[0] != version.n_router_entries: + logger.warning( + f"The number of router entries per chip of {routers[0]} " + f"was different to the expected value of " + f"{version.n_router_entries} " + f"for board Version {version.name}") + routers_st = f"router table of size {routers[0]}" + else: + routers_st = (f"router table sizes between " + f"{routers[0]} and {routers[-1]}") + logger.warning( + f"Not all Chips had the same n_router_tables. " + f"The counts where {self._n_router_entries_counter}.") + + cores = sorted(self._n_cores_counter.keys()) + if len(cores) == 1: + cores_st = f" {cores[0]} cores" + else: + cores_st = f"between {cores[0]} and {cores[-1]} cores" + + links = sorted(self._n_links_counter.keys()) + if len(links) == 1: + links_st = f" {links[0]} links." + else: + links_st = f"between {links[0]} and {links[-1]} links" + + return ( + f"Machine on {self.boot_chip.ip_address} " + f"with {self.n_chips} Chips, {self.get_cores_count()} cores " + f"and {self.get_links_count()} links. " + f"Chips have {sdram_st}, {routers_st}, {cores_st} and {links_st}.") @property def boot_chip(self): diff --git a/unittests/test_machine.py b/unittests/test_machine.py index fd90f578..30cdac86 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -81,8 +81,11 @@ def test_create_new_machine(self): self.assertEqual( next(x[1].ip_address for x in new_machine), "127.0.0.0") self.assertEqual(next(new_machine.chip_coordinates), (0, 0)) - self.assertEqual("856 cores and 120.0 links", - new_machine.cores_and_link_output_string()) + self.assertEqual( + "Machine on 127.0.0.0 with 48 Chips, 856 cores and 120.0 links. " + "Chips have sdram of 123469792 bytes, router table of size 1023, " + "between 17 and 18 cores and between 3 and 6 links.", + new_machine.summary_string()) self.assertEqual( "[VirtualNoWrapMachine: width=8, height=8, n_chips=48]", new_machine.__repr__()) diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index daefcb55..d10b8502 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -108,7 +108,8 @@ def test_version_2(self): self.assertEqual(16, count) # self.assertEqual(str(vm), # "[VirtualMachine: max_x=1, max_y=1, n_chips=4]") - self.assertEqual(vm.get_cores_and_link_count(), (72, 8)) + self.assertEqual(72, vm.get_cores_count()) + self.assertEqual(8, vm.get_links_count()) count = 0 for _chip in vm.get_existing_xys_on_board(vm.get_chip_at(1, 1)): count += 1 From 9b98b987aa136e41b1381b566c18355fa1d2be61 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 14 Jul 2023 14:33:31 +0100 Subject: [PATCH 17/24] test summary_string --- spinn_machine/machine.py | 6 +++-- unittests/test_machine.py | 55 +++++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index feb3f566..d5cd9012 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -952,7 +952,9 @@ def summary_string(self): """ Gets a summary of the Machine and logs warnings for weirdness - :return: + :return: A String descibing the Machine + :raises IndexError: If there are no Chips in the MAchine + :raises AttributeError: If there is no boot chip """ version = MachineDataView.get_machine_version() @@ -965,7 +967,7 @@ def summary_string(self): f"for board Version {version.name}") sdram_st = f"sdram of {sdram[0]} bytes" else: - sdram_st = "sdram of between {sdram[0]} and {sdram[-1]} bytes" + sdram_st = f"sdram of between {sdram[0]} and {sdram[-1]} bytes" logger.warning (f"Not all Chips have the same sdram. " f"The counts where {self._sdram_counter}.") diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 30cdac86..a64876d7 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -15,8 +15,10 @@ """ test for testing the python representation of a spinnaker machine """ +from testfixtures import LogCapture import unittest from spinn_utilities.config_holder import set_config +from spinn_utilities.testing import log_checker from spinn_machine import Link, Router, Chip from spinn_machine import virtual_machine from spinn_machine.config_setup import unittest_setup @@ -81,17 +83,60 @@ def test_create_new_machine(self): self.assertEqual( next(x[1].ip_address for x in new_machine), "127.0.0.0") self.assertEqual(next(new_machine.chip_coordinates), (0, 0)) - self.assertEqual( - "Machine on 127.0.0.0 with 48 Chips, 856 cores and 120.0 links. " - "Chips have sdram of 123469792 bytes, router table of size 1023, " - "between 17 and 18 cores and between 3 and 6 links.", - new_machine.summary_string()) self.assertEqual( "[VirtualNoWrapMachine: width=8, height=8, n_chips=48]", new_machine.__repr__()) self.assertEqual(2, len(list(new_machine.spinnaker_links))) self.assertEqual(1023, new_machine.min_n_router_enteries) + def test_summary(self): + machine = virtual_machine(8, 8) + self.assertEqual( + "Machine on 127.0.0.0 with 48 Chips, 856 cores and 120.0 links. " + "Chips have sdram of 123469792 bytes, router table of size 1023, " + "between 17 and 18 cores and between 3 and 6 links.", + machine.summary_string()) + + # Hack to test sefety code. Doing this outside tests not supported + machine._sdram_counter.clear() + machine._sdram_counter[123] += 1 + machine._n_router_entries_counter.clear() + machine._n_router_entries_counter[456] += 1 + with LogCapture() as lc: + self.assertEqual( + "Machine on 127.0.0.0 with 48 Chips, 856 cores and 120.0" + " links. Chips have sdram of 123 bytes, router table of size " + "456, between 17 and 18 cores and between 3 and 6 links.", + machine.summary_string()) + log_checker.assert_logs_warning_contains( + lc.records, + "The sdram per chip of 123 was differemt to the expected " + "value of 123469792 for board Version Spin1 48 Chip") + log_checker.assert_logs_warning_contains( + lc.records, + "The number of router entries per chip of 456 was different " + "to the expected value of 1023 " + "for board Version Spin1 48 Chip") + + # Hack to test sefety code. Doing this outside tests not supported + machine._sdram_counter[789] += 1 + machine._n_router_entries_counter[321] += 1 + with LogCapture() as lc: + self.assertEqual( + "Machine on 127.0.0.0 with 48 Chips, 856 cores and 120.0 " + "links. Chips have sdram of between 123 and 789 bytes, " + "router table sizes between 321 and 456, " + "between 17 and 18 cores and between 3 and 6 links.", + machine.summary_string()) + log_checker.assert_logs_warning_contains( + lc.records, + "Not all Chips have the same sdram. " + "The counts where Counter({123: 1, 789: 1}).") + log_checker.assert_logs_warning_contains( + lc.records, + "Not all Chips had the same n_router_tables. " + "The counts where Counter({456: 1, 321: 1}).") + def test_create_new_machine_with_invalid_chips(self): """ check that building a machine with invalid chips causes errors From a6edd61380d0f33779405c76df0c5567b53afaad Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 14 Jul 2023 15:28:09 +0100 Subject: [PATCH 18/24] flake8 --- spinn_machine/full_wrap_machine.py | 1 - spinn_machine/machine.py | 4 ++-- spinn_machine/no_wrap_machine.py | 1 - spinn_machine/router.py | 1 - spinn_machine/spinnaker_triad_geometry.py | 2 -- spinn_machine/version/version_spin1.py | 1 - unittests/test_machine.py | 2 +- unittests/test_virtual_machine.py | 2 +- 8 files changed, 4 insertions(+), 10 deletions(-) diff --git a/spinn_machine/full_wrap_machine.py b/spinn_machine/full_wrap_machine.py index 4923d438..dd6d6172 100644 --- a/spinn_machine/full_wrap_machine.py +++ b/spinn_machine/full_wrap_machine.py @@ -13,7 +13,6 @@ # limitations under the License. from spinn_utilities.overrides import overrides -from spinn_machine.data import MachineDataView from .machine import Machine diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index d5cd9012..c6a85c34 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -968,8 +968,8 @@ def summary_string(self): sdram_st = f"sdram of {sdram[0]} bytes" else: sdram_st = f"sdram of between {sdram[0]} and {sdram[-1]} bytes" - logger.warning (f"Not all Chips have the same sdram. " - f"The counts where {self._sdram_counter}.") + logger.warning(f"Not all Chips have the same sdram. " + f"The counts where {self._sdram_counter}.") routers = sorted(self._n_router_entries_counter.keys()) if len(routers) == 1: diff --git a/spinn_machine/no_wrap_machine.py b/spinn_machine/no_wrap_machine.py index 37d59ec3..ef41f919 100644 --- a/spinn_machine/no_wrap_machine.py +++ b/spinn_machine/no_wrap_machine.py @@ -14,7 +14,6 @@ from .machine import Machine from spinn_utilities.overrides import overrides -from spinn_machine.data import MachineDataView class NoWrapMachine(Machine): diff --git a/spinn_machine/router.py b/spinn_machine/router.py index e1103c05..322ef1e2 100644 --- a/spinn_machine/router.py +++ b/spinn_machine/router.py @@ -14,7 +14,6 @@ from .exceptions import ( SpinnMachineAlreadyExistsException, SpinnMachineInvalidParameterException) -from .machine import Machine class Router(object): diff --git a/spinn_machine/spinnaker_triad_geometry.py b/spinn_machine/spinnaker_triad_geometry.py index fe813d4d..833890bc 100644 --- a/spinn_machine/spinnaker_triad_geometry.py +++ b/spinn_machine/spinnaker_triad_geometry.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from spinn_machine.machine import Machine - class SpiNNakerTriadGeometry(object): """ diff --git a/spinn_machine/version/version_spin1.py b/spinn_machine/version/version_spin1.py index 827c501a..68ccab6e 100644 --- a/spinn_machine/version/version_spin1.py +++ b/spinn_machine/version/version_spin1.py @@ -32,7 +32,6 @@ def __init__(self): def n_non_user_cores(self): return 1 - @property @overrides(AbstractVersion.n_router_entries) def n_router_entries(self): diff --git a/unittests/test_machine.py b/unittests/test_machine.py index a64876d7..46cae9ef 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -95,7 +95,7 @@ def test_summary(self): "Machine on 127.0.0.0 with 48 Chips, 856 cores and 120.0 links. " "Chips have sdram of 123469792 bytes, router table of size 1023, " "between 17 and 18 cores and between 3 and 6 links.", - machine.summary_string()) + machine.summary_string()) # Hack to test sefety code. Doing this outside tests not supported machine._sdram_counter.clear() diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index d10b8502..f880a5b7 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -15,7 +15,7 @@ import unittest from spinn_utilities.config_holder import set_config from spinn_machine.config_setup import unittest_setup -from spinn_machine import (Chip, Link, Machine, Router, virtual_machine) +from spinn_machine import Chip, Link, Router, virtual_machine from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink From 4c5ab0013f16faa263639e81a752f9abd6893e0c Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 18 Jul 2023 14:30:20 +0100 Subject: [PATCH 19/24] _clear is a defining-attr-methods --- .pylintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.pylintrc b/.pylintrc index e3791953..1b98c077 100644 --- a/.pylintrc +++ b/.pylintrc @@ -383,6 +383,7 @@ init-import=no # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, + _clear, _hard_reset, setUp From 0bb881e28b7939dc646c70b32f51a6b7492ce1de Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 18 Jul 2023 14:32:28 +0100 Subject: [PATCH 20/24] pylint fixes --- spinn_machine/data/machine_data_view.py | 2 +- spinn_machine/machine.py | 15 +++++++++------ spinn_machine/version/abstract_version.py | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/spinn_machine/data/machine_data_view.py b/spinn_machine/data/machine_data_view.py index c86d3a40..dd22f52c 100644 --- a/spinn_machine/data/machine_data_view.py +++ b/spinn_machine/data/machine_data_view.py @@ -97,7 +97,7 @@ def has_machine(cls): """ Reports if a machine is currently set or can be mocked. - Unlike has_existing_machine for unittests this will return True even + Unlike has_existing_machine for unit tests this will return True even if a Machine has not yet been created :rtype: bool diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index c6a85c34..cb8184dd 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -943,8 +943,10 @@ def get_links_count(self): @property def min_n_router_enteries(self): """ - The minumum number of router_enteries found on any Chip - :return: + The minimum number of router_enteries found on any Chip + + :return: The lowest n router entry found on any Router + :rtype: int """ return sorted(self._n_router_entries_counter.keys())[-1] @@ -952,19 +954,20 @@ def summary_string(self): """ Gets a summary of the Machine and logs warnings for weirdness - :return: A String descibing the Machine + :return: A String describing the Machine :raises IndexError: If there are no Chips in the MAchine :raises AttributeError: If there is no boot chip """ + # pylint: disable=logging-fstring-interpolation version = MachineDataView.get_machine_version() sdram = sorted(self._sdram_counter.keys()) if len(sdram) == 1: if sdram[0] != version.max_sdram_per_chip: logger.warning( - f"The sdram per chip of {sdram[0]} was differemt to the " - f"expected value of {version.max_sdram_per_chip} " - f"for board Version {version.name}") + "The sdram per chip of {sdram[0]} was differemt to the " + "expected value of {version.max_sdram_per_chip} " + "for board Version {version.name}") sdram_st = f"sdram of {sdram[0]} bytes" else: sdram_st = f"sdram of between {sdram[0]} and {sdram[-1]} bytes" diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 56b8577d..603de30f 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -149,7 +149,7 @@ def n_chips_per_board(self): @abstractproperty def n_router_entries(self): """ - The standard number of router entires in a router table. + The standard number of router entries in a router table. While it is likely that all Chips will have this number it should not be counted on. Ask each Chip's Router for the correct value @@ -160,7 +160,7 @@ def n_router_entries(self): @property def expected_xys(self): """ - List of the standard xy coordinates of Chips for this version + List of the standard x y coordinates of Chips for this version Remember that will the board may have dead or excluded chips From e7b0679455e22bde9da9a984e7bc46cc8bb07af6 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 18 Jul 2023 14:37:47 +0100 Subject: [PATCH 21/24] f string and spelling --- spinn_machine/machine.py | 6 +++--- unittests/test_machine.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index cb8184dd..8fd4daaf 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -965,9 +965,9 @@ def summary_string(self): if len(sdram) == 1: if sdram[0] != version.max_sdram_per_chip: logger.warning( - "The sdram per chip of {sdram[0]} was differemt to the " - "expected value of {version.max_sdram_per_chip} " - "for board Version {version.name}") + f"The sdram per chip of {sdram[0]} was different to the " + f"expected value of {version.max_sdram_per_chip} " + f"for board Version {version.name}") sdram_st = f"sdram of {sdram[0]} bytes" else: sdram_st = f"sdram of between {sdram[0]} and {sdram[-1]} bytes" diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 46cae9ef..864d0a46 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -110,7 +110,7 @@ def test_summary(self): machine.summary_string()) log_checker.assert_logs_warning_contains( lc.records, - "The sdram per chip of 123 was differemt to the expected " + "The sdram per chip of 123 was different to the expected " "value of 123469792 for board Version Spin1 48 Chip") log_checker.assert_logs_warning_contains( lc.records, From 1606a96a45016a9da8eda7ac9ccfc2acee48576d Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 19 Jul 2023 06:42:02 +0100 Subject: [PATCH 22/24] adds tests and fix bug --- spinn_machine/version/abstract_version.py | 4 +-- unittests/version/test_version5.py | 41 ++++++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 603de30f..54937916 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -87,11 +87,11 @@ def __set_max_sdram_per_chip(self, max_sdram_per_chip): f"{max_sdram} as it is larger than " f"{self._max_sdram_per_chip} which is the default for a " f"{self.name} board ") - if max_sdram < self._max_cores_per_chip: + if max_sdram < self._max_sdram_per_chip: logger.warning( f"Max sdram per chip reduced to {max_sdram_per_chip} " f"due to cfg setting [Machine]max_sdram_allowed_per_chip") - self._max_sdram_per_chip = max_sdram_per_chip + self._max_sdram_per_chip = max_sdram @abstractproperty def name(self): diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index 4e4532ea..e1e9e93b 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -16,8 +16,10 @@ Testing Version5 """ import unittest +from spinn_utilities.config_holder import set_config from spinn_machine.version.version_5 import Version5 from spinn_machine.config_setup import unittest_setup +from spinn_machine.exceptions import SpinnMachineException class TestVersion5(unittest.TestCase): @@ -26,11 +28,48 @@ class TestVersion5(unittest.TestCase): def setUp(self): unittest_setup() - def test_version(self): + def test_attributes(self): version = Version5() self.assertEqual(18, version.max_cores_per_chip) self.assertEqual(123469792, version.max_sdram_per_chip) self.assertEqual(1, version.n_non_user_cores) + self.assertEqual("Spin1 48 Chip", version.name) + self.assertEqual(48, version.n_chips_per_board) + self.assertEqual(1023, version.n_router_entrie) + + def test_verify_config_width_height(self): + set_config("Machine", "width", "None") + set_config("Machine", "height", "None") + Version5() + + set_config("Machine", "width", 8) + with self.assertRaises(SpinnMachineException): + Version5() + + set_config("Machine", "height", 8) + Version5() + + set_config("Machine", "width", "None") + with self.assertRaises(SpinnMachineException): + Version5() + + def test_set_max_lower(self): + set_config("Machine", "max_sdram_allowed_per_chip", 1000) + set_config("Machine", "max_machine_core", 10) + version = Version5() + self.assertEqual(10, version.max_cores_per_chip) + self.assertEqual(1000, version.max_sdram_per_chip) + + def test_expected_xys(self): + version = Version5() + xys = version.expected_xys + self.assertEqual(48, len(xys)) + self.assertEqual(48, len(set(xys))) + for (x, y) in xys: + self.assertGreaterEqual(x, 0) + self.assertGreaterEqual(y, 0) + self.assertLess(x, 8) + self.assertLess(y, 8) if __name__ == '__main__': From fbdeeaae21b85ceb49d22101833927d5be698003 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 20 Jul 2023 15:54:37 +0100 Subject: [PATCH 23/24] Version class tests --- unittests/version/test_version3.py | 141 +++++++++++++++++++++++++++++ unittests/version/test_version5.py | 74 ++++++++++++++- 2 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 unittests/version/test_version3.py diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py new file mode 100644 index 00000000..072bde69 --- /dev/null +++ b/unittests/version/test_version3.py @@ -0,0 +1,141 @@ +# Copyright (c) 2015 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. + +""" +Testing Version5 +""" +import unittest +from spinn_utilities.config_holder import set_config +from spinn_machine.full_wrap_machine import FullWrapMachine +from spinn_machine.no_wrap_machine import NoWrapMachine +from spinn_machine.horizontal_wrap_machine import HorizontalWrapMachine +from spinn_machine.vertical_wrap_machine import VerticalWrapMachine +from spinn_machine.version.version_3 import Version3 +from spinn_machine.config_setup import unittest_setup +from spinn_machine.exceptions import SpinnMachineException + + +class TestVersion3(unittest.TestCase): + """ Tests of IPTag + """ + def setUp(self): + unittest_setup() + + def test_attributes(self): + version = Version3() + self.assertEqual(18, version.max_cores_per_chip) + self.assertEqual(123469792, version.max_sdram_per_chip) + self.assertEqual(1, version.n_non_user_cores) + self.assertEqual("Spin1 4 Chip", version.name) + self.assertEqual(4, version.n_chips_per_board) + self.assertEqual(1023, version.n_router_entries) + + def test_verify_config_width_height(self): + set_config("Machine", "width", "None") + set_config("Machine", "height", "None") + Version3() + + set_config("Machine", "width", 2) + with self.assertRaises(SpinnMachineException): + Version3() + + set_config("Machine", "height", 2) + Version3() + + set_config("Machine", "width", "None") + with self.assertRaises(SpinnMachineException): + Version3() + + def test_set_max_lower(self): + set_config("Machine", "max_sdram_allowed_per_chip", 1000) + set_config("Machine", "max_machine_core", 10) + version = Version3() + self.assertEqual(10, version.max_cores_per_chip) + self.assertEqual(1000, version.max_sdram_per_chip) + + def test_expected_xys(self): + version = Version3() + xys = version.expected_xys + self.assertEqual(4, len(xys)) + self.assertEqual(4, len(set(xys))) + for (x, y) in xys: + self.assertGreaterEqual(x, 0) + self.assertGreaterEqual(y, 0) + self.assertLess(x, 2) + self.assertLess(y, 2) + + def test_expected_chip_core_map(self): + version = Version3() + chip_core_map = version.chip_core_map + self.assertEqual(4, len(chip_core_map)) + for (x, y) in chip_core_map: + self.assertGreaterEqual(x, 0) + self.assertGreaterEqual(y, 0) + self.assertLess(x, 2) + self.assertLess(y, 2) + cores = chip_core_map[(x, y)] + self.assertGreaterEqual(cores, 16) + self.assertLessEqual(cores, 18) + + def test_get_potential_ethernet_chips(self): + version = Version3() + eths = version.get_potential_ethernet_chips(2, 2) + self.assertListEqual([(0, 0)], eths) + + # if size is wromg GIGO + eths = version.get_potential_ethernet_chips(8, 8) + self.assertListEqual([(0, 0)], eths) + eths = version.get_potential_ethernet_chips(12, 12) + self.assertListEqual([(0, 0)], eths) + eths = version.get_potential_ethernet_chips(16, 16) + self.assertListEqual([(0, 0)], eths) + + def test_verify_size(self): + version = Version3() + + with self.assertRaises(SpinnMachineException): + version.verify_size(12, -12) + with self.assertRaises(SpinnMachineException): + version.verify_size(-12, 12) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, None) + with self.assertRaises(SpinnMachineException): + version.verify_size(None, 12) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, 8) + with self.assertRaises(SpinnMachineException): + version.verify_size(8, 12) + version.verify_size(2, 2) + with self.assertRaises(SpinnMachineException): + version.verify_size(8, 8) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, 8) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, 12) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, 16) + with self.assertRaises(SpinnMachineException): + version.verify_size(16, 12) + with self.assertRaises(SpinnMachineException): + version.verify_size(16, 16) + + def test_create_machin(self): + version = Version3() + + machine = version.create_machine(width=2, height=2) + self.assertIsInstance(machine, FullWrapMachine) + + +if __name__ == '__main__': + unittest.main() diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index e1e9e93b..0d8c922d 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -17,6 +17,10 @@ """ import unittest from spinn_utilities.config_holder import set_config +from spinn_machine.full_wrap_machine import FullWrapMachine +from spinn_machine.no_wrap_machine import NoWrapMachine +from spinn_machine.horizontal_wrap_machine import HorizontalWrapMachine +from spinn_machine.vertical_wrap_machine import VerticalWrapMachine from spinn_machine.version.version_5 import Version5 from spinn_machine.config_setup import unittest_setup from spinn_machine.exceptions import SpinnMachineException @@ -35,7 +39,7 @@ def test_attributes(self): self.assertEqual(1, version.n_non_user_cores) self.assertEqual("Spin1 48 Chip", version.name) self.assertEqual(48, version.n_chips_per_board) - self.assertEqual(1023, version.n_router_entrie) + self.assertEqual(1023, version.n_router_entries) def test_verify_config_width_height(self): set_config("Machine", "width", "None") @@ -71,6 +75,74 @@ def test_expected_xys(self): self.assertLess(x, 8) self.assertLess(y, 8) + def test_expected_chip_core_map(self): + version = Version5() + chip_core_map = version.chip_core_map + self.assertEqual(48, len(chip_core_map)) + for (x, y) in chip_core_map: + self.assertGreaterEqual(x, 0) + self.assertGreaterEqual(y, 0) + self.assertLess(x, 8) + self.assertLess(y, 8) + cores = chip_core_map[(x, y)] + self.assertGreaterEqual(cores, 16) + self.assertLessEqual(cores, 18) + + def test_get_potential_ethernet_chips(self): + version = Version5() + eths = version.get_potential_ethernet_chips(8, 8) + self.assertListEqual([(0, 0)], eths) + eths = version.get_potential_ethernet_chips(12, 12) + self.assertListEqual([(0, 0), (4, 8), (8, 4)], eths) + eths = version.get_potential_ethernet_chips(16, 16) + self.assertListEqual([(0, 0), (4, 8), (8, 4)], eths) + + # if size is wrong GIGO + eths = version.get_potential_ethernet_chips(2, 2) + self.assertListEqual([(0, 0)], eths) + + + def test_verify_size(self): + version = Version5() + + with self.assertRaises(SpinnMachineException): + version.verify_size(12, -12) + with self.assertRaises(SpinnMachineException): + version.verify_size(-12, 12) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, None) + with self.assertRaises(SpinnMachineException): + version.verify_size(None, 12) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, 8) + with self.assertRaises(SpinnMachineException): + version.verify_size(8, 12) + with self.assertRaises(SpinnMachineException): + version.verify_size(2, 2) + + version.verify_size(8, 8) + with self.assertRaises(SpinnMachineException): + version.verify_size(12, 8) + version.verify_size(12, 12) + version.verify_size(12, 16) + version.verify_size(16, 12) + version.verify_size(16, 16) + + def test_create_machin(self): + version = Version5() + + machine = version.create_machine(width=8, height=8) + self.assertIsInstance(machine, NoWrapMachine) + + machine = version.create_machine(16, 16) + self.assertIsInstance(machine, NoWrapMachine) + + machine = version.create_machine(12, 16) + self.assertIsInstance(machine, HorizontalWrapMachine) + machine = version.create_machine(16, 12) + self.assertIsInstance(machine, VerticalWrapMachine) + machine = version.create_machine(12, 12) + self.assertIsInstance(machine, FullWrapMachine) if __name__ == '__main__': unittest.main() From 1934485a651bb203334613e4846e8d9afcc25855 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 20 Jul 2023 16:04:29 +0100 Subject: [PATCH 24/24] flake8 --- unittests/version/test_version3.py | 3 --- unittests/version/test_version5.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py index 072bde69..22cf1267 100644 --- a/unittests/version/test_version3.py +++ b/unittests/version/test_version3.py @@ -18,9 +18,6 @@ import unittest from spinn_utilities.config_holder import set_config from spinn_machine.full_wrap_machine import FullWrapMachine -from spinn_machine.no_wrap_machine import NoWrapMachine -from spinn_machine.horizontal_wrap_machine import HorizontalWrapMachine -from spinn_machine.vertical_wrap_machine import VerticalWrapMachine from spinn_machine.version.version_3 import Version3 from spinn_machine.config_setup import unittest_setup from spinn_machine.exceptions import SpinnMachineException diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index 0d8c922d..72581186 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -101,7 +101,6 @@ def test_get_potential_ethernet_chips(self): eths = version.get_potential_ethernet_chips(2, 2) self.assertListEqual([(0, 0)], eths) - def test_verify_size(self): version = Version5() @@ -144,5 +143,6 @@ def test_create_machin(self): machine = version.create_machine(12, 12) self.assertIsInstance(machine, FullWrapMachine) + if __name__ == '__main__': unittest.main()