From e5294fa1c58fa9ee65ce92c5c99ddb6310e6e07e Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 08:29:52 +0100 Subject: [PATCH 01/54] version201 --- spinn_machine/version/abstract_version.py | 6 +- spinn_machine/version/version_201.py | 107 ++++++++++++++++ spinn_machine/version/version_spin1.py | 7 +- unittests/version/test_version201.py | 147 ++++++++++++++++++++++ unittests/version/test_version3.py | 2 +- unittests/version/test_version5.py | 2 +- 6 files changed, 263 insertions(+), 8 deletions(-) create mode 100644 spinn_machine/version/version_201.py create mode 100644 unittests/version/test_version201.py diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index c437c48a..3d82fd7d 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -13,7 +13,7 @@ # limitations under the License. from __future__ import annotations import logging -from typing import Mapping, Optional, Sequence, Tuple, TYPE_CHECKING +from typing import List, Mapping, Optional, Sequence, Tuple, TYPE_CHECKING from spinn_utilities.abstract_base import AbstractBase, abstractmethod from spinn_utilities.log import FormatAdapter from spinn_utilities.config_holder import get_config_int_or_none @@ -214,9 +214,9 @@ def chip_core_map(self) -> Mapping[XY, int]: @property @abstractmethod - def clock_speed_hz(self) -> int: + def clock_speeds_hz(self) -> List[int]: """ - The processor clock speed in Hz + The processor clock speeds in Hz this processor can run at :rtype: int """ diff --git a/spinn_machine/version/version_201.py b/spinn_machine/version/version_201.py new file mode 100644 index 00000000..159f13c8 --- /dev/null +++ b/spinn_machine/version/version_201.py @@ -0,0 +1,107 @@ +# Copyright (c) 2024 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 typing import Final, List, Mapping, Optional, Sequence, Tuple + +from spinn_utilities.abstract_base import AbstractBase +from spinn_utilities.typing.coords import XY +from spinn_utilities.overrides import overrides + +from spinn_machine.exceptions import SpinnMachineException +from spinn_machine.full_wrap_machine import FullWrapMachine +from spinn_machine.machine import Machine + +from .abstract_version import AbstractVersion + +CHIPS_PER_BOARD: Final = {(0, 0): 152} + + +class Version201(AbstractVersion, metaclass=AbstractBase): + # pylint: disable=abstract-method + """ + Code for the 1 Chip test Spin2 board versions + """ + + __slots__ = () + + def __init__(self) -> None: + super().__init__(max_cores_per_chip=152, + max_sdram_per_chip=1073741824) + + @property + @overrides(AbstractVersion.n_scamp_cores) + def n_scamp_cores(self) -> int: + return 1 + + @property + @overrides(AbstractVersion.n_router_entries) + def n_router_entries(self) -> int: + return 16384 + + @property + @overrides(AbstractVersion.minimum_cores_expected) + def minimum_cores_expected(self) -> int: + return 150 + + @property + @overrides(AbstractVersion.clock_speeds_hz) + def clock_speeds_hz(self) -> List[int]: + return [150, 300] + + @property + @overrides(AbstractVersion.dtcm_bytes) + def dtcm_bytes(self) -> int: + raise NotImplementedError + + @property + @overrides(AbstractVersion.name) + def name(self) -> str: + return "Spin2 1 Chip" + + @property + @overrides(AbstractVersion.number) + def number(self) -> int: + return 201 + + @property + @overrides(AbstractVersion.board_shape) + def board_shape(self) -> Tuple[int, int]: + return (1, 1) + + @property + @overrides(AbstractVersion.chip_core_map) + def chip_core_map(self) -> Mapping[XY, int]: + return CHIPS_PER_BOARD + + @overrides(AbstractVersion.get_potential_ethernet_chips) + def get_potential_ethernet_chips( + self, width: int, height: int) -> Sequence[XY]: + return [(0, 0)] + + @overrides(AbstractVersion._verify_size) + def _verify_size(self, width: int, height: int): + if width != 1: + raise SpinnMachineException("Unexpected {width=}") + if height != 1: + raise SpinnMachineException("Unexpected {height=}") + + @overrides(AbstractVersion._create_machine) + def _create_machine(self, width: int, height: int, origin: str) -> Machine: + return FullWrapMachine(width, height, CHIPS_PER_BOARD, origin) + + @overrides(AbstractVersion.illegal_ethernet_message) + def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: + if x != 0 or y != 0: + return "Only Chip 0, 0 may be an Ethernet Chip" + return None diff --git a/spinn_machine/version/version_spin1.py b/spinn_machine/version/version_spin1.py index 24a20b47..e71e7794 100644 --- a/spinn_machine/version/version_spin1.py +++ b/spinn_machine/version/version_spin1.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import List from spinn_utilities.abstract_base import AbstractBase from spinn_utilities.overrides import overrides from .abstract_version import AbstractVersion @@ -44,9 +45,9 @@ def minimum_cores_expected(self) -> int: return 5 @property - @overrides(AbstractVersion.clock_speed_hz) - def clock_speed_hz(self) -> int: - return 200 + @overrides(AbstractVersion.clock_speeds_hz) + def clock_speeds_hz(self) -> List[int]: + return [200] @property @overrides(AbstractVersion.dtcm_bytes) diff --git a/unittests/version/test_version201.py b/unittests/version/test_version201.py new file mode 100644 index 00000000..d5759bcf --- /dev/null +++ b/unittests/version/test_version201.py @@ -0,0 +1,147 @@ +# 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.version.version_201 import Version201 +from spinn_machine.config_setup import unittest_setup +from spinn_machine.exceptions import SpinnMachineException + + +class TestVersion201(unittest.TestCase): + """ Tests of IPTag + """ + def setUp(self): + unittest_setup() + + def test_attributes(self): + version = Version201() + self.assertEqual(152, version.max_cores_per_chip) + self.assertEqual(2**30, version.max_sdram_per_chip) + self.assertEqual(1, version.n_scamp_cores) + self.assertEqual("Spin2 1 Chip", version.name) + self.assertEqual(201, version.number) + self.assertEqual((1, 1), version.board_shape) + self.assertEqual(1, version.n_chips_per_board) + self.assertEqual(16384, version.n_router_entries) + + def test_verify_config_width_height(self): + set_config("Machine", "width", "None") + set_config("Machine", "height", "None") + Version201() + + set_config("Machine", "width", 1) + with self.assertRaises(SpinnMachineException): + Version201() + + set_config("Machine", "height", 1) + Version201() + + set_config("Machine", "width", "None") + with self.assertRaises(SpinnMachineException): + Version201() + + def test_set_max_lower(self): + set_config("Machine", "max_sdram_allowed_per_chip", 1000) + set_config("Machine", "max_machine_core", 100) + version = Version201() + self.assertEqual(100, version.max_cores_per_chip) + self.assertEqual(1000, version.max_sdram_per_chip) + + def test_expected_xys(self): + version = Version201() + xys = version.expected_xys + self.assertEqual(1, len(xys)) + self.assertEqual(1, len(set(xys))) + for (x, y) in xys: + self.assertGreaterEqual(x, 0) + self.assertGreaterEqual(y, 0) + self.assertLess(x, 1) + self.assertLess(y, 1) + + def test_expected_chip_core_map(self): + version = Version201() + chip_core_map = version.chip_core_map + self.assertEqual(1, len(chip_core_map)) + for (x, y) in chip_core_map: + self.assertGreaterEqual(x, 0) + self.assertGreaterEqual(y, 0) + self.assertLess(x, 1) + self.assertLess(y, 1) + cores = chip_core_map[(x, y)] + self.assertGreaterEqual(cores, 100) + self.assertLessEqual(cores, 152) + + def test_get_potential_ethernet_chips(self): + version = Version201() + eths = version.get_potential_ethernet_chips(0, 0) + 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 = Version201() + + 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(1, 1) + 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 = Version201() + + machine = version.create_machine(width=1, height=1) + self.assertIsInstance(machine, FullWrapMachine) + + def test_processor_info(self): + version = Version201() + self.assertEqual([150, 300], version.clock_speeds_hz) + #self.assertEqual(65536, version.dtcm_bytes) + + +if __name__ == '__main__': + unittest.main() diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py index 5d5795ed..11ab0066 100644 --- a/unittests/version/test_version3.py +++ b/unittests/version/test_version3.py @@ -137,7 +137,7 @@ def test_create_machin(self): def test_processor_info(self): version = Version3() - self.assertEqual(200, version.clock_speed_hz) + self.assertEqual([200], version.clock_speeds_hz) self.assertEqual(65536, version.dtcm_bytes) diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index a4ec4387..10f2c1f2 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -147,7 +147,7 @@ def test_create_machin(self): def test_processor_info(self): version = Version5() - self.assertEqual(200, version.clock_speed_hz) + self.assertEqual([200], version.clock_speeds_hz) self.assertEqual(65536, version.dtcm_bytes) From 24f702a6438cfaf707bb22e224aa87b1d2ed2396 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 10:00:15 +0100 Subject: [PATCH 02/54] split virtual machine tests --- unittests/test_using_virtual_machine.py | 427 ++++++++++++++ unittests/test_virtual_machine3.py | 265 +++++++++ ...al_machine.py => test_virtual_machine5.py} | 536 +----------------- 3 files changed, 721 insertions(+), 507 deletions(-) create mode 100644 unittests/test_using_virtual_machine.py create mode 100644 unittests/test_virtual_machine3.py rename unittests/{test_virtual_machine.py => test_virtual_machine5.py} (55%) diff --git a/unittests/test_using_virtual_machine.py b/unittests/test_using_virtual_machine.py new file mode 100644 index 00000000..c83db2b8 --- /dev/null +++ b/unittests/test_using_virtual_machine.py @@ -0,0 +1,427 @@ +# Copyright (c) 2014 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +from spinn_utilities.config_holder import set_config +from spinn_machine.config_setup import unittest_setup +from spinn_machine import Chip, Link, Router, virtual_machine +from spinn_machine.exceptions import ( + SpinnMachineAlreadyExistsException, SpinnMachineException) +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 TestUsingVirtualMachine(unittest.TestCase): + + VERSION_5_N_CORES_PER_BOARD = sum(CHIPS_PER_BOARD.values()) + + def setUp(self): + unittest_setup() + + def _create_chip(self, x, y): + # Create a list of processors. + + n_processors = 18 + + links = list() + links.append(Link(0, 0, 0, 1, 1)) + links.append(Link(0, 1, 1, 1, 0)) + links.append(Link(1, 1, 2, 0, 0)) + links.append(Link(1, 0, 3, 0, 1)) + _router = Router(links, 1024) + + _sdram = 128 + nearest_ethernet_chip = (0, 0) + _ip = "192.162.240.253" + + if (x == y == 0): + return Chip(x, y, n_processors, _router, _sdram, + nearest_ethernet_chip[0], + nearest_ethernet_chip[1], _ip) + else: + return Chip(x, y, n_processors, _router, _sdram, + nearest_ethernet_chip[0], + nearest_ethernet_chip[1], None) + + def test_new_vm_with_max_cores(self): + set_config("Machine", "version", 2) + n_cpus = 13 + set_config("Machine", "max_machine_core", n_cpus) + vm = virtual_machine(2, 2, validate=True) + _chip = vm[1, 1] + self.assertEqual(n_cpus, _chip.n_processors) + self.assertEqual(n_cpus - 1, _chip.n_placable_processors) + self.assertEqual(1, _chip.n_scamp_processors) + self.assertEqual(n_cpus - 1, len(list(_chip.placable_processors_ids))) + self.assertEqual(1, len(list(_chip.scamp_processors_ids))) + count = sum(_chip.n_processors for _chip in vm.chips) + self.assertEqual(count, 4 * n_cpus) + + def test_iter_chips(self): + set_config("Machine", "version", 2) + vm = virtual_machine(2, 2) + self.assertEqual(4, vm.n_chips) + count = 0 + for _chip in vm.chips: + count += 1 + 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") + vm = virtual_machine(2, 2) + self.assertEqual(3, vm.n_chips) + count = 0 + for _chip in vm.chip_coordinates: + count += 1 + self.assertNotIn(_chip, down_chips) + 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_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) + + self.assertTrue(vm.is_chip_at(2, 2)) + _good = vm.get_chip_at(2, 2) + self.assertEqual(_chip, _good) + + _bad = vm.get_chip_at(2, 1) + self.assertIsNone(_bad) + + count = 0 + for _chip in vm.chips: + count += 1 + 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) + + _chip = self._create_chip(2, 2) + vm.add_chip(_chip) + self.assertEqual(4, vm.n_chips) + + self.assertTrue(vm.is_chip_at(2, 2)) + _good = vm.get_chip_at(2, 2) + self.assertEqual(_chip, _good) + + _bad = vm.get_chip_at(2, 1) + self.assertIsNone(_bad) + + _down = vm.get_chip_at(1, 1) + self.assertIsNone(_down) + + count = 0 + for _chip in vm.chips: + count += 1 + 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) + self.assertFalse(vm.is_chip_at(1, 1)) + + _chip = self._create_chip(1, 1) + vm.add_chip(_chip) + self.assertEqual(4, vm.n_chips) + + self.assertTrue(vm.is_chip_at(1, 1)) + _good = vm.get_chip_at(1, 1) + self.assertEqual(_chip, _good) + + _bad = vm.get_chip_at(2, 1) + self.assertIsNone(_bad) + + count = 0 + for _chip in vm.chips: + count += 1 + self.assertEqual(4, count) + + def _check_path(self, source, target, path, width, height): + new_target = ((source[0] + path[0] - path[2]) % width, + (source[1] + path[1] - path[2]) % 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: + rig_len = shortest_mesh_path_length( + to_xyz(source), to_xyz(target)) + mac_len = machine.get_vector_length(source, target) + self.assertEqual(rig_len, mac_len) + path = machine.get_vector(source, target) + self.assertEqual( + mac_len, abs(path[0]) + abs(path[1]) + abs(path[2])) + 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) + for source in machine.chip_coordinates: + for target in machine.chip_coordinates: + rig_len = shortest_torus_path_length( + to_xyz(source), to_xyz(target), width, height) + mac_len = machine.get_vector_length(source, target) + self.assertEqual(rig_len, mac_len) + path = machine.get_vector(source, target) + self.assertEqual( + mac_len, abs(path[0]) + abs(path[1]) + abs(path[2]), + "{}{}{}".format(source, target, path)) + 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) + for source in machine.chip_coordinates: + for target in machine.chip_coordinates: + rig_no = shortest_mesh_path_length( + to_xyz(source), to_xyz(target)) + if source[0] < target[0]: + fake = (target[0] - width, target[1]) + else: + fake = (target[0] + width, target[1]) + rig_with = shortest_mesh_path_length( + to_xyz(source), to_xyz(fake)) + rig_len = min(rig_no, rig_with) + mac_len = machine.get_vector_length(source, target) + self.assertEqual(rig_len, mac_len, "{} {}".format( + source, target)) + path = machine.get_vector(source, target) + self.assertEqual( + mac_len, abs(path[0]) + abs(path[1]) + abs(path[2]), + "{}{}{}".format(source, target, path)) + 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) + for source in machine.chip_coordinates: + for target in machine.chip_coordinates: + rig_no = shortest_mesh_path_length( + to_xyz(source), to_xyz(target)) + if source[1] < target[1]: + fake = (target[0], target[1] - height) + else: + fake = (target[0], target[1] + height) + rig_with = shortest_mesh_path_length( + to_xyz(source), to_xyz(fake)) + rig_len = min(rig_no, rig_with) + mac_len = machine.get_vector_length(source, target) + self.assertEqual(rig_len, mac_len, "{} {}".format( + source, target)) + path = machine.get_vector(source, target) + self.assertEqual( + mac_len, abs(path[0]) + abs(path[1]) + abs(path[2]), + "{}{}{}".format(source, target, path)) + 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): + min1 = minimise_xyz((x, y, 0)) + min2 = machine._minimize_vector(x, y) + 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 + down_links = [ + (2, 2, 1), (2, 3, 0), (3, 4, 5), (4, 4, 4), (4, 3, 3), (3, 2, 2)] + for (x, y, link) in down_links: + if machine.is_link_at(x, y, link): + del machine._chips[x, y].router._links[link] + unreachable = machine.unreachable_incoming_chips() + 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 + for link in range(6): + if machine.is_link_at(3, 3, link): + del machine._chips[3, 3].router._links[link] + unreachable = machine.unreachable_outgoing_chips() + 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) + machine = virtual_machine(16, 16) + unreachable = machine.unreachable_incoming_local_chips() + 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) + machine = virtual_machine(16, 16) + unreachable = machine.unreachable_outgoing_local_chips() + 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) + machine = virtual_machine(16, 16) + with self.assertRaises(SpinnMachineException): + set_config("Machine", "repair_machine", False) + repaired = machine_repair(machine) + set_config("Machine", "repair_machine", True) + repaired = machine_repair(machine) + self.assertTrue(machine.is_chip_at(8, 7)) + 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 = [ + (7, 7, 0), (7, 3, 1), (6, 7, 2), (4, 7, 3), (8, 6, 4), (8, 4, 5)] + for (x, y, link) in down_links: + del machine._chips[x, y].router._links[link] + with self.assertRaises(SpinnMachineException): + set_config("Machine", "repair_machine", False) + new_machine = machine_repair(machine) + set_config("Machine", "repair_machine", True) + new_machine = machine_repair(machine) + 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 + down_links = [ + (3, 6, 0), (5, 4, 1), (3, 2, 5), (1, 3, 3)] + for (x, y, link) in down_links: + if machine.is_link_at(x, y, link): + del machine._chips[x, y].router._links[link] + with self.assertRaises(SpinnMachineException): + set_config("Machine", "repair_machine", False) + new_machine = machine_repair(machine) + set_config("Machine", "repair_machine", True) + new_machine = machine_repair(machine) + 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)] + set_config("Machine", "repair_machine", False) + new_machine = machine_repair(machine, [(3, 3)]) + self.assertIsNotNone(new_machine) + 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") + set_config("Machine", "down_links", "1,3,3:3,5,3:5,3,3,ignored_ip") + + machine = virtual_machine(8, 8) + + self.assertFalse(machine.is_chip_at(4, 4)) + self.assertFalse(machine.is_chip_at(2, 2)) + self.assertTrue(machine.is_chip_at(6, 6)) + self.assertTrue(machine.is_chip_at(0, 0)) + + chip = machine[3, 3] + self.assertFalse(chip.is_processor_with_id(3)) + + chip = machine[5, 5] + self.assertFalse(chip.is_processor_with_id(6)) + + chip = machine[7, 7] + self.assertTrue(chip.is_processor_with_id(6)) + + chip = machine[1, 1] + self.assertFalse(chip.is_processor_with_id(1)) + + router = machine[1, 3].router + self.assertFalse(router.is_link(3)) + + router = machine[3, 5].router + self.assertFalse(router.is_link(3)) + + router = machine[5, 3].router + self.assertTrue(router.is_link(3)) + + chip = machine[0, 0] + for i in range(0, 5): + self.assertTrue(chip.is_processor_with_id(i)) + for i in range(5, 11): + self.assertFalse(chip.is_processor_with_id(i)) + for i in range(12, 18): + self.assertTrue(chip.is_processor_with_id(i)) + + def test_bad_ignores(self): + try: + IgnoreChip.parse_string("4,4,3,4:6,6,ignored_ip") + except Exception as ex: + self.assertTrue("downed_chip" in str(ex)) + + try: + IgnoreCore.parse_string("3,3,3,4: 5,5,-5:7,7,7,ignored_ip") + except Exception as ex: + self.assertTrue("downed_core" in str(ex)) + + empty = IgnoreCore.parse_string(None) + self.assertEqual(len(empty), 0) + + try: + IgnoreLink.parse_string("1,3:5,3,3,ignored_ip") + except Exception as ex: + self.assertTrue("downed_link" in str(ex)) + + +if __name__ == '__main__': + unittest.main() diff --git a/unittests/test_virtual_machine3.py b/unittests/test_virtual_machine3.py new file mode 100644 index 00000000..61597d99 --- /dev/null +++ b/unittests/test_virtual_machine3.py @@ -0,0 +1,265 @@ +# Copyright (c) 2014 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +from spinn_utilities.config_holder import set_config +from spinn_machine.config_setup import unittest_setup +from spinn_machine import Chip, Link, Router, virtual_machine +from spinn_machine.exceptions import ( + SpinnMachineException, SpinnMachineAlreadyExistsException) + + +class TestVirtualMachine3(unittest.TestCase): + + def setUp(self): + unittest_setup() + + def _create_chip(self, x, y): + # Create a list of processors. + + n_processors = 18 + + links = list() + links.append(Link(0, 0, 0, 1, 1)) + links.append(Link(0, 1, 1, 1, 0)) + links.append(Link(1, 1, 2, 0, 0)) + links.append(Link(1, 0, 3, 0, 1)) + _router = Router(links, 1024) + + _sdram = 128 + nearest_ethernet_chip = (0, 0) + _ip = "192.162.240.253" + + if (x == y == 0): + return Chip(x, y, n_processors, _router, _sdram, + nearest_ethernet_chip[0], + nearest_ethernet_chip[1], _ip) + else: + return Chip(x, y, n_processors, _router, _sdram, + nearest_ethernet_chip[0], + nearest_ethernet_chip[1], None) + + def test_illegal_vms(self): + set_config("Machine", "version", 3) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=-1, height=2) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=2, height=-1) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=15, height=15) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=8, height=8) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=1, height=1) + + 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)) + self.assertTrue(vm.is_chip_at(0, 1)) + self.assertTrue(vm.is_chip_at(1, 0)) + self.assertTrue(vm.is_chip_at(1, 1)) + self.assertEqual(1, len(vm.ethernet_connected_chips)) + self.assertTrue(vm.is_link_at(0, 0, 0)) + self.assertTrue(vm.is_link_at(0, 0, 1)) + self.assertTrue(vm.is_link_at(0, 0, 2)) + self.assertFalse(vm.is_link_at(0, 0, 3)) + self.assertFalse(vm.is_link_at(0, 0, 4)) + self.assertTrue(vm.is_link_at(0, 0, 5)) + self.assertTrue(vm.is_link_at(0, 1, 0)) + self.assertTrue(vm.is_link_at(0, 1, 1)) + self.assertTrue(vm.is_link_at(0, 1, 2)) + self.assertFalse(vm.is_link_at(0, 1, 3)) + self.assertFalse(vm.is_link_at(0, 1, 4)) + self.assertTrue(vm.is_link_at(0, 1, 5)) + + self.assertFalse(vm.is_link_at(1, 0, 0)) + self.assertFalse(vm.is_link_at(1, 0, 1)) + self.assertTrue(vm.is_link_at(1, 0, 2)) + self.assertTrue(vm.is_link_at(1, 0, 3)) + self.assertTrue(vm.is_link_at(1, 0, 4)) + self.assertTrue(vm.is_link_at(1, 0, 5)) + self.assertFalse(vm.is_link_at(1, 1, 0)) + self.assertFalse(vm.is_link_at(1, 1, 1)) + self.assertTrue(vm.is_link_at(1, 1, 2)) + self.assertTrue(vm.is_link_at(1, 1, 3)) + self.assertTrue(vm.is_link_at(1, 1, 4)) + self.assertTrue(vm.is_link_at(1, 1, 5)) + + count = 0 + for _chip in vm.chips: + for _link in _chip.router.links: + count += 1 + self.assertEqual(16, count) +# self.assertEqual(str(vm), +# "[VirtualMachine: max_x=1, max_y=1, n_chips=4]") + 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[1, 1]): + count += 1 + self.assertEqual(4, count) + self.assertEqual((2, 0), vm.get_unused_xy()) + + def test_new_vm_with_max_cores(self): + set_config("Machine", "version", 2) + n_cpus = 13 + set_config("Machine", "max_machine_core", n_cpus) + vm = virtual_machine(2, 2, validate=True) + _chip = vm[1, 1] + self.assertEqual(n_cpus, _chip.n_processors) + self.assertEqual(n_cpus - 1, _chip.n_placable_processors) + self.assertEqual(1, _chip.n_scamp_processors) + self.assertEqual(n_cpus - 1, len(list(_chip.placable_processors_ids))) + self.assertEqual(1, len(list(_chip.scamp_processors_ids))) + count = sum(_chip.n_processors for _chip in vm.chips) + self.assertEqual(count, 4 * n_cpus) + + def test_iter_chips(self): + set_config("Machine", "version", 2) + vm = virtual_machine(2, 2) + self.assertEqual(4, vm.n_chips) + count = 0 + for _chip in vm.chips: + count += 1 + 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") + vm = virtual_machine(2, 2) + self.assertEqual(3, vm.n_chips) + count = 0 + for _chip in vm.chip_coordinates: + count += 1 + self.assertNotIn(_chip, down_chips) + 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_chips(self): + set_config("Machine", "version", 2) + vm = virtual_machine(2, 2) + count = 0 + for _chip in vm.chips: + count += 1 + self.assertEqual(count, 4) + + def test_ethernet_chips_exist(self): + set_config("Machine", "version", 2) + vm = virtual_machine(width=2, height=2) + for eth_chip in vm._ethernet_connected_chips: + self.assertTrue(vm.get_chip_at(eth_chip.x, eth_chip.y), + "Eth chip location x={}, y={} not in " + "_configured_chips" + .format(eth_chip.x, eth_chip.y)) + + def test_boot_chip(self): + set_config("Machine", "version", 2) + vm = virtual_machine(2, 2) + # as Chip == its XY + self.assertEqual(vm.boot_chip, (0, 0)) + + def test_get_chips_on_boards(self): + set_config("Machine", "version", 2) + vm = virtual_machine(width=2, height=2) + # check each chip appears only once on the entire board + count00 = 0 + count01 = 0 + count04 = 0 + for eth_chip in vm._ethernet_connected_chips: + list_of_chips = list(vm.get_existing_xys_on_board(eth_chip)) + self.assertEqual(len(list_of_chips), 4) + if (0, 0) in list_of_chips: + count00 += 1 + if (0, 1) in list_of_chips: + count01 += 1 + if (0, 4) in list_of_chips: + count04 += 1 + # (0,0), (0,1) are all on this virtual machine + self.assertEqual(count00, 1) + self.assertEqual(count01, 1) + + # (24,36) is not on this virtual machine + self.assertEqual(count04, 0) + + def test_fpga_links_single_board(self): + set_config("Machine", "version", 3) + machine = virtual_machine(width=2, height=2) + machine.add_fpga_links() + self.assertEqual(0, len(machine._fpga_links)) + + def test_size_2_2(self): + set_config("Machine", "version", 2) + machine = virtual_machine(2, 2, validate=True) + ethernet = machine[0, 0] + chips = set(machine.get_existing_xys_on_board(ethernet)) + self.assertEqual(len(chips), 4) + chips = set(machine.get_existing_xys_by_ethernet(0, 0)) + self.assertEqual(len(chips), 4) + global_xys = set() + for chip in machine.chips: + local_x, local_y = machine.get_local_xy(chip) + global_x, global_y = machine.get_global_xy( + local_x, local_y, + chip.nearest_ethernet_x, chip.nearest_ethernet_y) + self.assertEqual(global_x, chip.x) + self.assertEqual(global_y, chip.y) + global_xys.add((global_x, global_y)) + self.assertEqual(len(global_xys), 4) + self.assertEqual(4, len(list(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) + self.assertEqual(4, len(list(machine.get_xys_by_ethernet(0, 0)))) + count = 0 + for chip in machine.get_chips_by_ethernet(0, 0): + count += 1 + xy = (chip.x, chip.y) + assert xy not in hole + self.assertEqual(3, count) + count = 0 + for xy in machine.get_existing_xys_by_ethernet(0, 0): + count += 1 + assert xy not in hole + self.assertEqual(3, count) + + def _check_path(self, source, target, path, width, height): + new_target = ((source[0] + path[0] - path[2]) % width, + (source[1] + path[1] - path[2]) % height) + self.assertEqual(target, new_target, "{}{}".format(source, path)) + + 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)) + self.assertEqual(n_cores, 4 * 18) + n_cores = sum(chip.n_processors for chip in machine.chips) + self.assertEqual(n_cores, 4 * 18) + + +if __name__ == '__main__': + unittest.main() diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine5.py similarity index 55% rename from unittests/test_virtual_machine.py rename to unittests/test_virtual_machine5.py index ac405269..40f40983 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine5.py @@ -15,48 +15,18 @@ import unittest from spinn_utilities.config_holder import set_config from spinn_machine.config_setup import unittest_setup -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 spinn_machine.machine_factory import machine_repair +from spinn_machine import virtual_machine +from spinn_machine.exceptions import SpinnMachineException 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): +class TestVirtualMachine5(unittest.TestCase): VERSION_5_N_CORES_PER_BOARD = sum(CHIPS_PER_BOARD.values()) def setUp(self): unittest_setup() - def _create_chip(self, x, y): - # Create a list of processors. - - n_processors = 18 - - links = list() - links.append(Link(0, 0, 0, 1, 1)) - links.append(Link(0, 1, 1, 1, 0)) - links.append(Link(1, 1, 2, 0, 0)) - links.append(Link(1, 0, 3, 0, 1)) - _router = Router(links, 1024) - - _sdram = 128 - nearest_ethernet_chip = (0, 0) - _ip = "192.162.240.253" - - if (x == y == 0): - return Chip(x, y, n_processors, _router, _sdram, - nearest_ethernet_chip[0], - nearest_ethernet_chip[1], _ip) - else: - return Chip(x, y, n_processors, _router, _sdram, - nearest_ethernet_chip[0], - nearest_ethernet_chip[1], None) - def test_illegal_vms(self): set_config("Machine", "version", 5) with self.assertRaises(SpinnMachineException): @@ -65,56 +35,37 @@ def test_illegal_vms(self): virtual_machine(width=2, height=-1) with self.assertRaises(SpinnMachineException): virtual_machine(width=15, height=15) + with self.assertRaises(SpinnMachineException): + virtual_machine(5, 7) + size_x = 12 * 5 + size_y = 12 * 7 + with self.assertRaises(SpinnMachineException): + virtual_machine(size_x + 1, size_y, validate=True) + size_x = 12 * 5 + size_y = None + with self.assertRaises(SpinnMachineException): + virtual_machine(size_x, size_y, validate=True) - 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)) - self.assertTrue(vm.is_chip_at(0, 1)) - self.assertTrue(vm.is_chip_at(1, 0)) - self.assertTrue(vm.is_chip_at(1, 1)) + def test_version_5(self): + set_config("Machine", "version", 5) + vm = virtual_machine(width=8, height=8) + self.assertEqual(48, vm.n_chips) self.assertEqual(1, len(vm.ethernet_connected_chips)) - self.assertTrue(vm.is_link_at(0, 0, 0)) - self.assertTrue(vm.is_link_at(0, 0, 1)) - self.assertTrue(vm.is_link_at(0, 0, 2)) - self.assertFalse(vm.is_link_at(0, 0, 3)) - self.assertFalse(vm.is_link_at(0, 0, 4)) - self.assertTrue(vm.is_link_at(0, 0, 5)) - self.assertTrue(vm.is_link_at(0, 1, 0)) - self.assertTrue(vm.is_link_at(0, 1, 1)) - self.assertTrue(vm.is_link_at(0, 1, 2)) - self.assertFalse(vm.is_link_at(0, 1, 3)) - self.assertFalse(vm.is_link_at(0, 1, 4)) - self.assertTrue(vm.is_link_at(0, 1, 5)) - - self.assertFalse(vm.is_link_at(1, 0, 0)) - self.assertFalse(vm.is_link_at(1, 0, 1)) - self.assertTrue(vm.is_link_at(1, 0, 2)) - self.assertTrue(vm.is_link_at(1, 0, 3)) - self.assertTrue(vm.is_link_at(1, 0, 4)) - self.assertTrue(vm.is_link_at(1, 0, 5)) - self.assertFalse(vm.is_link_at(1, 1, 0)) - self.assertFalse(vm.is_link_at(1, 1, 1)) - self.assertTrue(vm.is_link_at(1, 1, 2)) - self.assertTrue(vm.is_link_at(1, 1, 3)) - self.assertTrue(vm.is_link_at(1, 1, 4)) - self.assertTrue(vm.is_link_at(1, 1, 5)) count = 0 for _chip in vm.chips: for _link in _chip.router.links: count += 1 - self.assertEqual(16, count) + self.assertEqual(240, count) + self.assertEqual(120, vm.get_links_count()) # self.assertEqual(str(vm), # "[VirtualMachine: max_x=1, max_y=1, n_chips=4]") - self.assertEqual(72, vm.get_cores_count()) - self.assertEqual(8, vm.get_links_count()) + self.assertEqual(856, vm.get_cores_count()) count = 0 for _chip in vm.get_existing_xys_on_board(vm[1, 1]): count += 1 - self.assertEqual(4, count) - self.assertEqual((2, 0), vm.get_unused_xy()) + self.assertEqual(48, count) + self.assertEqual((0, 4), vm.get_unused_xy()) def test_version_5_8_by_8(self): set_config("Machine", "version", 5) @@ -169,53 +120,6 @@ def test_version_5_hole2(self): self.assertEqual(48, len(list(vm.local_xys))) self.assertEqual((0, 4), vm.get_unused_xy()) - def test_new_vm_with_max_cores(self): - set_config("Machine", "version", 2) - n_cpus = 13 - set_config("Machine", "max_machine_core", n_cpus) - vm = virtual_machine(2, 2, validate=True) - _chip = vm[1, 1] - self.assertEqual(n_cpus, _chip.n_processors) - self.assertEqual(n_cpus - 1, _chip.n_placable_processors) - self.assertEqual(1, _chip.n_scamp_processors) - self.assertEqual(n_cpus - 1, len(list(_chip.placable_processors_ids))) - self.assertEqual(1, len(list(_chip.scamp_processors_ids))) - count = sum(_chip.n_processors for _chip in vm.chips) - self.assertEqual(count, 4 * n_cpus) - - def test_iter_chips(self): - set_config("Machine", "version", 2) - vm = virtual_machine(2, 2) - self.assertEqual(4, vm.n_chips) - count = 0 - for _chip in vm.chips: - count += 1 - 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") - vm = virtual_machine(2, 2) - self.assertEqual(3, vm.n_chips) - count = 0 - for _chip in vm.chip_coordinates: - count += 1 - self.assertNotIn(_chip, down_chips) - 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(SpinnMachineException): - virtual_machine(5, 7) - def test_12_n_plus4_12_m_4(self): set_config("Machine", "version", 5) size_x = 12 * 5 @@ -230,94 +134,13 @@ def test_12_n_12_m(self): 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(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(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) - - self.assertTrue(vm.is_chip_at(2, 2)) - _good = vm.get_chip_at(2, 2) - self.assertEqual(_chip, _good) - - _bad = vm.get_chip_at(2, 1) - self.assertIsNone(_bad) - - count = 0 - for _chip in vm.chips: - count += 1 - 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) - - _chip = self._create_chip(2, 2) - vm.add_chip(_chip) - self.assertEqual(4, vm.n_chips) - - self.assertTrue(vm.is_chip_at(2, 2)) - _good = vm.get_chip_at(2, 2) - self.assertEqual(_chip, _good) - - _bad = vm.get_chip_at(2, 1) - self.assertIsNone(_bad) - - _down = vm.get_chip_at(1, 1) - self.assertIsNone(_down) - - count = 0 - for _chip in vm.chips: - count += 1 - 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) - self.assertFalse(vm.is_chip_at(1, 1)) - - _chip = self._create_chip(1, 1) - vm.add_chip(_chip) - self.assertEqual(4, vm.n_chips) - - self.assertTrue(vm.is_chip_at(1, 1)) - _good = vm.get_chip_at(1, 1) - self.assertEqual(_chip, _good) - - _bad = vm.get_chip_at(2, 1) - self.assertIsNone(_bad) - - count = 0 - for _chip in vm.chips: - count += 1 - self.assertEqual(4, count) - def test_chips(self): - set_config("Machine", "version", 2) - vm = virtual_machine(2, 2) + set_config("Machine", "version", 5) + vm = virtual_machine(8, 8) count = 0 for _chip in vm.chips: count += 1 - self.assertEqual(count, 4) + self.assertEqual(count, 48) def test_ethernet_chips_exist(self): set_config("Machine", "version", 5) @@ -329,9 +152,10 @@ 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) + set_config("Machine", "version", 5) + vm = virtual_machine(12, 12) + # based on Chip equaling its XY + self.assertEqual(vm.boot_chip, (0, 0)) def test_get_chips_on_boards(self): set_config("Machine", "version", 5) @@ -460,26 +284,6 @@ def test_big(self): 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[0, 0] - chips = set(machine.get_existing_xys_on_board(ethernet)) - self.assertEqual(len(chips), 4) - chips = set(machine.get_existing_xys_by_ethernet(0, 0)) - self.assertEqual(len(chips), 4) - global_xys = set() - for chip in machine.chips: - local_x, local_y = machine.get_local_xy(chip) - global_x, global_y = machine.get_global_xy( - local_x, local_y, - chip.nearest_ethernet_x, chip.nearest_ethernet_y) - self.assertEqual(global_x, chip.x) - self.assertEqual(global_y, chip.y) - global_xys.add((global_x, global_y)) - self.assertEqual(len(global_xys), 4) - self.assertEqual(4, len(list(machine.local_xys))) - def test_48_28(self): set_config("Machine", "version", 5) machine = virtual_machine(48, 24, validate=True) @@ -540,24 +344,6 @@ def test_52_24(self): self.assertEqual(len(global_xys), 48 * 24) self.assertEqual(48, len(list(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) - self.assertEqual(4, len(list(machine.get_xys_by_ethernet(0, 0)))) - count = 0 - for chip in machine.get_chips_by_ethernet(0, 0): - count += 1 - xy = (chip.x, chip.y) - assert xy not in hole - self.assertEqual(3, count) - count = 0 - for xy in machine.get_existing_xys_by_ethernet(0, 0): - count += 1 - assert xy not in hole - 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)] @@ -762,261 +548,6 @@ def test_no_wrap_holes(self): assert xy not in hole self.assertEqual(46, count) - def _check_path(self, source, target, path, width, height): - new_target = ((source[0] + path[0] - path[2]) % width, - (source[1] + path[1] - path[2]) % 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: - rig_len = shortest_mesh_path_length( - to_xyz(source), to_xyz(target)) - mac_len = machine.get_vector_length(source, target) - self.assertEqual(rig_len, mac_len) - path = machine.get_vector(source, target) - self.assertEqual( - mac_len, abs(path[0]) + abs(path[1]) + abs(path[2])) - 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) - for source in machine.chip_coordinates: - for target in machine.chip_coordinates: - rig_len = shortest_torus_path_length( - to_xyz(source), to_xyz(target), width, height) - mac_len = machine.get_vector_length(source, target) - self.assertEqual(rig_len, mac_len) - path = machine.get_vector(source, target) - self.assertEqual( - mac_len, abs(path[0]) + abs(path[1]) + abs(path[2]), - "{}{}{}".format(source, target, path)) - 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) - for source in machine.chip_coordinates: - for target in machine.chip_coordinates: - rig_no = shortest_mesh_path_length( - to_xyz(source), to_xyz(target)) - if source[0] < target[0]: - fake = (target[0] - width, target[1]) - else: - fake = (target[0] + width, target[1]) - rig_with = shortest_mesh_path_length( - to_xyz(source), to_xyz(fake)) - rig_len = min(rig_no, rig_with) - mac_len = machine.get_vector_length(source, target) - self.assertEqual(rig_len, mac_len, "{} {}".format( - source, target)) - path = machine.get_vector(source, target) - self.assertEqual( - mac_len, abs(path[0]) + abs(path[1]) + abs(path[2]), - "{}{}{}".format(source, target, path)) - 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) - for source in machine.chip_coordinates: - for target in machine.chip_coordinates: - rig_no = shortest_mesh_path_length( - to_xyz(source), to_xyz(target)) - if source[1] < target[1]: - fake = (target[0], target[1] - height) - else: - fake = (target[0], target[1] + height) - rig_with = shortest_mesh_path_length( - to_xyz(source), to_xyz(fake)) - rig_len = min(rig_no, rig_with) - mac_len = machine.get_vector_length(source, target) - self.assertEqual(rig_len, mac_len, "{} {}".format( - source, target)) - path = machine.get_vector(source, target) - self.assertEqual( - mac_len, abs(path[0]) + abs(path[1]) + abs(path[2]), - "{}{}{}".format(source, target, path)) - 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): - min1 = minimise_xyz((x, y, 0)) - min2 = machine._minimize_vector(x, y) - 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 - down_links = [ - (2, 2, 1), (2, 3, 0), (3, 4, 5), (4, 4, 4), (4, 3, 3), (3, 2, 2)] - for (x, y, link) in down_links: - if machine.is_link_at(x, y, link): - del machine._chips[x, y].router._links[link] - unreachable = machine.unreachable_incoming_chips() - 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 - for link in range(6): - if machine.is_link_at(3, 3, link): - del machine._chips[3, 3].router._links[link] - unreachable = machine.unreachable_outgoing_chips() - 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) - machine = virtual_machine(16, 16) - unreachable = machine.unreachable_incoming_local_chips() - 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) - machine = virtual_machine(16, 16) - unreachable = machine.unreachable_outgoing_local_chips() - 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) - machine = virtual_machine(16, 16) - with self.assertRaises(SpinnMachineException): - set_config("Machine", "repair_machine", False) - repaired = machine_repair(machine) - set_config("Machine", "repair_machine", True) - repaired = machine_repair(machine) - self.assertTrue(machine.is_chip_at(8, 7)) - 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 = [ - (7, 7, 0), (7, 3, 1), (6, 7, 2), (4, 7, 3), (8, 6, 4), (8, 4, 5)] - for (x, y, link) in down_links: - del machine._chips[x, y].router._links[link] - with self.assertRaises(SpinnMachineException): - set_config("Machine", "repair_machine", False) - new_machine = machine_repair(machine) - set_config("Machine", "repair_machine", True) - new_machine = machine_repair(machine) - 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 - down_links = [ - (3, 6, 0), (5, 4, 1), (3, 2, 5), (1, 3, 3)] - for (x, y, link) in down_links: - if machine.is_link_at(x, y, link): - del machine._chips[x, y].router._links[link] - with self.assertRaises(SpinnMachineException): - set_config("Machine", "repair_machine", False) - new_machine = machine_repair(machine) - set_config("Machine", "repair_machine", True) - new_machine = machine_repair(machine) - 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)] - set_config("Machine", "repair_machine", False) - new_machine = machine_repair(machine, [(3, 3)]) - self.assertIsNotNone(new_machine) - 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") - set_config("Machine", "down_links", "1,3,3:3,5,3:5,3,3,ignored_ip") - - machine = virtual_machine(8, 8) - - self.assertFalse(machine.is_chip_at(4, 4)) - self.assertFalse(machine.is_chip_at(2, 2)) - self.assertTrue(machine.is_chip_at(6, 6)) - self.assertTrue(machine.is_chip_at(0, 0)) - - chip = machine[3, 3] - self.assertFalse(chip.is_processor_with_id(3)) - - chip = machine[5, 5] - self.assertFalse(chip.is_processor_with_id(6)) - - chip = machine[7, 7] - self.assertTrue(chip.is_processor_with_id(6)) - - chip = machine[1, 1] - self.assertFalse(chip.is_processor_with_id(1)) - - router = machine[1, 3].router - self.assertFalse(router.is_link(3)) - - router = machine[3, 5].router - self.assertFalse(router.is_link(3)) - - router = machine[5, 3].router - self.assertTrue(router.is_link(3)) - - chip = machine[0, 0] - for i in range(0, 5): - self.assertTrue(chip.is_processor_with_id(i)) - for i in range(5, 11): - self.assertFalse(chip.is_processor_with_id(i)) - for i in range(12, 18): - self.assertTrue(chip.is_processor_with_id(i)) - - def test_bad_ignores(self): - try: - IgnoreChip.parse_string("4,4,3,4:6,6,ignored_ip") - except Exception as ex: - self.assertTrue("downed_chip" in str(ex)) - - try: - IgnoreCore.parse_string("3,3,3,4: 5,5,-5:7,7,7,ignored_ip") - except Exception as ex: - self.assertTrue("downed_core" in str(ex)) - - empty = IgnoreCore.parse_string(None) - self.assertEqual(len(empty), 0) - - try: - IgnoreLink.parse_string("1,3:5,3,3,ignored_ip") - except Exception as ex: - self.assertTrue("downed_link" in str(ex)) - def test_n_cores_full_wrap(self): set_config("Machine", "version", 5) machine = virtual_machine(12, 12) @@ -1077,15 +608,6 @@ def test_n_cores_8_8(self): n_cores = sum(chip.n_processors for chip in machine.chips) self.assertEqual(n_cores, self.VERSION_5_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)) - self.assertEqual(n_cores, 4 * 18) - n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, 4 * 18) - if __name__ == '__main__': unittest.main() From 757dcced3ace083efdb4997884179b89a2fcf03b Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 11:19:20 +0100 Subject: [PATCH 03/54] virtual Spin1 1 Chip machine --- spinn_machine/version/version_201.py | 6 +- spinn_machine/version/version_factory.py | 8 +- unittests/test_virtual_machine201.py | 229 +++++++++++++++++++++++ unittests/version/test_version201.py | 6 +- 4 files changed, 242 insertions(+), 7 deletions(-) create mode 100644 unittests/test_virtual_machine201.py diff --git a/spinn_machine/version/version_201.py b/spinn_machine/version/version_201.py index 159f13c8..29e6b7cf 100644 --- a/spinn_machine/version/version_201.py +++ b/spinn_machine/version/version_201.py @@ -19,7 +19,7 @@ from spinn_utilities.overrides import overrides from spinn_machine.exceptions import SpinnMachineException -from spinn_machine.full_wrap_machine import FullWrapMachine +from spinn_machine.no_wrap_machine import NoWrapMachine from spinn_machine.machine import Machine from .abstract_version import AbstractVersion @@ -52,7 +52,7 @@ def n_router_entries(self) -> int: @property @overrides(AbstractVersion.minimum_cores_expected) def minimum_cores_expected(self) -> int: - return 150 + return 100 @property @overrides(AbstractVersion.clock_speeds_hz) @@ -98,7 +98,7 @@ def _verify_size(self, width: int, height: int): @overrides(AbstractVersion._create_machine) def _create_machine(self, width: int, height: int, origin: str) -> Machine: - return FullWrapMachine(width, height, CHIPS_PER_BOARD, origin) + return NoWrapMachine(width, height, CHIPS_PER_BOARD, origin) @overrides(AbstractVersion.illegal_ethernet_message) def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index 1624624e..ad57b0c7 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -36,6 +36,7 @@ def version_factory() -> AbstractVersion: # pylint: disable=import-outside-toplevel from .version_3 import Version3 from .version_5 import Version5 + from .version_201 import Version201 version = get_config_int_or_none("Machine", "version") if version in [2, 3]: @@ -44,6 +45,9 @@ def version_factory() -> AbstractVersion: if version in [4, 5]: return Version5() + if version == 201: + return Version201() + spalloc_server = get_config_str_or_none("Machine", "spalloc_server") if spalloc_server is not None: return Version5() @@ -56,9 +60,11 @@ def version_factory() -> AbstractVersion: height = get_config_int_or_none("Machine", "height") width = get_config_int_or_none("Machine", "width") if height is not None and width is not None: + logger.info("Your cfg file does not have a version") if height == width == 2: - logger.info("Your cfg file does not have a ") return Version3() + elif height == width == 1: + return Version201() return Version5() if version is None: diff --git a/unittests/test_virtual_machine201.py b/unittests/test_virtual_machine201.py new file mode 100644 index 00000000..35ee1827 --- /dev/null +++ b/unittests/test_virtual_machine201.py @@ -0,0 +1,229 @@ +# Copyright (c) 2014 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +from spinn_utilities.config_holder import set_config +from spinn_machine.config_setup import unittest_setup +from spinn_machine import Chip, Link, Router, virtual_machine +from spinn_machine.exceptions import ( + SpinnMachineException, SpinnMachineAlreadyExistsException) + + +class TestVirtualMachine201(unittest.TestCase): + + def setUp(self): + unittest_setup() + + def _create_chip(self, x, y): + # Create a list of processors. + + n_processors = 18 + + links = list() + links.append(Link(0, 0, 0, 1, 1)) + links.append(Link(0, 1, 1, 1, 0)) + links.append(Link(1, 1, 2, 0, 0)) + links.append(Link(1, 0, 3, 0, 1)) + _router = Router(links, 1024) + + _sdram = 128 + nearest_ethernet_chip = (0, 0) + _ip = "192.162.240.253" + + if (x == y == 0): + return Chip(x, y, n_processors, _router, _sdram, + nearest_ethernet_chip[0], + nearest_ethernet_chip[1], _ip) + else: + return Chip(x, y, n_processors, _router, _sdram, + nearest_ethernet_chip[0], + nearest_ethernet_chip[1], None) + + def test_illegal_vms(self): + set_config("Machine", "version", 201) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=-1, height=2) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=2, height=-1) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=15, height=15) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=8, height=8) + with self.assertRaises(SpinnMachineException): + virtual_machine(width=2, height=2) + + def test_version_201(self): + set_config("Machine", "version", 201) + vm = virtual_machine(width=1, height=1) + self.assertEqual(1, vm.n_chips) + self.assertTrue(vm.is_chip_at(0, 0)) + self.assertFalse(vm.is_chip_at(0, 1)) + self.assertEqual(1, len(vm.ethernet_connected_chips)) + self.assertFalse(vm.is_link_at(0, 0, 0)) + self.assertFalse(vm.is_link_at(0, 0, 1)) + self.assertFalse(vm.is_link_at(0, 0, 2)) + self.assertFalse(vm.is_link_at(0, 0, 3)) + self.assertFalse(vm.is_link_at(0, 0, 4)) + self.assertFalse(vm.is_link_at(0, 0, 5)) + + count = 0 + for _chip in vm.chips: + for _link in _chip.router.links: + count += 1 + self.assertEqual(0, count) + self.assertEqual(152, vm.get_cores_count()) + self.assertEqual(0, vm.get_links_count()) + count = 0 + for _chip in vm.get_existing_xys_on_board(vm[0, 0]): + count += 1 + self.assertEqual(1, count) + self.assertEqual((1, 0), vm.get_unused_xy()) + + def test_new_vm_with_max_cores(self): + set_config("Machine", "version", 201) + n_cpus = 105 + set_config("Machine", "max_machine_core", n_cpus) + vm = virtual_machine(1, 1, validate=True) + _chip = vm[0, 0] + self.assertEqual(n_cpus, _chip.n_processors) + self.assertEqual(n_cpus - 1, _chip.n_placable_processors) + self.assertEqual(1, _chip.n_scamp_processors) + self.assertEqual(n_cpus - 1, len(list(_chip.placable_processors_ids))) + self.assertEqual(1, len(list(_chip.scamp_processors_ids))) + count = sum(_chip.n_processors for _chip in vm.chips) + self.assertEqual(count, 1 * n_cpus) + + def test_iter_chips(self): + set_config("Machine", "version", 201) + vm = virtual_machine(1, 1) + self.assertEqual(1, vm.n_chips) + count = 0 + for _chip in vm.chips: + count += 1 + self.assertEqual(1, count) + + def test_add_existing_chip(self): + set_config("Machine", "version", 201) + vm = virtual_machine(1, 1) + _chip = self._create_chip(0, 0) + with self.assertRaises(SpinnMachineAlreadyExistsException): + vm.add_chip(_chip) + + def test_chips(self): + set_config("Machine", "version", 201) + vm = virtual_machine(1, 1) + count = 0 + for _chip in vm.chips: + count += 1 + self.assertEqual(count, 1) + + def test_ethernet_chips_exist(self): + set_config("Machine", "version", 201) + vm = virtual_machine(width=1, height=1) + for eth_chip in vm._ethernet_connected_chips: + self.assertTrue(vm.get_chip_at(eth_chip.x, eth_chip.y), + "Eth chip location x={}, y={} not in " + "_configured_chips" + .format(eth_chip.x, eth_chip.y)) + + def test_boot_chip(self): + set_config("Machine", "version", 201) + vm = virtual_machine(1, 1) + # as Chip == its XY + self.assertEqual(vm.boot_chip, (0, 0)) + + def test_get_chips_on_boards(self): + set_config("Machine", "version", 201) + vm = virtual_machine(width=1, height=1) + # check each chip appears only once on the entire board + count00 = 0 + count01 = 0 + count04 = 0 + for eth_chip in vm._ethernet_connected_chips: + list_of_chips = list(vm.get_existing_xys_on_board(eth_chip)) + self.assertEqual(len(list_of_chips), 1) + if (0, 0) in list_of_chips: + count00 += 1 + if (0, 1) in list_of_chips: + count01 += 1 + if (0, 4) in list_of_chips: + count04 += 1 + # (0,0) is on this virtual machine + self.assertEqual(count00, 1) + + # (0, 1), (24,36) is not on this virtual machine + self.assertEqual(count01, 0) + self.assertEqual(count04, 0) + + def test_fpga_links_single_board(self): + set_config("Machine", "version", 3) + machine = virtual_machine(width=2, height=2) + machine.add_fpga_links() + self.assertEqual(0, len(machine._fpga_links)) + + def test_size_2_2(self): + set_config("Machine", "version", 2) + machine = virtual_machine(2, 2, validate=True) + ethernet = machine[0, 0] + chips = set(machine.get_existing_xys_on_board(ethernet)) + self.assertEqual(len(chips), 4) + chips = set(machine.get_existing_xys_by_ethernet(0, 0)) + self.assertEqual(len(chips), 4) + global_xys = set() + for chip in machine.chips: + local_x, local_y = machine.get_local_xy(chip) + global_x, global_y = machine.get_global_xy( + local_x, local_y, + chip.nearest_ethernet_x, chip.nearest_ethernet_y) + self.assertEqual(global_x, chip.x) + self.assertEqual(global_y, chip.y) + global_xys.add((global_x, global_y)) + self.assertEqual(len(global_xys), 4) + self.assertEqual(4, len(list(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) + self.assertEqual(4, len(list(machine.get_xys_by_ethernet(0, 0)))) + count = 0 + for chip in machine.get_chips_by_ethernet(0, 0): + count += 1 + xy = (chip.x, chip.y) + assert xy not in hole + self.assertEqual(3, count) + count = 0 + for xy in machine.get_existing_xys_by_ethernet(0, 0): + count += 1 + assert xy not in hole + self.assertEqual(3, count) + + def _check_path(self, source, target, path, width, height): + new_target = ((source[0] + path[0] - path[2]) % width, + (source[1] + path[1] - path[2]) % height) + self.assertEqual(target, new_target, "{}{}".format(source, path)) + + 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)) + self.assertEqual(n_cores, 4 * 18) + n_cores = sum(chip.n_processors for chip in machine.chips) + self.assertEqual(n_cores, 4 * 18) + + +if __name__ == '__main__': + unittest.main() diff --git a/unittests/version/test_version201.py b/unittests/version/test_version201.py index d5759bcf..cb9ede9f 100644 --- a/unittests/version/test_version201.py +++ b/unittests/version/test_version201.py @@ -17,7 +17,7 @@ """ 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.version.version_201 import Version201 from spinn_machine.config_setup import unittest_setup from spinn_machine.exceptions import SpinnMachineException @@ -131,11 +131,11 @@ def test_verify_size(self): with self.assertRaises(SpinnMachineException): version.verify_size(16, 16) - def test_create_machin(self): + def test_create_machine(self): version = Version201() machine = version.create_machine(width=1, height=1) - self.assertIsInstance(machine, FullWrapMachine) + self.assertIsInstance(machine, NoWrapMachine) def test_processor_info(self): version = Version201() From 695b4489663a1d5673bd860c1314743e0a29b298 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 12:16:40 +0100 Subject: [PATCH 04/54] version -1 for when it only matters that there is a version --- spinn_machine/version/version_factory.py | 9 +++++++++ unittests/test_chip.py | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index ad57b0c7..e79543b3 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -14,6 +14,7 @@ from __future__ import annotations import logging +import sys from typing import TYPE_CHECKING from spinn_utilities.config_holder import ( get_config_int_or_none, get_config_str_or_none) @@ -39,6 +40,14 @@ def version_factory() -> AbstractVersion: from .version_201 import Version201 version = get_config_int_or_none("Machine", "version") + + if version == -1: + # test needs a version but which would CAN not metter + # Use the fact that we run actions against different python versions + minor = sys.version_info.minor + options = [2, 5, 201] + version = options[minor % len(options)] + if version in [2, 3]: return Version3() diff --git a/unittests/test_chip.py b/unittests/test_chip.py index e7d73cb8..b181744b 100644 --- a/unittests/test_chip.py +++ b/unittests/test_chip.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest import unittest from spinn_utilities.config_holder import set_config from spinn_utilities.ordered_set import OrderedSet @@ -23,7 +24,7 @@ class TestingChip(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) + set_config("Machine", "version", -1) self._x = 0 self._y = 1 From e36ea3dff35f968d63ed7f43cad77948919f8d07 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 12:16:57 +0100 Subject: [PATCH 05/54] version201 json --- spinn_machine/json_machine.py | 32 +++++++++++++++++--------------- unittests/test_json_machine.py | 31 ++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/spinn_machine/json_machine.py b/spinn_machine/json_machine.py index 9bde816b..f841eadd 100644 --- a/spinn_machine/json_machine.py +++ b/spinn_machine/json_machine.py @@ -236,21 +236,7 @@ def to_json() -> JsonObject: :rtype: dict """ machine = MachineDataView.get_machine() - # Find the standard values for any non-Ethernet chip to use by default - std = None - for chip in machine.chips: - if chip.ip_address is None: - std = _Desc( - monitors=chip.n_processors - chip.n_placable_processors, - router_entries=_int_value( - chip.router.n_available_multicast_entries), - sdram=chip.sdram, - tags=list(chip.tag_ids)) - break - else: - raise ValueError("could not compute standard resources") - - # find the nth values to use for Ethernet chips + # find the standard values to use for Ethernet chips chip = machine.boot_chip eth = _Desc( monitors=chip.n_processors - chip.n_placable_processors, @@ -259,6 +245,22 @@ def to_json() -> JsonObject: sdram=chip.sdram, tags=list(chip.tag_ids)) + # Find the standard values for any non-Ethernet chip to use by default + if machine.n_chips > 1: + for chip in machine.chips: + if chip.ip_address is None: + std = _Desc( + monitors=chip.n_processors - chip.n_placable_processors, + router_entries=_int_value( + chip.router.n_available_multicast_entries), + sdram=chip.sdram, + tags=list(chip.tag_ids)) + break + else: + raise ValueError("could not compute standard resources") + else: + std = eth + # write basic stuff return { "height": machine.height, diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 65a5a06a..52ee0d14 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -25,9 +25,35 @@ class TestJsonMachine(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) + + def test_json_version_3(self): + set_config("Machine", "version", 3) + vm = virtual_machine(width=2, height=2) + MachineDataWriter.mock().set_machine(vm) + jpath = mktemp("json") + to_json_path(jpath) + jm = machine_from_json(jpath) + vstr = str(vm).replace("Virtual", "") + jstr = str(jm).replace("Json", "") + self.assertEqual(vstr, jstr) + for vchip, jchip in zip(vm, jm): + self.assertEqual(str(vchip), str(jchip)) + + def test_json_version_201(self): + set_config("Machine", "version", 201) + vm = virtual_machine(width=1, height=1) + MachineDataWriter.mock().set_machine(vm) + jpath = mktemp("json") + to_json_path(jpath) + jm = machine_from_json(jpath) + vstr = str(vm).replace("Virtual", "") + jstr = str(jm).replace("Json", "") + self.assertEqual(vstr, jstr) + for vchip, jchip in zip(vm, jm): + self.assertEqual(str(vchip), str(jchip)) def test_json_version_5_hole(self): + set_config("Machine", "version", 5) set_config("Machine", "down_chips", "3,3") vm = virtual_machine(width=8, height=8) MachineDataWriter.mock().set_machine(vm) @@ -41,6 +67,7 @@ def test_json_version_5_hole(self): self.assertEqual(str(vchip), str(jchip)) def test_exceptions(self): + set_config("Machine", "version", 5) vm = virtual_machine(width=8, height=8) MachineDataWriter.mock().set_machine(vm) chip22 = vm[2, 2] @@ -59,6 +86,7 @@ def test_exceptions(self): self.assertEqual(vchip33.tag_ids, chip33.tag_ids) def test_monitor_exceptions(self): + set_config("Machine", "version", 5) vm = virtual_machine(width=8, height=8) MachineDataWriter.mock().set_machine(vm) chip02 = vm[0, 2] @@ -73,6 +101,7 @@ def test_monitor_exceptions(self): machine_from_json(jpath) def test_ethernet_exceptions(self): + set_config("Machine", "version", 5) vm = virtual_machine(width=16, height=16) MachineDataWriter.mock().set_machine(vm) chip48 = vm[4, 8] From e79a72ec8eb30cc188b170cb3b8f7684c12ee380 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 13:19:24 +0100 Subject: [PATCH 06/54] mock any version --- spinn_machine/data/machine_data_writer.py | 9 +++------ unittests/data/test_data.py | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/spinn_machine/data/machine_data_writer.py b/spinn_machine/data/machine_data_writer.py index 08dd6b21..3eda7274 100644 --- a/spinn_machine/data/machine_data_writer.py +++ b/spinn_machine/data/machine_data_writer.py @@ -46,12 +46,9 @@ def _mock_machine(self) -> None: """ Method to create a virtual machine in mock mode. """ - if self.get_machine_version().number == 3: - self.set_machine(virtual_machine(width=2, height=2)) - elif self.get_machine_version().number == 5: - self.set_machine(virtual_machine(width=8, height=8)) - else: - raise NotImplementedError("Please set machine version") + version = self.get_machine_version() + width, height = version.board_shape + self.set_machine(virtual_machine(width=width, height=height)) @overrides(UtilsDataWriter._setup) def _setup(self) -> None: diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index f0647bde..9f770632 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -94,3 +94,26 @@ def test_where_is_setup(self): "None", MachineDataView.where_is_chip(None) ) + + def test_mock_any(self): + # Should work with any version + set_config("Machine", "version", -1) + # check there is a value not what it is + MachineDataView.get_machine() + + def test_mock3(self): + # Should work with any version + set_config("Machine", "version", -1) + # check there is a value not what it is + MachineDataView.get_machine() + + def test_mock5(self): + set_config("Machine", "version", 5) + # check there is a value not what it is + MachineDataView.get_machine() + + def test_mock201(self): + set_config("Machine", "version", 201) + # check there is a value not what it is + MachineDataView.get_machine() + From 7e7aef2be0f22634196405b6043b85eec542f3cc Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 13:24:59 +0100 Subject: [PATCH 07/54] flake8 --- unittests/test_chip.py | 1 - unittests/version/test_version201.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/unittests/test_chip.py b/unittests/test_chip.py index b181744b..2dee708e 100644 --- a/unittests/test_chip.py +++ b/unittests/test_chip.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pytest import unittest from spinn_utilities.config_holder import set_config from spinn_utilities.ordered_set import OrderedSet diff --git a/unittests/version/test_version201.py b/unittests/version/test_version201.py index cb9ede9f..b36734e8 100644 --- a/unittests/version/test_version201.py +++ b/unittests/version/test_version201.py @@ -140,7 +140,7 @@ def test_create_machine(self): def test_processor_info(self): version = Version201() self.assertEqual([150, 300], version.clock_speeds_hz) - #self.assertEqual(65536, version.dtcm_bytes) + # self.assertEqual(65536, version.dtcm_bytes) if __name__ == '__main__': From bdc332b85be90ddadf123a8f8a7629e2ac4f3df9 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 13:33:08 +0100 Subject: [PATCH 08/54] flake8 --- unittests/data/test_data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index 9f770632..24851ec9 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -116,4 +116,3 @@ def test_mock201(self): set_config("Machine", "version", 201) # check there is a value not what it is MachineDataView.get_machine() - From 3de2599b5db42bbface823ee46eedf1061760a03 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 13:40:18 +0100 Subject: [PATCH 09/54] pylint --- spinn_machine/version/version_factory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index e79543b3..0db6891b 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -42,7 +42,7 @@ def version_factory() -> AbstractVersion: version = get_config_int_or_none("Machine", "version") if version == -1: - # test needs a version but which would CAN not metter + # test needs a version but ANY version will work # Use the fact that we run actions against different python versions minor = sys.version_info.minor options = [2, 5, 201] From 58c11c460eb14ae5a717ae1f95fcd512af406ecf Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 15:21:01 +0100 Subject: [PATCH 10/54] ANY_VERSION --- spinn_machine/version/__init__.py | 5 +++++ spinn_machine/version/version_factory.py | 13 +++++++++++-- unittests/data/test_data.py | 22 +++++++++++++++++++--- unittests/test_chip.py | 3 ++- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/spinn_machine/version/__init__.py b/spinn_machine/version/__init__.py index 91eaa0c5..39f93a99 100644 --- a/spinn_machine/version/__init__.py +++ b/spinn_machine/version/__init__.py @@ -11,3 +11,8 @@ # 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 ( + ANY_VERSION, FOUR_PLUS_CHIPS, version_factory) + +__all__ = ["ANY_VERSION", "FOUR_PLUS_CHIPS", "version_factory"] \ No newline at end of file diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index 0db6891b..18c4f8de 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -25,6 +25,9 @@ logger = FormatAdapter(logging.getLogger(__name__)) +ANY_VERSION = -11 +FOUR_PLUS_CHIPS = -2 + def version_factory() -> AbstractVersion: """ @@ -41,11 +44,17 @@ def version_factory() -> AbstractVersion: version = get_config_int_or_none("Machine", "version") - if version == -1: + if version < 0: # test needs a version but ANY version will work + if version == ANY_VERSION: + options = [2, 5, 201] + elif version == FOUR_PLUS_CHIPS: + options = [2, 5] + else: + raise SpinnMachineException( + f"Unexpected cfg [Machine]version {version}") # Use the fact that we run actions against different python versions minor = sys.version_info.minor - options = [2, 5, 201] version = options[minor % len(options)] if version in [2, 3]: diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index 24851ec9..685dcc10 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -19,6 +19,7 @@ from spinn_machine.config_setup import unittest_setup from spinn_machine.data import MachineDataView from spinn_machine.data.machine_data_writer import MachineDataWriter +from spinn_machine.version import ANY_VERSION, FOUR_PLUS_CHIPS class TestSimulatorData(unittest.TestCase): @@ -97,13 +98,28 @@ def test_where_is_setup(self): def test_mock_any(self): # Should work with any version - set_config("Machine", "version", -1) + set_config("Machine", "version", ANY_VERSION) # check there is a value not what it is - MachineDataView.get_machine() + machine = MachineDataView.get_machine() + self.assertGreaterEqual(1, machine.n_chips) + + def test_mock_4_or_more(self): + # Should work with any version + set_config("Machine", "version", FOUR_PLUS_CHIPS) + # check there is a value not what it is + machine = MachineDataView.get_machine() + self.assertGreaterEqual(machine.n_chips, 4) + + def test_mockFourPlus(self): + # Should work with any version + set_config("Machine", "version", ANY_VERSION) + # check there is a value not what it is + machine = MachineDataView.get_machine() + self.assertGreaterEqual(4, machine.n_chips) def test_mock3(self): # Should work with any version - set_config("Machine", "version", -1) + set_config("Machine", "version", 3) # check there is a value not what it is MachineDataView.get_machine() diff --git a/unittests/test_chip.py b/unittests/test_chip.py index 2dee708e..0d0fac6f 100644 --- a/unittests/test_chip.py +++ b/unittests/test_chip.py @@ -17,13 +17,14 @@ from spinn_utilities.ordered_set import OrderedSet from spinn_machine import Link, Router, Chip from spinn_machine.config_setup import unittest_setup +from spinn_machine.version import ANY_VERSION class TestingChip(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", -1) + set_config("Machine", "version", ANY_VERSION) self._x = 0 self._y = 1 From 05edc85a65770370c491372660708903ae060204 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 16:12:41 +0100 Subject: [PATCH 11/54] multiple flexible versions --- spinn_machine/version/__init__.py | 4 +- spinn_machine/version/version_factory.py | 5 +- unittests/test_json_machine.py | 88 +++++++++++++++--------- 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/spinn_machine/version/__init__.py b/spinn_machine/version/__init__.py index 39f93a99..489f6f94 100644 --- a/spinn_machine/version/__init__.py +++ b/spinn_machine/version/__init__.py @@ -13,6 +13,6 @@ # limitations under the License. from .version_factory import ( - ANY_VERSION, FOUR_PLUS_CHIPS, version_factory) + ANY_VERSION, BIG_MACHINE, FOUR_PLUS_CHIPS, version_factory) -__all__ = ["ANY_VERSION", "FOUR_PLUS_CHIPS", "version_factory"] \ No newline at end of file +__all__ = ["ANY_VERSION", "BIG_MACHINE", "FOUR_PLUS_CHIPS", "version_factory"] \ No newline at end of file diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index 18c4f8de..e2633848 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -25,8 +25,9 @@ logger = FormatAdapter(logging.getLogger(__name__)) -ANY_VERSION = -11 +ANY_VERSION = -1 FOUR_PLUS_CHIPS = -2 +BIG_MACHINE = -3 def version_factory() -> AbstractVersion: @@ -50,6 +51,8 @@ def version_factory() -> AbstractVersion: options = [2, 5, 201] elif version == FOUR_PLUS_CHIPS: options = [2, 5] + elif version == BIG_MACHINE: + options = [5] else: raise SpinnMachineException( f"Unexpected cfg [Machine]version {version}") diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 52ee0d14..d16f5c9b 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -19,6 +19,7 @@ from spinn_machine.data.machine_data_writer import MachineDataWriter from spinn_machine.config_setup import unittest_setup from spinn_machine.json_machine import (machine_from_json, to_json_path) +from spinn_machine.version import BIG_MACHINE, FOUR_PLUS_CHIPS class TestJsonMachine(unittest.TestCase): @@ -39,6 +40,19 @@ def test_json_version_3(self): for vchip, jchip in zip(vm, jm): self.assertEqual(str(vchip), str(jchip)) + def test_json_version_5(self): + set_config("Machine", "version", 5) + vm = virtual_machine(width=8, height=8) + MachineDataWriter.mock().set_machine(vm) + jpath = mktemp("json") + to_json_path(jpath) + jm = machine_from_json(jpath) + vstr = str(vm).replace("Virtual", "") + jstr = str(jm).replace("Json", "") + self.assertEqual(vstr, jstr) + for vchip, jchip in zip(vm, jm): + self.assertEqual(str(vchip), str(jchip)) + def test_json_version_201(self): set_config("Machine", "version", 201) vm = virtual_machine(width=1, height=1) @@ -52,11 +66,13 @@ def test_json_version_201(self): for vchip, jchip in zip(vm, jm): self.assertEqual(str(vchip), str(jchip)) - def test_json_version_5_hole(self): - set_config("Machine", "version", 5) + def test_json_hole(self): + set_config("Machine", "version", BIG_MACHINE) set_config("Machine", "down_chips", "3,3") - vm = virtual_machine(width=8, height=8) - MachineDataWriter.mock().set_machine(vm) + writer = MachineDataWriter.mock() + width, heigth = writer.get_machine_version().board_shape + vm = virtual_machine(width, heigth) + writer.set_machine(vm) jpath = mktemp("json") to_json_path(jpath) jm = machine_from_json(jpath) @@ -67,32 +83,36 @@ def test_json_version_5_hole(self): self.assertEqual(str(vchip), str(jchip)) def test_exceptions(self): - set_config("Machine", "version", 5) - vm = virtual_machine(width=8, height=8) - MachineDataWriter.mock().set_machine(vm) - chip22 = vm[2, 2] - router22 = chip22.router - router22._n_available_multicast_entries = \ - router22._n_available_multicast_entries - 20 - chip33 = vm[3, 3] - chip33._sdram = 50000000 - chip33._tag_ids = [2, 3] + set_config("Machine", "version", FOUR_PLUS_CHIPS) + writer = MachineDataWriter.mock() + width, heigth = writer.get_machine_version().board_shape + vm = virtual_machine(width, heigth) + writer.set_machine(vm) + chip01 = vm[0, 1] + router01 = chip01.router + router01._n_available_multicast_entries = \ + router01._n_available_multicast_entries - 20 + chip10 = vm[1, 0] + chip10._sdram = 50000000 + chip10._tag_ids = [2, 3] jpath = mktemp("json") to_json_path(jpath) jm = machine_from_json(jpath) for vchip, jchip in zip(vm, jm): self.assertEqual(str(vchip), str(jchip)) - vchip33 = jm[3, 3] - self.assertEqual(vchip33.tag_ids, chip33.tag_ids) + vchip10 = jm[1, 0] + self.assertEqual(vchip10.tag_ids, chip10.tag_ids) def test_monitor_exceptions(self): - set_config("Machine", "version", 5) - vm = virtual_machine(width=8, height=8) - MachineDataWriter.mock().set_machine(vm) - chip02 = vm[0, 2] + set_config("Machine", "version", FOUR_PLUS_CHIPS) + writer = MachineDataWriter.mock() + width, heigth = writer.get_machine_version().board_shape + vm = virtual_machine(width, heigth) + writer.set_machine(vm) + chip01 = vm[0, 1] # Hack in an extra monitor - chip02._scamp_processors = tuple([0, 1]) - chip02._placable_processors = tuple([2, 3, 4, 5, 6, 7, 8, 9]) + chip01._scamp_processors = tuple([0, 1]) + chip01._placable_processors = tuple([2, 3, 4, 5, 6, 7, 8, 9]) jpath = mktemp("json") # Should still be able to write json even with more than one monitor to_json_path(jpath) @@ -101,22 +121,24 @@ def test_monitor_exceptions(self): machine_from_json(jpath) def test_ethernet_exceptions(self): - set_config("Machine", "version", 5) - vm = virtual_machine(width=16, height=16) - MachineDataWriter.mock().set_machine(vm) - chip48 = vm[4, 8] - router48 = chip48.router - router48._n_available_multicast_entries = \ - router48._n_available_multicast_entries - 20 - chip48._sdram = 50000000 - chip48._tag_ids = [2, 3] + set_config("Machine", "version", BIG_MACHINE) + writer = MachineDataWriter.mock() + width, heigth = writer.get_machine_version().board_shape + vm = virtual_machine(width*2, heigth*2) + writer.set_machine(vm) + chip_e_1 = vm.ethernet_connected_chips[1] + router_e_1= chip_e_1.router + router_e_1._n_available_multicast_entries = \ + router_e_1._n_available_multicast_entries - 20 + chip_e_1._sdram = 50000000 + chip_e_1._tag_ids = [2, 3] jpath = mktemp("json") to_json_path(jpath) jm = machine_from_json(jpath) for vchip, jchip in zip(vm, jm): self.assertEqual(str(vchip), str(jchip)) - vchip48 = jm[4, 8] - self.assertEqual(vchip48.tag_ids, chip48.tag_ids) + vchip_e_1 = jm.ethernet_connected_chips[1] + self.assertEqual(vchip_e_1.tag_ids, chip_e_1.tag_ids) if __name__ == '__main__': From 2875adfe08709d6018dd29db68ce590b1ad99b08 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 3 Apr 2024 16:49:00 +0100 Subject: [PATCH 12/54] version sets spinnaker links --- spinn_machine/machine.py | 28 ++++++++++------------- spinn_machine/version/abstract_version.py | 13 ++++++++++- spinn_machine/version/version_3.py | 6 ++++- spinn_machine/version/version_5.py | 6 ++++- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 1e496504..9306a1b6 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -853,22 +853,18 @@ def add_spinnaker_links(self) -> None: Add SpiNNaker links that are on a given machine depending on the version of the board. """ - if self._width == self._height == 2: - chip_0_0 = self[0, 0] - ip_0_0 = chip_0_0.ip_address - assert ip_0_0 is not None - if not chip_0_0.router.is_link(3): - self._add_spinnaker_link(0, 0, 0, 3, ip_0_0) - chip = self.get_chip_at(1, 0) - if chip is not None and not chip.router.is_link(0): - self._add_spinnaker_link(1, 1, 0, 0, ip_0_0) - elif (self._width == self._height == 8) or \ - self.multiple_48_chip_boards(): - for chip in self._ethernet_connected_chips: - if not chip.router.is_link(4): - ip = chip.ip_address - assert ip is not None - self._add_spinnaker_link(0, chip.x, chip.y, 4, ip) + version = MachineDataView.get_machine_version() + for ethernet in self._ethernet_connected_chips: + ip = ethernet.ip_address + assert ip is not None + for (s_id, (local_x, local_y, link)) in enumerate( + version.spinnaker_links()): + global_x, global_y = self.get_global_xy( + local_x, local_y, ethernet.x, ethernet.y) + chip = self.get_chip_at(global_x, global_y) + if not chip.router.is_link(link): + self._add_spinnaker_link( + s_id, global_x, global_y, link, ip) def _add_spinnaker_link( self, spinnaker_link_id: int, x: int, y: int, link: int, diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index c437c48a..940bd231 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -13,7 +13,7 @@ # limitations under the License. from __future__ import annotations import logging -from typing import Mapping, Optional, Sequence, Tuple, TYPE_CHECKING +from typing import List, Mapping, Optional, Sequence, Tuple, TYPE_CHECKING from spinn_utilities.abstract_base import AbstractBase, abstractmethod from spinn_utilities.log import FormatAdapter from spinn_utilities.config_holder import get_config_int_or_none @@ -351,3 +351,14 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: :return: An explanation that the x and y can never be an Ethernet """ raise NotImplementedError + + def spinnaker_links(self) -> List[Tuple[int, int, int]]: + """ + The list of Local X, Y and link Id to add spinnaker links to + + These are applied local to each Ethernet Chip and only if the link is + not connected to another board + + :rtype: List((int, int, int)) + """ + raise NotImplementedError diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index a186ccb6..75e05bfb 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Final, Mapping, Optional, Sequence, Tuple +from typing import Final, List, Mapping, Optional, Sequence, Tuple from spinn_utilities.overrides import overrides from spinn_utilities.typing.coords import XY from spinn_machine.exceptions import SpinnMachineException @@ -72,3 +72,7 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: if x != 0 or y != 0: return "Only Chip 0, 0 may be an Ethernet Chip" return None + + @overrides(VersionSpin1.spinnaker_links) + def spinnaker_links(self) -> List[Tuple[int, int, int]]: + return [(0, 0, 3), (1, 0, 0)] \ No newline at end of file diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index 178432dd..cf4530db 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Final, Mapping, Optional, Sequence, Tuple +from typing import Final, List, Mapping, Optional, Sequence, Tuple from spinn_utilities.overrides import overrides from spinn_utilities.typing.coords import XY from spinn_machine.exceptions import SpinnMachineException @@ -107,3 +107,7 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: return "Only Chip with x + y divisible by 12 " \ "may be an Ethernet Chip" return None + + @overrides(VersionSpin1.spinnaker_links) + def spinnaker_links(self) -> List[Tuple[int, int, int]]: + return [(0, 0, 4)] \ No newline at end of file From ac1561954c646f43b8369889fdc10e7b90454837 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 4 Apr 2024 07:42:13 +0100 Subject: [PATCH 13/54] add str and repr --- spinn_machine/link_data_objects/spinnaker_link_data.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spinn_machine/link_data_objects/spinnaker_link_data.py b/spinn_machine/link_data_objects/spinnaker_link_data.py index f2dcfd64..de932f66 100644 --- a/spinn_machine/link_data_objects/spinnaker_link_data.py +++ b/spinn_machine/link_data_objects/spinnaker_link_data.py @@ -55,3 +55,11 @@ def __hash__(self) -> int: return hash((self._spinnaker_link_id, self.connected_chip_x, self.connected_chip_y, self.connected_link, self.board_address)) + + def __str__(self): + return (f"id:{self._spinnaker_link_id} x:{self.connected_chip_x} " + f"y:{self.connected_chip_y} link:{self._spinnaker_link_id} " + f"{self.board_address}") + + def __repr__(self) -> str: + return self.__str__() From 4869a16701e0e05ceec3ec9a90cf6a9ea917b033 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 4 Apr 2024 07:42:26 +0100 Subject: [PATCH 14/54] test spinnaker links --- unittests/test_virtual_machine.py | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index ac405269..517c4e10 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -19,6 +19,7 @@ from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink +from spinn_machine.link_data_objects import SpinnakerLinkData 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, @@ -115,6 +116,15 @@ def test_version_2(self): count += 1 self.assertEqual(4, count) self.assertEqual((2, 0), vm.get_unused_xy()) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + sp = SpinnakerLinkData(0, 0, 0, 3, '127.0.0.0') + expected.append((('127.0.0.0', 0), sp)) + expected.append((((0, 0), 0), sp)) + sp = SpinnakerLinkData(1, 1, 0, 0, '127.0.0.0') + expected.append((('127.0.0.0', 1), sp)) + expected.append((((1, 0), 1), sp)) + self.assertEqual(expected, spinnaker_links) def test_version_5_8_by_8(self): set_config("Machine", "version", 5) @@ -128,6 +138,12 @@ def test_version_5_8_by_8(self): self.assertEqual(240, count) count = sum(_chip.n_processors for _chip in vm.chips) self.assertEqual(count, 856) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + sp = SpinnakerLinkData(0, 0, 0, 4, '127.0.0.0') + expected.append((('127.0.0.0', 0), sp)) + expected.append((((0, 0), 0), sp)) + self.assertEqual(expected, spinnaker_links) def test_version_5_12_by_12(self): set_config("Machine", "version", 5) @@ -141,6 +157,31 @@ def test_version_5_12_by_12(self): count += 1 self.assertEqual(48, count) self.assertEqual((12, 0), vm.get_unused_xy()) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + self.assertEqual(expected, spinnaker_links) + + def test_version_5_16_by_16(self): + set_config("Machine", "version", 5) + vm = virtual_machine(height=16, width=16, validate=True) + self.assertEqual(144, vm.n_chips) + self.assertEqual(3, len(vm.ethernet_connected_chips)) + count = sum(1 for _chip in vm.chips for _link in _chip.router.links) + self.assertEqual(768, count) + count = 0 + for _chip in vm.get_existing_xys_on_board(vm[1, 1]): + count += 1 + self.assertEqual(48, count) + self.assertEqual((0, 4), vm.get_unused_xy()) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + sp = SpinnakerLinkData(0, 0, 0, 4, '127.0.0.0') + expected.append((('127.0.0.0', 0), sp)) + expected.append((((0, 0), 0), sp)) + sp = SpinnakerLinkData(0, 4, 8, 4, '127.0.4.8') + expected.append((('127.0.4.8', 0), sp)) + expected.append((((4, 8), 0), sp)) + self.assertEqual(expected, spinnaker_links) def test_version_5_hole(self): set_config("Machine", "version", 5) From cf77e45fafdd9d126e491bd8590315cc40a56cd7 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 4 Apr 2024 07:47:21 +0100 Subject: [PATCH 15/54] flake8 --- spinn_machine/version/version_3.py | 2 +- spinn_machine/version/version_5.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index 75e05bfb..84884b0c 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -75,4 +75,4 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: @overrides(VersionSpin1.spinnaker_links) def spinnaker_links(self) -> List[Tuple[int, int, int]]: - return [(0, 0, 3), (1, 0, 0)] \ No newline at end of file + return [(0, 0, 3), (1, 0, 0)] diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index cf4530db..f3e1c934 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -110,4 +110,4 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: @overrides(VersionSpin1.spinnaker_links) def spinnaker_links(self) -> List[Tuple[int, int, int]]: - return [(0, 0, 4)] \ No newline at end of file + return [(0, 0, 4)] From 79c5e3c7c58fb6c160f9f096105d5341ae03b6d0 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 4 Apr 2024 07:54:07 +0100 Subject: [PATCH 16/54] reinsert check for None --- spinn_machine/machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 9306a1b6..77a4a22f 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -862,7 +862,7 @@ def add_spinnaker_links(self) -> None: global_x, global_y = self.get_global_xy( local_x, local_y, ethernet.x, ethernet.y) chip = self.get_chip_at(global_x, global_y) - if not chip.router.is_link(link): + if chip is not None and not chip.router.is_link(link): self._add_spinnaker_link( s_id, global_x, global_y, link, ip) From fd88e5160e0f8368c501ea6b1f4045e2b060c8a2 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 5 Apr 2024 09:57:56 +0100 Subject: [PATCH 17/54] tests taken from master's values --- unittests/test_virtual_machine.py | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index 517c4e10..a3a02fc6 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -144,6 +144,59 @@ def test_version_5_8_by_8(self): expected.append((('127.0.0.0', 0), sp)) expected.append((((0, 0), 0), sp)) self.assertEqual(expected, spinnaker_links) + # 8 links on each of the 6 sides recorded 3 times + # Except for the Ethernet Chip's 3 links which are only recorded twice + expected_fpgas = 8 * 6 * 3 - 3 + self.assertEqual(expected_fpgas, len(vm._fpga_links)) + keys = set([('127.0.0.0', 0, 0), ((7, 3), 0, 0), ((0, 0), 0, 0), + ('127.0.0.0', 0, 1), ((7, 3), 0, 1), ((0, 0), 0, 1), + ('127.0.0.0', 0, 2), ((6, 2), 0, 2), ((0, 0), 0, 2), + ('127.0.0.0', 0, 3), ((6, 2), 0, 3), ((0, 0), 0, 3), + ('127.0.0.0', 0, 4), ((5, 1), 0, 4), ((0, 0), 0, 4), + ('127.0.0.0', 0, 5), ((5, 1), 0, 5), ((0, 0), 0, 5), + ('127.0.0.0', 0, 6), ((4, 0), 0, 6), ((0, 0), 0, 6), + ('127.0.0.0', 0, 7), ((4, 0), 0, 7), ((0, 0), 0, 7), + ('127.0.0.0', 0, 8), ((4, 0), 0, 8), ((0, 0), 0, 8), + ('127.0.0.0', 0, 9), ((3, 0), 0, 9), ((0, 0), 0, 9), + ('127.0.0.0', 0, 10), ((3, 0), 0, 10), ((0, 0), 0, 10), + ('127.0.0.0', 0, 11), ((2, 0), 0, 11), ((0, 0), 0, 11), + ('127.0.0.0', 0, 12), ((2, 0), 0, 12), ((0, 0), 0, 12), + ('127.0.0.0', 0, 13), ((1, 0), 0, 13), ((0, 0), 0, 13), + ('127.0.0.0', 0, 14), ((1, 0), 0, 14), ((0, 0), 0, 14), + ('127.0.0.0', 0, 15), ((0, 0), 0, 15), + ('127.0.0.0', 1, 0), ((0, 0), 1, 0), + ('127.0.0.0', 1, 1), ((0, 0), 1, 1), + ('127.0.0.0', 1, 2), ((0, 1), 1, 2), ((0, 0), 1, 2), + ('127.0.0.0', 1, 3), ((0, 1), 1, 3), ((0, 0), 1, 3), + ('127.0.0.0', 1, 4), ((0, 2), 1, 4), ((0, 0), 1, 4), + ('127.0.0.0', 1, 5), ((0, 2), 1, 5), ((0, 0), 1, 5), + ('127.0.0.0', 1, 6), ((0, 3), 1, 6), ((0, 0), 1, 6), + ('127.0.0.0', 1, 7), ((0, 3), 1, 7), ((0, 0), 1, 7), + ('127.0.0.0', 1, 8), ((0, 3), 1, 8), ((0, 0), 1, 8), + ('127.0.0.0', 1, 9), ((1, 4), 1, 9), ((0, 0), 1, 9), + ('127.0.0.0', 1, 10), ((1, 4), 1, 10), ((0, 0), 1, 10), + ('127.0.0.0', 1, 11), ((2, 5), 1, 11), ((0, 0), 1, 11), + ('127.0.0.0', 1, 12), ((2, 5), 1, 12), ((0, 0), 1, 12), + ('127.0.0.0', 1, 13), ((3, 6), 1, 13), ((0, 0), 1, 13), + ('127.0.0.0', 1, 14), ((3, 6), 1, 14), ((0, 0), 1, 14), + ('127.0.0.0', 1, 15), ((4, 7), 1, 15), ((0, 0), 1, 15), + ('127.0.0.0', 2, 0), ((4, 7), 2, 0), ((0, 0), 2, 0), + ('127.0.0.0', 2, 1), ((4, 7), 2, 1), ((0, 0), 2, 1), + ('127.0.0.0', 2, 2), ((5, 7), 2, 2), ((0, 0), 2, 2), + ('127.0.0.0', 2, 3), ((5, 7), 2, 3), ((0, 0), 2, 3), + ('127.0.0.0', 2, 4), ((6, 7), 2, 4), ((0, 0), 2, 4), + ('127.0.0.0', 2, 5), ((6, 7), 2, 5), ((0, 0), 2, 5), + ('127.0.0.0', 2, 6), ((7, 7), 2, 6), ((0, 0), 2, 6), + ('127.0.0.0', 2, 7), ((7, 7), 2, 7), ((0, 0), 2, 7), + ('127.0.0.0', 2, 8), ((7, 7), 2, 8), ((0, 0), 2, 8), + ('127.0.0.0', 2, 9), ((7, 6), 2, 9), ((0, 0), 2, 9), + ('127.0.0.0', 2, 10), ((7, 6), 2, 10), ((0, 0), 2, 10), + ('127.0.0.0', 2, 11), ((7, 5), 2, 11), ((0, 0), 2, 11), + ('127.0.0.0', 2, 12), ((7, 5), 2, 12), ((0, 0), 2, 12), + ('127.0.0.0', 2, 13), ((7, 4), 2, 13), ((0, 0), 2, 13), + ('127.0.0.0', 2, 14), ((7, 4), 2, 14), ((0, 0), 2, 14), + ('127.0.0.0', 2, 15), ((7, 3), 2, 15), ((0, 0), 2, 15)]) + self.assertEqual(keys, set(vm._fpga_links.keys())) def test_version_5_12_by_12(self): set_config("Machine", "version", 5) @@ -160,6 +213,10 @@ def test_version_5_12_by_12(self): spinnaker_links = (list(vm.spinnaker_links)) expected = [] self.assertEqual(expected, spinnaker_links) + # 8 links on each of the 6 sides recorded 3 times + # Except for the Ethernet Chip's 3 links which are only recorded twice + expected_fpgas = (8 * 6 * 3 - 3) * 3 + self.assertEqual(expected_fpgas, len(vm._fpga_links)) def test_version_5_16_by_16(self): set_config("Machine", "version", 5) @@ -182,6 +239,10 @@ def test_version_5_16_by_16(self): expected.append((('127.0.4.8', 0), sp)) expected.append((((4, 8), 0), sp)) self.assertEqual(expected, spinnaker_links) + # 8 links on each of the 6 sides recorded 3 times + # Except for the Ethernet Chip's 3 links which are only recorded twice + expected_fpgas = (8 * 6 * 3 - 3) * 3 + self.assertEqual(expected_fpgas, len(vm._fpga_links)) def test_version_5_hole(self): set_config("Machine", "version", 5) From dd4fdd6e8ff77cf997d4b760121f5e93d42b0f35 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 5 Apr 2024 14:25:27 +0100 Subject: [PATCH 18/54] more tests based on master --- unittests/test_virtual_machine.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index a3a02fc6..dedf3b8e 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -197,6 +197,29 @@ def test_version_5_8_by_8(self): ('127.0.0.0', 2, 14), ((7, 4), 2, 14), ((0, 0), 2, 14), ('127.0.0.0', 2, 15), ((7, 3), 2, 15), ((0, 0), 2, 15)]) self.assertEqual(keys, set(vm._fpga_links.keys())) + data = set() + for (_, fpga_id, fpga_link), link in vm._fpga_links.items(): + data.add((link.connected_chip_x, link.connected_chip_y, + link.connected_link, fpga_id, fpga_link)) + expected = set([(7, 3, 0, 0, 0), (7, 3, 5, 0, 1), (6, 2, 0, 0, 2), + (6, 2, 5, 0, 3), (5, 1, 0, 0, 4), (5, 1, 5, 0, 5), + (4, 0, 0, 0, 6), (4, 0, 5, 0, 7), (4, 0, 4, 0, 8), + (3, 0, 5, 0, 9), (3, 0, 4, 0, 10), (2, 0, 5, 0, 11), + (2, 0, 4, 0, 12), (1, 0, 5, 0, 13), (1, 0, 4, 0, 14), + (0, 0, 5, 0, 15), + (0, 0, 4, 1, 0), (0, 0, 3, 1, 1), (0, 1, 4, 1, 2), + (0, 1, 3, 1, 3), (0, 2, 4, 1, 4), (0, 2, 3, 1, 5), + (0, 3, 4, 1, 6), (0, 3, 3, 1, 7), (0, 3, 2, 1, 8), + (1, 4, 3, 1, 9), (1, 4, 2, 1, 10), (2, 5, 3, 1, 11), + (2, 5, 2, 1, 12), (3, 6, 3, 1, 13), (3, 6, 2, 1, 14), + (4, 7, 3, 1, 15), + (4, 7, 2, 2, 0), (4, 7, 1, 2, 1), (5, 7, 2, 2, 2), + (5, 7, 1, 2, 3), (6, 7, 2, 2, 4), (6, 7, 1, 2, 5), + (7, 7, 2, 2, 6), (7, 7, 1, 2, 7), (7, 7, 0, 2, 8), + (7, 6, 1, 2, 9), (7, 6, 0, 2, 10), (7, 5, 1, 2, 11), + (7, 5, 0, 2, 12), (7, 4, 1, 2, 13),(7, 4, 0, 2, 14), + (7, 3, 1, 2, 15)]) + self.assertEqual(data, expected) def test_version_5_12_by_12(self): set_config("Machine", "version", 5) From e4cd2264542fc5a1334ecabc7f958650ef244909 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 5 Apr 2024 14:32:52 +0100 Subject: [PATCH 19/54] move fpga link creation data to Version using a simple list --- spinn_machine/machine.py | 85 ++++++----------------- spinn_machine/version/abstract_version.py | 11 +++ spinn_machine/version/version_3.py | 4 ++ spinn_machine/version/version_5.py | 25 +++++++ unittests/test_virtual_machine.py | 2 +- 5 files changed, 64 insertions(+), 63 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 77a4a22f..454938d8 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -876,75 +876,36 @@ def _add_spinnaker_link( def add_fpga_links(self) -> None: """ - Add FPGA links that are on a given machine depending on the + Add fpga links that are on a given machine depending on the version of the board. """ - if self._width == self._height == 8 or self.multiple_48_chip_boards(): - - for ethernet_connected_chip in self._ethernet_connected_chips: - - # the sides of the hexagonal shape of the board are as follows - # - # - # Top - # #### - # ##### - # Top Left ###### Right - # ####### - # ######## - # ####### - # Left ###### Bottom Right - # ##### - # Bottom - # - - # handle the first chip - (ex, ey) = ethernet_connected_chip - ip = ethernet_connected_chip.ip_address - assert ip is not None - - # List of start x, start y, first link, second link, - # change in x to next, change in y to next - chip_links = [(7, 3, 0, 5, -1, -1), # Bottom Right - (4, 0, 4, 5, -1, 0), # Bottom - (0, 0, 4, 3, 0, 1), # Left - (0, 3, 2, 3, 1, 1), # Top Left - (4, 7, 2, 1, 1, 0), # Top - (7, 7, 0, 1, 0, -1)] # Right - - f = 0 - lk = 0 - for i, (x, y, l1, l2, dx, dy) in enumerate(chip_links): - for _ in range(4): - fx = (x + ex) % (self._width) - fy = (y + ey) % (self._height) - self._add_fpga_link(f, lk, fx, fy, l1, ip, ex, ey) - f, lk = self._next_fpga_link(f, lk) - if i % 2 == 1: - x += dx - y += dy - fx = (x + ex) % (self._width) - fy = (y + ey) % (self._height) - self._add_fpga_link(f, lk, fx, fy, l2, ip, ex, ey) - f, lk = self._next_fpga_link(f, lk) - if i % 2 == 0: - x += dx - y += dy + version = MachineDataView.get_machine_version() + for ethernet in self._ethernet_connected_chips: + ip = ethernet.ip_address + assert ip is not None + for (local_x, local_y, link, fpga_id, fpga_link) in \ + version.fpga_links(): + global_x, global_y = self.get_global_xy( + local_x, local_y, ethernet.x, ethernet.y) + chip = self.get_chip_at(global_x, global_y) + if chip is not None: + self._add_fpga_link(fpga_id, fpga_link, chip.x, chip.y, + link, ip, ethernet.x, ethernet.y) + def _add_fpga_link( self, fpga_id: int, fpga_link: int, x: int, y: int, link: int, board_address: str, ex: int, ey: int): # pylint: disable=too-many-arguments - if self.is_chip_at(x, y): - link_data = FPGALinkData( - fpga_link_id=fpga_link, fpga_id=fpga_id, - connected_chip_x=x, connected_chip_y=y, - connected_link=link, board_address=board_address) - self._fpga_links[board_address, fpga_id, fpga_link] = link_data - # Add for the exact chip coordinates - self._fpga_links[(x, y), fpga_id, fpga_link] = link_data - # Add for the Ethernet chip coordinates to allow this to work too - self._fpga_links[(ex, ey), fpga_id, fpga_link] = link_data + link_data = FPGALinkData( + fpga_link_id=fpga_link, fpga_id=fpga_id, + connected_chip_x=x, connected_chip_y=y, + connected_link=link, board_address=board_address) + self._fpga_links[board_address, fpga_id, fpga_link] = link_data + # Add for the exact chip coordinates + self._fpga_links[(x, y), fpga_id, fpga_link] = link_data + # Add for the Ethernet chip coordinates to allow this to work too + self._fpga_links[(ex, ey), fpga_id, fpga_link] = link_data @staticmethod def _next_fpga_link(fpga_id: int, fpga_link: int) -> Tuple[int, int]: diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 940bd231..3cebcc3f 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -362,3 +362,14 @@ def spinnaker_links(self) -> List[Tuple[int, int, int]]: :rtype: List((int, int, int)) """ raise NotImplementedError + + def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: + """ + The list of Local X, Y, link, fpga_link_id and fpga_id + + These are applied local to each Ethernet Chip and even if the link is + connected to another board + + :rtype: List((int, int, int, int, int)) + """ + raise NotImplementedError \ No newline at end of file diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index 84884b0c..2f42abd4 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -76,3 +76,7 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: @overrides(VersionSpin1.spinnaker_links) def spinnaker_links(self) -> List[Tuple[int, int, int]]: return [(0, 0, 3), (1, 0, 0)] + + @overrides(VersionSpin1.fpga_links) + def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: + return [] diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index f3e1c934..4855d468 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -111,3 +111,28 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: @overrides(VersionSpin1.spinnaker_links) def spinnaker_links(self) -> List[Tuple[int, int, int]]: return [(0, 0, 4)] + + @overrides(VersionSpin1.fpga_links) + def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: + return [(0, 0, 3, 1, 1), (0, 0, 4, 1, 0), (0, 0, 5, 0, 15), + (0, 1, 3, 1, 3), (0, 1, 4, 1, 2), + (0, 2, 3, 1, 5), (0, 2, 4, 1, 4), + (0, 3, 2, 1, 8), (0, 3, 3, 1, 7), (0, 3, 4, 1, 6), + (1, 0, 4, 0, 14), (1, 0, 5, 0, 13), + (1, 4, 2, 1, 10), (1, 4, 3, 1, 9), + (2, 0, 4, 0, 12), (2, 0, 5, 0, 11), + (2, 5, 2, 1, 12), (2, 5, 3, 1, 11), + (3, 0, 4, 0, 10), (3, 0, 5, 0, 9), + (3, 6, 2, 1, 14), (3, 6, 3, 1, 13), + (4, 0, 0, 0, 6), (4, 0, 4, 0, 8), + (4, 0, 5, 0, 7), (4, 7, 1, 2, 1), + (4, 7, 2, 2, 0), (4, 7, 3, 1, 15), + (5, 1, 0, 0, 4), (5, 1, 5, 0, 5), + (5, 7, 1, 2, 3), (5, 7, 2, 2, 2), + (6, 2, 0, 0, 2), (6, 2, 5, 0, 3), + (6, 7, 1, 2, 5), (6, 7, 2, 2, 4), + (7, 3, 0, 0, 0), (7, 3, 1, 2, 15), (7, 3, 5, 0, 1), + (7, 4, 0, 2, 14), (7, 4, 1, 2, 13), + (7, 5, 0, 2, 12), (7, 5, 1, 2, 11), + (7, 6, 0, 2, 10), (7, 6, 1, 2, 9), + (7, 7, 0, 2, 8), (7, 7, 1, 2, 7), (7, 7, 2, 2, 6)] diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index dedf3b8e..8421cc7a 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -217,7 +217,7 @@ def test_version_5_8_by_8(self): (5, 7, 1, 2, 3), (6, 7, 2, 2, 4), (6, 7, 1, 2, 5), (7, 7, 2, 2, 6), (7, 7, 1, 2, 7), (7, 7, 0, 2, 8), (7, 6, 1, 2, 9), (7, 6, 0, 2, 10), (7, 5, 1, 2, 11), - (7, 5, 0, 2, 12), (7, 4, 1, 2, 13),(7, 4, 0, 2, 14), + (7, 5, 0, 2, 12), (7, 4, 1, 2, 13), (7, 4, 0, 2, 14), (7, 3, 1, 2, 15)]) self.assertEqual(data, expected) From f65f828202a6a60a035ebf51555fd32d8206f3d5 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 5 Apr 2024 14:47:52 +0100 Subject: [PATCH 20/54] flake8 --- spinn_machine/machine.py | 1 - spinn_machine/version/abstract_version.py | 2 +- spinn_machine/version/version_3.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 454938d8..08eab886 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -892,7 +892,6 @@ def add_fpga_links(self) -> None: self._add_fpga_link(fpga_id, fpga_link, chip.x, chip.y, link, ip, ethernet.x, ethernet.y) - def _add_fpga_link( self, fpga_id: int, fpga_link: int, x: int, y: int, link: int, board_address: str, ex: int, ey: int): diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 3cebcc3f..0f8acaff 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -372,4 +372,4 @@ def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: :rtype: List((int, int, int, int, int)) """ - raise NotImplementedError \ No newline at end of file + raise NotImplementedError diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index 2f42abd4..40a275f4 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -78,5 +78,5 @@ def spinnaker_links(self) -> List[Tuple[int, int, int]]: return [(0, 0, 3), (1, 0, 0)] @overrides(VersionSpin1.fpga_links) - def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: + def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: return [] From 434d387b294bffae267c9d168fbae9c3e3e0454d Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 5 Apr 2024 15:01:54 +0100 Subject: [PATCH 21/54] FPGA capitalised in comment --- spinn_machine/machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 08eab886..945f5cf6 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -876,7 +876,7 @@ def _add_spinnaker_link( def add_fpga_links(self) -> None: """ - Add fpga links that are on a given machine depending on the + Add FPGA links that are on a given machine depending on the version of the board. """ version = MachineDataView.get_machine_version() From 20d0064261c8457d9665ccaf90d68e96405f06b0 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 5 Apr 2024 16:40:48 +0100 Subject: [PATCH 22/54] add in fpga spinnaker/link tests lost in merge --- spinn_machine/version/version_201.py | 8 ++ unittests/test_virtual_machine201.py | 2 + unittests/test_virtual_machine3.py | 13 ++- unittests/test_virtual_machine5.py | 119 ++++++++++++++++++++++++++- 4 files changed, 140 insertions(+), 2 deletions(-) diff --git a/spinn_machine/version/version_201.py b/spinn_machine/version/version_201.py index 29e6b7cf..9caf5d6c 100644 --- a/spinn_machine/version/version_201.py +++ b/spinn_machine/version/version_201.py @@ -105,3 +105,11 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: if x != 0 or y != 0: return "Only Chip 0, 0 may be an Ethernet Chip" return None + + @overrides(AbstractVersion.spinnaker_links) + def spinnaker_links(self) -> List[Tuple[int, int, int]]: + return [] + + @overrides(AbstractVersion.fpga_links) + def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: + return [] diff --git a/unittests/test_virtual_machine201.py b/unittests/test_virtual_machine201.py index 35ee1827..0fbeb9f1 100644 --- a/unittests/test_virtual_machine201.py +++ b/unittests/test_virtual_machine201.py @@ -89,6 +89,8 @@ def test_version_201(self): count += 1 self.assertEqual(1, count) self.assertEqual((1, 0), vm.get_unused_xy()) + self.assertEqual(0, len(list(vm.spinnaker_links))) + self.assertEqual(0, len(vm._fpga_links)) def test_new_vm_with_max_cores(self): set_config("Machine", "version", 201) diff --git a/unittests/test_virtual_machine3.py b/unittests/test_virtual_machine3.py index 61597d99..41c82d60 100644 --- a/unittests/test_virtual_machine3.py +++ b/unittests/test_virtual_machine3.py @@ -14,8 +14,9 @@ import unittest from spinn_utilities.config_holder import set_config -from spinn_machine.config_setup import unittest_setup from spinn_machine import Chip, Link, Router, virtual_machine +from spinn_machine.config_setup import unittest_setup +from spinn_machine.link_data_objects import SpinnakerLinkData from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) @@ -112,6 +113,16 @@ def test_version_2(self): count += 1 self.assertEqual(4, count) self.assertEqual((2, 0), vm.get_unused_xy()) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + sp = SpinnakerLinkData(0, 0, 0, 3, '127.0.0.0') + expected.append((('127.0.0.0', 0), sp)) + expected.append((((0, 0), 0), sp)) + sp = SpinnakerLinkData(1, 1, 0, 0, '127.0.0.0') + expected.append((('127.0.0.0', 1), sp)) + expected.append((((1, 0), 1), sp)) + self.assertEqual(expected, spinnaker_links) + self.assertEqual(0, len(vm._fpga_links)) def test_new_vm_with_max_cores(self): set_config("Machine", "version", 2) diff --git a/unittests/test_virtual_machine5.py b/unittests/test_virtual_machine5.py index 40f40983..2d599c2b 100644 --- a/unittests/test_virtual_machine5.py +++ b/unittests/test_virtual_machine5.py @@ -14,9 +14,11 @@ import unittest from spinn_utilities.config_holder import set_config -from spinn_machine.config_setup import unittest_setup + from spinn_machine import virtual_machine +from spinn_machine.config_setup import unittest_setup from spinn_machine.exceptions import SpinnMachineException +from spinn_machine.link_data_objects import SpinnakerLinkData from spinn_machine.version.version_5 import CHIPS_PER_BOARD @@ -79,6 +81,88 @@ def test_version_5_8_by_8(self): self.assertEqual(240, count) count = sum(_chip.n_processors for _chip in vm.chips) self.assertEqual(count, 856) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + sp = SpinnakerLinkData(0, 0, 0, 4, '127.0.0.0') + expected.append((('127.0.0.0', 0), sp)) + expected.append((((0, 0), 0), sp)) + self.assertEqual(expected, spinnaker_links) + # 8 links on each of the 6 sides recorded 3 times + # Except for the Ethernet Chip's 3 links which are only recorded twice + expected_fpgas = 8 * 6 * 3 - 3 + self.assertEqual(expected_fpgas, len(vm._fpga_links)) + keys = set([('127.0.0.0', 0, 0), ((7, 3), 0, 0), ((0, 0), 0, 0), + ('127.0.0.0', 0, 1), ((7, 3), 0, 1), ((0, 0), 0, 1), + ('127.0.0.0', 0, 2), ((6, 2), 0, 2), ((0, 0), 0, 2), + ('127.0.0.0', 0, 3), ((6, 2), 0, 3), ((0, 0), 0, 3), + ('127.0.0.0', 0, 4), ((5, 1), 0, 4), ((0, 0), 0, 4), + ('127.0.0.0', 0, 5), ((5, 1), 0, 5), ((0, 0), 0, 5), + ('127.0.0.0', 0, 6), ((4, 0), 0, 6), ((0, 0), 0, 6), + ('127.0.0.0', 0, 7), ((4, 0), 0, 7), ((0, 0), 0, 7), + ('127.0.0.0', 0, 8), ((4, 0), 0, 8), ((0, 0), 0, 8), + ('127.0.0.0', 0, 9), ((3, 0), 0, 9), ((0, 0), 0, 9), + ('127.0.0.0', 0, 10), ((3, 0), 0, 10), ((0, 0), 0, 10), + ('127.0.0.0', 0, 11), ((2, 0), 0, 11), ((0, 0), 0, 11), + ('127.0.0.0', 0, 12), ((2, 0), 0, 12), ((0, 0), 0, 12), + ('127.0.0.0', 0, 13), ((1, 0), 0, 13), ((0, 0), 0, 13), + ('127.0.0.0', 0, 14), ((1, 0), 0, 14), ((0, 0), 0, 14), + ('127.0.0.0', 0, 15), ((0, 0), 0, 15), + ('127.0.0.0', 1, 0), ((0, 0), 1, 0), + ('127.0.0.0', 1, 1), ((0, 0), 1, 1), + ('127.0.0.0', 1, 2), ((0, 1), 1, 2), ((0, 0), 1, 2), + ('127.0.0.0', 1, 3), ((0, 1), 1, 3), ((0, 0), 1, 3), + ('127.0.0.0', 1, 4), ((0, 2), 1, 4), ((0, 0), 1, 4), + ('127.0.0.0', 1, 5), ((0, 2), 1, 5), ((0, 0), 1, 5), + ('127.0.0.0', 1, 6), ((0, 3), 1, 6), ((0, 0), 1, 6), + ('127.0.0.0', 1, 7), ((0, 3), 1, 7), ((0, 0), 1, 7), + ('127.0.0.0', 1, 8), ((0, 3), 1, 8), ((0, 0), 1, 8), + ('127.0.0.0', 1, 9), ((1, 4), 1, 9), ((0, 0), 1, 9), + ('127.0.0.0', 1, 10), ((1, 4), 1, 10), ((0, 0), 1, 10), + ('127.0.0.0', 1, 11), ((2, 5), 1, 11), ((0, 0), 1, 11), + ('127.0.0.0', 1, 12), ((2, 5), 1, 12), ((0, 0), 1, 12), + ('127.0.0.0', 1, 13), ((3, 6), 1, 13), ((0, 0), 1, 13), + ('127.0.0.0', 1, 14), ((3, 6), 1, 14), ((0, 0), 1, 14), + ('127.0.0.0', 1, 15), ((4, 7), 1, 15), ((0, 0), 1, 15), + ('127.0.0.0', 2, 0), ((4, 7), 2, 0), ((0, 0), 2, 0), + ('127.0.0.0', 2, 1), ((4, 7), 2, 1), ((0, 0), 2, 1), + ('127.0.0.0', 2, 2), ((5, 7), 2, 2), ((0, 0), 2, 2), + ('127.0.0.0', 2, 3), ((5, 7), 2, 3), ((0, 0), 2, 3), + ('127.0.0.0', 2, 4), ((6, 7), 2, 4), ((0, 0), 2, 4), + ('127.0.0.0', 2, 5), ((6, 7), 2, 5), ((0, 0), 2, 5), + ('127.0.0.0', 2, 6), ((7, 7), 2, 6), ((0, 0), 2, 6), + ('127.0.0.0', 2, 7), ((7, 7), 2, 7), ((0, 0), 2, 7), + ('127.0.0.0', 2, 8), ((7, 7), 2, 8), ((0, 0), 2, 8), + ('127.0.0.0', 2, 9), ((7, 6), 2, 9), ((0, 0), 2, 9), + ('127.0.0.0', 2, 10), ((7, 6), 2, 10), ((0, 0), 2, 10), + ('127.0.0.0', 2, 11), ((7, 5), 2, 11), ((0, 0), 2, 11), + ('127.0.0.0', 2, 12), ((7, 5), 2, 12), ((0, 0), 2, 12), + ('127.0.0.0', 2, 13), ((7, 4), 2, 13), ((0, 0), 2, 13), + ('127.0.0.0', 2, 14), ((7, 4), 2, 14), ((0, 0), 2, 14), + ('127.0.0.0', 2, 15), ((7, 3), 2, 15), ((0, 0), 2, 15)]) + self.assertEqual(keys, set(vm._fpga_links.keys())) + data = set() + for (_, fpga_id, fpga_link), link in vm._fpga_links.items(): + data.add((link.connected_chip_x, link.connected_chip_y, + link.connected_link, fpga_id, fpga_link)) + expected = set([(7, 3, 0, 0, 0), (7, 3, 5, 0, 1), (6, 2, 0, 0, 2), + (6, 2, 5, 0, 3), (5, 1, 0, 0, 4), (5, 1, 5, 0, 5), + (4, 0, 0, 0, 6), (4, 0, 5, 0, 7), (4, 0, 4, 0, 8), + (3, 0, 5, 0, 9), (3, 0, 4, 0, 10), (2, 0, 5, 0, 11), + (2, 0, 4, 0, 12), (1, 0, 5, 0, 13), (1, 0, 4, 0, 14), + (0, 0, 5, 0, 15), + (0, 0, 4, 1, 0), (0, 0, 3, 1, 1), (0, 1, 4, 1, 2), + (0, 1, 3, 1, 3), (0, 2, 4, 1, 4), (0, 2, 3, 1, 5), + (0, 3, 4, 1, 6), (0, 3, 3, 1, 7), (0, 3, 2, 1, 8), + (1, 4, 3, 1, 9), (1, 4, 2, 1, 10), (2, 5, 3, 1, 11), + (2, 5, 2, 1, 12), (3, 6, 3, 1, 13), (3, 6, 2, 1, 14), + (4, 7, 3, 1, 15), + (4, 7, 2, 2, 0), (4, 7, 1, 2, 1), (5, 7, 2, 2, 2), + (5, 7, 1, 2, 3), (6, 7, 2, 2, 4), (6, 7, 1, 2, 5), + (7, 7, 2, 2, 6), (7, 7, 1, 2, 7), (7, 7, 0, 2, 8), + (7, 6, 1, 2, 9), (7, 6, 0, 2, 10), (7, 5, 1, 2, 11), + (7, 5, 0, 2, 12), (7, 4, 1, 2, 13), (7, 4, 0, 2, 14), + (7, 3, 1, 2, 15)]) + self.assertEqual(data, expected) def test_version_5_12_by_12(self): set_config("Machine", "version", 5) @@ -92,6 +176,39 @@ def test_version_5_12_by_12(self): count += 1 self.assertEqual(48, count) self.assertEqual((12, 0), vm.get_unused_xy()) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + self.assertEqual(expected, spinnaker_links) + # 8 links on each of the 6 sides recorded 3 times + # Except for the Ethernet Chip's 3 links which are only recorded twice + expected_fpgas = (8 * 6 * 3 - 3) * 3 + self.assertEqual(expected_fpgas, len(vm._fpga_links)) + + def test_version_5_16_by_16(self): + set_config("Machine", "version", 5) + vm = virtual_machine(height=16, width=16, validate=True) + self.assertEqual(144, vm.n_chips) + self.assertEqual(3, len(vm.ethernet_connected_chips)) + count = sum(1 for _chip in vm.chips for _link in _chip.router.links) + self.assertEqual(768, count) + count = 0 + for _chip in vm.get_existing_xys_on_board(vm[1, 1]): + count += 1 + self.assertEqual(48, count) + self.assertEqual((0, 4), vm.get_unused_xy()) + spinnaker_links = (list(vm.spinnaker_links)) + expected = [] + sp = SpinnakerLinkData(0, 0, 0, 4, '127.0.0.0') + expected.append((('127.0.0.0', 0), sp)) + expected.append((((0, 0), 0), sp)) + sp = SpinnakerLinkData(0, 4, 8, 4, '127.0.4.8') + expected.append((('127.0.4.8', 0), sp)) + expected.append((((4, 8), 0), sp)) + self.assertEqual(expected, spinnaker_links) + # 8 links on each of the 6 sides recorded 3 times + # Except for the Ethernet Chip's 3 links which are only recorded twice + expected_fpgas = (8 * 6 * 3 - 3) * 3 + self.assertEqual(expected_fpgas, len(vm._fpga_links)) def test_version_5_hole(self): set_config("Machine", "version", 5) From 1de838589fcbe2af9890ec9694eb783567d002e8 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 07:08:50 +0100 Subject: [PATCH 23/54] Move monitor core count to Machine level --- spinn_machine/data/machine_data_view.py | 33 +++++++++++++++++++++++ spinn_machine/data/machine_data_writer.py | 19 +++++++++++++ unittests/data/test_data.py | 12 +++++++++ 3 files changed, 64 insertions(+) diff --git a/spinn_machine/data/machine_data_view.py b/spinn_machine/data/machine_data_view.py index 6d0ff4fc..b88fad0a 100644 --- a/spinn_machine/data/machine_data_view.py +++ b/spinn_machine/data/machine_data_view.py @@ -43,6 +43,8 @@ class _MachineDataModel(object): __slots__ = [ # Data values cached + "_all_monitor_cores", + "_ethernet_monitor_cores", "_machine", "_machine_generator", "_machine_version", @@ -73,6 +75,8 @@ def _hard_reset(self) -> None: This does NOT clear the machine as it may have been asked for before """ self._soft_reset() + self._all_monitor_cores: int = 0 + self._ethernet_monitor_cores: int = 0 self._machine: Optional[Machine] = None self._user_accessed_machine = False @@ -263,3 +267,32 @@ def get_machine_version(cls) -> AbstractVersion: if cls.__data._machine_version is None: cls.__data._machine_version = version_factory() return cls.__data._machine_version + + @classmethod + def get_all_monitor_cores(cls) -> int: + """ + The number of cores on every chip reported to be used by \ + monitor vertices. + + Ethernet-enabled chips may have more. + + Does not include the system core reserved by the machine/ scamp. + + :rtype: int + """ + return cls.__data._all_monitor_cores + + @classmethod + def get_ethernet_monitor_cores(cls) -> int: + """ + The number of cores on every Ethernet chip reported to be used by \ + monitor vertices. + + This includes the one returned by get_all_monitor_cores unless for + some reason these are not on Ethernet chips. + + Does not include the system core reserved by the machine/ scamp. + + :rtype: int + """ + return cls.__data._ethernet_monitor_cores diff --git a/spinn_machine/data/machine_data_writer.py b/spinn_machine/data/machine_data_writer.py index 08dd6b21..c893de52 100644 --- a/spinn_machine/data/machine_data_writer.py +++ b/spinn_machine/data/machine_data_writer.py @@ -109,3 +109,22 @@ def set_machine_generator(self, machine_generator: Callable[[], None]): if not callable(machine_generator): raise TypeError("machine_generator must be callable") self.__data._machine_generator = machine_generator + + def add_monitor_core(self, all_cores: bool): + """ + Accepts a simple of the monitor cores to be added. + + Called by PacmanDataWriter add_sample_monitor_vertex. + + Only affect is to change the numbers reported by the + get_all/ethernet_monitor methods. + + :param bool all_cores: + If True assumes that this Vertex will be placed on all cores + including Ethernet ones. + If False assumes that this Vertex type will only be placed on + Ethernet Vertices + """ + self.__data._ethernet_monitor_cores += 1 + if all_cores: + self.__data._all_monitor_cores += 1 diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index f0647bde..3c606ef7 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -94,3 +94,15 @@ def test_where_is_setup(self): "None", MachineDataView.where_is_chip(None) ) + + def test_get_monitors(self): + writer = MachineDataWriter.setup() + self.assertEqual(0, MachineDataView.get_all_monitor_cores()) + self.assertEqual(0, MachineDataView.get_ethernet_monitor_cores()) + writer.add_monitor_core(True) + self.assertEqual(1, MachineDataView.get_all_monitor_cores()) + self.assertEqual(1, MachineDataView.get_ethernet_monitor_cores()) + writer.add_monitor_core(False) + writer.add_monitor_core(True) + self.assertEqual(2, MachineDataView.get_all_monitor_cores()) + self.assertEqual(3, MachineDataView.get_ethernet_monitor_cores()) From 04b585c5cac81a8c61d8350ce3913ffdb21422ec Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 08:00:39 +0100 Subject: [PATCH 24/54] size_from_n_cores --- spinn_machine/version/abstract_version.py | 37 +++++++++++++++++++++++ spinn_machine/version/version_5.py | 12 ++++++++ unittests/version/test_version3.py | 7 +++++ unittests/version/test_version5.py | 17 +++++++++++ 4 files changed, 73 insertions(+) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index c437c48a..be4e335c 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -18,6 +18,7 @@ from spinn_utilities.log import FormatAdapter from spinn_utilities.config_holder import get_config_int_or_none from spinn_utilities.typing.coords import XY +from spinn_machine.data import MachineDataView from spinn_machine.exceptions import SpinnMachineException if TYPE_CHECKING: from spinn_machine.machine import Machine @@ -351,3 +352,39 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: :return: An explanation that the x and y can never be an Ethernet """ raise NotImplementedError + + def size_from_n_cores(self, n_cores: int) -> Tuple[int, int]: + """ + Returns the size needed to support this many cores. + + Takes into consideration monitor cores. + + Designed for use with virtual boards. + Does not include a safety factor for blacklisted boards. + For real machines a slighlty bigger Machine may be needed. + + :param int n_cores: Number of None Scamp and monitor cores needed + :rtype: (int, int) + """ + cores_per_board = sum(self.chip_core_map.values()) + cores_per_board -= MachineDataView.get_ethernet_monitor_cores() + cores_per_board -= ( + (MachineDataView.get_all_monitor_cores() + self.n_scamp_cores) + * self.n_chips_per_board) + # Double minus to round up + return self.size_from_n_boards(-(-n_cores // cores_per_board)) + + def size_from_n_boards(self, n_boards: int) -> Tuple[int, int]: + """ + Returns the size needed to support this many boards. + + :param int n_boards: + :rtype: (int, int) + :raises SpinnMachineException: + If multiple boards are needed but not supported + """ + # Override for versions that support multiple boards + if n_boards == 1: + return self.board_shape + raise SpinnMachineException( + f"Version {self} does not support multiple boards") \ No newline at end of file diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index 178432dd..6f3216fa 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import math from typing import Final, Mapping, Optional, Sequence, Tuple from spinn_utilities.overrides import overrides from spinn_utilities.typing.coords import XY @@ -107,3 +108,14 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: return "Only Chip with x + y divisible by 12 " \ "may be an Ethernet Chip" return None + + @overrides(VersionSpin1.size_from_n_boards) + def size_from_n_boards(self, n_boards: int) -> Tuple[int, int]: + if n_boards <= 1: + return 8, 8 + # This replicates how spalloc does it + # returning a rectangle of triads + triads = math.ceil(n_boards / 3) + width = math.ceil(math.sqrt(triads)) + height = math.ceil(triads / width) + return width * 12 + 4, height * 12 + 4 diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py index 5d5795ed..22751fdb 100644 --- a/unittests/version/test_version3.py +++ b/unittests/version/test_version3.py @@ -140,6 +140,13 @@ def test_processor_info(self): self.assertEqual(200, version.clock_speed_hz) self.assertEqual(65536, version.dtcm_bytes) + def test_size_from_n_cores(self): + version = Version3() + self.assertEqual((2, 2), version.size_from_n_cores(10)) + self.assertEqual((2, 2), version.size_from_n_cores(18 * 4)) + with self.assertRaises(SpinnMachineException): + self.assertEqual((2, 2), version.size_from_n_cores(18 * 4 + 1)) + if __name__ == '__main__': unittest.main() diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index a4ec4387..b6adfb5f 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -150,6 +150,23 @@ def test_processor_info(self): self.assertEqual(200, version.clock_speed_hz) self.assertEqual(65536, version.dtcm_bytes) + def test_size_from_n_cores(self): + version = Version5() + #self.assertEqual((8, 8), version.size_from_n_cores(10)) + # standard for there to be 8 17 core Chips and each has 1 scamp core + n_cores = 17 * 48 - 8 + self.assertEqual((8, 8), version.size_from_n_cores(n_cores)) + self.assertEqual((16, 16), version.size_from_n_cores(n_cores + 1)) + self.assertEqual((16, 16), version.size_from_n_cores(n_cores * 3)) + self.assertEqual((28, 16), version.size_from_n_cores(n_cores * 4)) + self.assertEqual((28, 16), version.size_from_n_cores(n_cores * 6)) + self.assertEqual((28, 28), version.size_from_n_cores(n_cores * 7)) + self.assertEqual((28, 28), version.size_from_n_cores(n_cores * 12)) + self.assertEqual((40, 28), version.size_from_n_cores(n_cores * 13)) + self.assertEqual((40, 28), version.size_from_n_cores(n_cores * 18)) + self.assertEqual((40, 40), version.size_from_n_cores(n_cores * 18 + 1)) + + if __name__ == '__main__': unittest.main() From cd4766c6785e0e5f9ff550df4ec6127d14b548a4 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 12:30:43 +0100 Subject: [PATCH 25/54] virtual machine by n_cores --- spinn_machine/virtual_machine.py | 36 +++++++++++++++--- unittests/test_virtual_machine.py | 62 +++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 6 deletions(-) diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index 49d15920..1c042db8 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -14,7 +14,7 @@ from collections import defaultdict import logging -from typing import Dict, List, Optional, Set, Tuple +from typing import Dict, List, Optional, overload, Set, Tuple from spinn_utilities.config_holder import get_config_str_or_none from spinn_utilities.log import FormatAdapter from spinn_utilities.typing.coords import XY @@ -28,18 +28,39 @@ logger = FormatAdapter(logging.getLogger(__name__)) +@overload def virtual_machine( - width: int, height: int, validate: bool = True): + width: int, height: int, + validate: bool = True, n_cores: None = None): + ... + + +@overload +def virtual_machine( + width: None = None, height: None = None, + validate: bool = True, n_cores: int = 0): + ... + + +def virtual_machine( + width: Optional[int] = None, height: Optional[int] = None, + validate: bool = True, n_cores: Optional[int] = None): """ Create a virtual SpiNNaker machine, used for planning execution. - :param int width: the width of the virtual machine in chips - :param int height: the height of the virtual machine in chips + :param width: the width of the virtual machine in chips + :type width: int or None + :param height: the height of the virtual machine in chips + :type height: int or None :param bool validate: if True will call the machine validate function + :param n_cores: + If provided will be used to calculate the size of Machine needed. + In which case width and height are ignored! + :returns: a virtual machine (that cannot execute code) :rtype: ~spinn_machine.Machine """ - factory = _VirtualMachine(width, height, validate) + factory = _VirtualMachine(width, height, validate, n_cores) return factory.machine @@ -64,8 +85,11 @@ class _VirtualMachine(object): ORIGIN = "Virtual" def __init__( - self, width: int, height: int, validate: bool = True): + self, width: Optional[int] = None, height: Optional[int] = None, + validate: bool = True, n_cores: Optional[int] = None): version = MachineDataView.get_machine_version() + if n_cores: + width, height = version.size_from_n_cores(n_cores) version.verify_size(height, width) max_cores = version.max_cores_per_chip self._n_router_entries = version.n_router_entries diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index ac405269..4f975ddb 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -16,6 +16,7 @@ from spinn_utilities.config_holder import set_config from spinn_machine.config_setup import unittest_setup from spinn_machine import Chip, Link, Router, virtual_machine +from spinn_machine.data import MachineDataView from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink @@ -1086,6 +1087,67 @@ 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_2_2_by_cores(self): + set_config("Machine", "version", 2) + machine = virtual_machine(n_cores=40) + self.assertEqual(4, machine.n_chips) + + def test_2_2_by_cores_too_many(self): + set_config("Machine", "version", 2) + with self.assertRaises(SpinnMachineException): + machine = virtual_machine(n_cores=100) + + def test_8_8_by_cores_1_board(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine(n_cores=n_cores) + self.assertEqual(8, machine.width) + self.assertEqual(8, machine.height) + self.assertEqual(n_cores, machine.total_available_user_cores) + + def test_8_8_by_cores_3_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine(n_cores=n_cores * 2) + # despite asking for two boards you get a triad + self.assertEqual(16, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores*3, machine.total_available_user_cores) + + def test_8_8_by_cores_6_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine(n_cores=n_cores * 5) + self.assertEqual(28, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores * 6, machine.total_available_user_cores) + + def test_8_8_by_cores_12_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine(n_cores=n_cores * 9) + self.assertEqual(28, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 12, machine.total_available_user_cores) + + def test_8_8_by_cores_18_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine(n_cores=n_cores * 12 + 1) + self.assertEqual(40, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 18, machine.total_available_user_cores) + if __name__ == '__main__': unittest.main() From 24ac4b014434b863a7a7e0a0bdbc83c4fd0edc29 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 12:34:07 +0100 Subject: [PATCH 26/54] mock machine any version --- spinn_machine/data/machine_data_writer.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/spinn_machine/data/machine_data_writer.py b/spinn_machine/data/machine_data_writer.py index c893de52..52b44074 100644 --- a/spinn_machine/data/machine_data_writer.py +++ b/spinn_machine/data/machine_data_writer.py @@ -46,12 +46,8 @@ def _mock_machine(self) -> None: """ Method to create a virtual machine in mock mode. """ - if self.get_machine_version().number == 3: - self.set_machine(virtual_machine(width=2, height=2)) - elif self.get_machine_version().number == 5: - self.set_machine(virtual_machine(width=8, height=8)) - else: - raise NotImplementedError("Please set machine version") + width, height = self.get_machine_version().board_shape + self.set_machine(virtual_machine(width=width, height=height)) @overrides(UtilsDataWriter._setup) def _setup(self) -> None: From c4202768711310d12164465edea2597505563c1c Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 12:43:16 +0100 Subject: [PATCH 27/54] fix test to consider scamp core --- unittests/version/test_version3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py index 22751fdb..3095fe46 100644 --- a/unittests/version/test_version3.py +++ b/unittests/version/test_version3.py @@ -143,9 +143,9 @@ def test_processor_info(self): def test_size_from_n_cores(self): version = Version3() self.assertEqual((2, 2), version.size_from_n_cores(10)) - self.assertEqual((2, 2), version.size_from_n_cores(18 * 4)) + self.assertEqual((2, 2), version.size_from_n_cores(17 * 4)) with self.assertRaises(SpinnMachineException): - self.assertEqual((2, 2), version.size_from_n_cores(18 * 4 + 1)) + self.assertEqual((2, 2), version.size_from_n_cores(17 * 4 + 1)) if __name__ == '__main__': From 39d3ac233e33a7d425b1f3ab5d29aa139de02190 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 12:48:46 +0100 Subject: [PATCH 28/54] flake8 --- spinn_machine/version/abstract_version.py | 2 +- unittests/test_virtual_machine.py | 6 ++++++ unittests/version/test_version5.py | 3 +-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index be4e335c..ef4183ec 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -387,4 +387,4 @@ def size_from_n_boards(self, n_boards: int) -> Tuple[int, int]: if n_boards == 1: return self.board_shape raise SpinnMachineException( - f"Version {self} does not support multiple boards") \ No newline at end of file + f"Version {self} does not support multiple boards") diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index 4f975ddb..bc2a174a 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -1094,8 +1094,14 @@ def test_2_2_by_cores(self): def test_2_2_by_cores_too_many(self): set_config("Machine", "version", 2) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board with self.assertRaises(SpinnMachineException): machine = virtual_machine(n_cores=100) + self.assertEqual(2, machine.width) + self.assertEqual(2, machine.height) + self.assertEqual(n_cores, machine.total_available_user_cores) def test_8_8_by_cores_1_board(self): set_config("Machine", "version", 5) diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index b6adfb5f..50e0bc2f 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -152,7 +152,7 @@ def test_processor_info(self): def test_size_from_n_cores(self): version = Version5() - #self.assertEqual((8, 8), version.size_from_n_cores(10)) + self.assertEqual((8, 8), version.size_from_n_cores(10)) # standard for there to be 8 17 core Chips and each has 1 scamp core n_cores = 17 * 48 - 8 self.assertEqual((8, 8), version.size_from_n_cores(n_cores)) @@ -167,6 +167,5 @@ def test_size_from_n_cores(self): self.assertEqual((40, 40), version.size_from_n_cores(n_cores * 18 + 1)) - if __name__ == '__main__': unittest.main() From 54d9747540ca078c2e2fde056cf5bb0350b4e233 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 15:59:16 +0100 Subject: [PATCH 29/54] correct param order --- spinn_machine/version/abstract_version.py | 2 +- spinn_machine/virtual_machine.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index ef4183ec..36b94708 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -361,7 +361,7 @@ def size_from_n_cores(self, n_cores: int) -> Tuple[int, int]: Designed for use with virtual boards. Does not include a safety factor for blacklisted boards. - For real machines a slighlty bigger Machine may be needed. + For real machines a slightly bigger Machine may be needed. :param int n_cores: Number of None Scamp and monitor cores needed :rtype: (int, int) diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index 1c042db8..f93ed4d7 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -90,7 +90,7 @@ def __init__( version = MachineDataView.get_machine_version() if n_cores: width, height = version.size_from_n_cores(n_cores) - version.verify_size(height, width) + version.verify_size(width, height) max_cores = version.max_cores_per_chip self._n_router_entries = version.n_router_entries self._machine = version.create_machine( From d83ebc8a1a232211760f36c22e222322abe21aff Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 8 Apr 2024 16:04:59 +0100 Subject: [PATCH 30/54] typing --- spinn_machine/virtual_machine.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index f93ed4d7..b7dcd81a 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -84,12 +84,26 @@ class _VirtualMachine(object): ORIGIN = "Virtual" + @overload + def __init__( + self, width: int, height: int, + validate: bool = True, n_cores: None = None): + ... + + @overload + def __init__( + self, width: None = None, height: None = None, + validate: bool = True, n_cores: int = 0): + ... + def __init__( self, width: Optional[int] = None, height: Optional[int] = None, validate: bool = True, n_cores: Optional[int] = None): version = MachineDataView.get_machine_version() if n_cores: width, height = version.size_from_n_cores(n_cores) + assert width is not None + assert height is not None version.verify_size(width, height) max_cores = version.max_cores_per_chip self._n_router_entries = version.n_router_entries From b9b6c77919e06bb871acf4a03a4243c7f9b23d2a Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 07:25:08 +0100 Subject: [PATCH 31/54] typing assert --- spinn_machine/virtual_machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index b7dcd81a..3ca95edc 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -102,9 +102,9 @@ def __init__( version = MachineDataView.get_machine_version() if n_cores: width, height = version.size_from_n_cores(n_cores) + version.verify_size(width, height) assert width is not None assert height is not None - version.verify_size(width, height) max_cores = version.max_cores_per_chip self._n_router_entries = version.n_router_entries self._machine = version.create_machine( From 7384e71e72dbc4d1f6686a03addcdbc83cde0bd2 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 10:30:06 +0100 Subject: [PATCH 32/54] virtual_machine_by --- spinn_machine/__init__.py | 6 +- spinn_machine/data/machine_data_writer.py | 5 +- spinn_machine/version/abstract_version.py | 2 +- spinn_machine/virtual_machine.py | 118 ++++++++++++++-------- unittests/test_json_machine.py | 25 ++--- unittests/test_virtual_machine.py | 69 ++++++++++--- 6 files changed, 151 insertions(+), 74 deletions(-) diff --git a/spinn_machine/__init__.py b/spinn_machine/__init__.py index 57c9644d..54134e64 100644 --- a/spinn_machine/__init__.py +++ b/spinn_machine/__init__.py @@ -85,10 +85,12 @@ from .multicast_routing_entry import MulticastRoutingEntry from .router import Router from .spinnaker_triad_geometry import SpiNNakerTriadGeometry -from .virtual_machine import virtual_machine +from .virtual_machine import ( + virtual_machine, virtual_machine_by_boards, virtual_machine_by_cores) from .fixed_route_entry import FixedRouteEntry __all__ = ["Chip", "CoreSubset", "CoreSubsets", "FixedRouteEntry", "FrozenCoreSubsets", "Link", "Machine", "MulticastRoutingEntry", - "Router", "SpiNNakerTriadGeometry", "virtual_machine"] + "Router", "SpiNNakerTriadGeometry", "virtual_machine", + "virtual_machine_by_boards", "virtual_machine_by_cores"] diff --git a/spinn_machine/data/machine_data_writer.py b/spinn_machine/data/machine_data_writer.py index 52b44074..f5aec30a 100644 --- a/spinn_machine/data/machine_data_writer.py +++ b/spinn_machine/data/machine_data_writer.py @@ -17,7 +17,7 @@ from spinn_utilities.data.utils_data_writer import UtilsDataWriter from spinn_utilities.overrides import overrides from spinn_utilities.log import FormatAdapter -from spinn_machine import Machine, virtual_machine +from spinn_machine import Machine, virtual_machine_by_boards from .machine_data_view import MachineDataView, _MachineDataModel logger = FormatAdapter(logging.getLogger(__name__)) __temp_dir = None @@ -46,8 +46,7 @@ def _mock_machine(self) -> None: """ Method to create a virtual machine in mock mode. """ - width, height = self.get_machine_version().board_shape - self.set_machine(virtual_machine(width=width, height=height)) + self.set_machine(virtual_machine_by_boards(1)) @overrides(UtilsDataWriter._setup) def _setup(self) -> None: diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 36b94708..848bba9b 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -357,7 +357,7 @@ def size_from_n_cores(self, n_cores: int) -> Tuple[int, int]: """ Returns the size needed to support this many cores. - Takes into consideration monitor cores. + Takes into consideration scamp and monitor cores. Designed for use with virtual boards. Does not include a safety factor for blacklisted boards. diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index 3ca95edc..b2a2e42c 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -11,7 +11,7 @@ # 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 math from collections import defaultdict import logging from typing import Dict, List, Optional, overload, Set, Tuple @@ -28,40 +28,92 @@ logger = FormatAdapter(logging.getLogger(__name__)) -@overload -def virtual_machine( - width: int, height: int, - validate: bool = True, n_cores: None = None): - ... +def virtual_machine(width: int, height: int, validate: bool = True): + """ + Create a virtual SpiNNaker machine, used for planning execution. + :param int width: the width of the virtual machine in chips + :param int height: the height of the virtual machine in chips + :param bool validate: if True will call the machine validate function -@overload -def virtual_machine( - width: None = None, height: None = None, - validate: bool = True, n_cores: int = 0): - ... + :returns: a virtual machine (that cannot execute code) + :rtype: ~spinn_machine.Machine + """ + factory = _VirtualMachine(width, height, validate) + return factory.machine -def virtual_machine( - width: Optional[int] = None, height: Optional[int] = None, - validate: bool = True, n_cores: Optional[int] = None): +def virtual_machine_by_min_size(width: int, height: int, validate: bool = True): """ Create a virtual SpiNNaker machine, used for planning execution. - :param width: the width of the virtual machine in chips - :type width: int or None - :param height: the height of the virtual machine in chips - :type height: int or None + :param int width: the minimum width of the virtual machine in chips + :param int height: the minimum height of the virtual machine in chips :param bool validate: if True will call the machine validate function - :param n_cores: - If provided will be used to calculate the size of Machine needed. - In which case width and height are ignored! :returns: a virtual machine (that cannot execute code) :rtype: ~spinn_machine.Machine """ - factory = _VirtualMachine(width, height, validate, n_cores) - return factory.machine + version = MachineDataView.get_machine_version() + w_board, h_board = version.board_shape + # check for edge case + if width <= w_board and height > h_board: + width = w_board * 2 + if height <= h_board and width > w_board: + height = h_board * 2 + width = w_board * math.ceil(width / w_board) + height = h_board * math.ceil(height / h_board) + return virtual_machine(width, height, validate) + + +def virtual_machine_by_cores(n_cores: int, validate: bool = True): + """ + Create a virtual SpiNNaker machine, used for planning execution. + + Semantic sugar for + + MachineDataView.get_machine_version() + + width, height = version.size_from_n_cores(n_cores) + + return virtual_machine(width, height, validate) + + :param n_cores: Minimum number of user cores + :param bool validate: if True will call the machine validate function + + :returns: a virtual machine (that cannot execute code) + :rtype: ~spinn_machine.Machine + :raises SpinnMachineException: + If multiple boards are needed but not supported + """ + version = MachineDataView.get_machine_version() + width, height = version.size_from_n_cores(n_cores) + return virtual_machine(width, height, validate) + + +def virtual_machine_by_boards(n_boards: int, validate: bool = True): + """ + Create a virtual SpiNNaker machine, used for planning execution. + + semantic sugar for: + + version = MachineDataView.get_machine_version() + + width, height = version.size_from_n_boards(n_boards) + + return virtual_machine(width, height, validate) + + :param n_boards: Minimum number of boards + :param bool validate: if True will call the machine validate function + + :returns: a virtual machine (that cannot execute code) + :rtype: ~spinn_machine.Machine + :raises SpinnMachineException: + If multiple boards are needed but not supported + """ + version = MachineDataView.get_machine_version() + width, height = version.size_from_n_boards(n_boards) + return virtual_machine(width, height, validate) class _VirtualMachine(object): @@ -84,27 +136,9 @@ class _VirtualMachine(object): ORIGIN = "Virtual" - @overload - def __init__( - self, width: int, height: int, - validate: bool = True, n_cores: None = None): - ... - - @overload - def __init__( - self, width: None = None, height: None = None, - validate: bool = True, n_cores: int = 0): - ... - - def __init__( - self, width: Optional[int] = None, height: Optional[int] = None, - validate: bool = True, n_cores: Optional[int] = None): + def __init__(self, width: int, height: int, validate: bool = True): version = MachineDataView.get_machine_version() - if n_cores: - width, height = version.size_from_n_cores(n_cores) version.verify_size(width, height) - assert width is not None - assert height is not None max_cores = version.max_cores_per_chip self._n_router_entries = version.n_router_entries self._machine = version.create_machine( diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 65a5a06a..3d997dee 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -15,7 +15,8 @@ from tempfile import mktemp import unittest from spinn_utilities.config_holder import set_config -from spinn_machine import virtual_machine +from spinn_machine.virtual_machine import ( + virtual_machine_by_boards, virtual_machine_by_min_size) from spinn_machine.data.machine_data_writer import MachineDataWriter from spinn_machine.config_setup import unittest_setup from spinn_machine.json_machine import (machine_from_json, to_json_path) @@ -29,7 +30,7 @@ def setUp(self): def test_json_version_5_hole(self): set_config("Machine", "down_chips", "3,3") - vm = virtual_machine(width=8, height=8) + vm = virtual_machine_by_min_size(width=8, height=8) MachineDataWriter.mock().set_machine(vm) jpath = mktemp("json") to_json_path(jpath) @@ -41,7 +42,7 @@ def test_json_version_5_hole(self): self.assertEqual(str(vchip), str(jchip)) def test_exceptions(self): - vm = virtual_machine(width=8, height=8) + vm = virtual_machine_by_min_size(width=8, height=8) MachineDataWriter.mock().set_machine(vm) chip22 = vm[2, 2] router22 = chip22.router @@ -73,21 +74,21 @@ def test_monitor_exceptions(self): machine_from_json(jpath) def test_ethernet_exceptions(self): - vm = virtual_machine(width=16, height=16) + vm = virtual_machine_by_boards(2) MachineDataWriter.mock().set_machine(vm) - chip48 = vm[4, 8] - router48 = chip48.router - router48._n_available_multicast_entries = \ - router48._n_available_multicast_entries - 20 - chip48._sdram = 50000000 - chip48._tag_ids = [2, 3] + eth2 = vm.ethernet_connected_chips[1] + router2 = eth2.router + router2._n_available_multicast_entries = \ + router2._n_available_multicast_entries - 20 + eth2._sdram = 50000000 + eth2._tag_ids = [2, 3] jpath = mktemp("json") to_json_path(jpath) jm = machine_from_json(jpath) for vchip, jchip in zip(vm, jm): self.assertEqual(str(vchip), str(jchip)) - vchip48 = jm[4, 8] - self.assertEqual(vchip48.tag_ids, chip48.tag_ids) + jeth2 = jm.ethernet_connected_chips[1] + self.assertEqual(jeth2.tag_ids, eth2.tag_ids) if __name__ == '__main__': diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index bc2a174a..3820ca95 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -15,7 +15,9 @@ import unittest from spinn_utilities.config_holder import set_config from spinn_machine.config_setup import unittest_setup -from spinn_machine import Chip, Link, Router, virtual_machine +from spinn_machine import (Chip, Link, Router, virtual_machine, + virtual_machine_by_boards, virtual_machine_by_cores) +from spinn_machine.virtual_machine import virtual_machine_by_min_size from spinn_machine.data import MachineDataView from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) @@ -1089,26 +1091,34 @@ def test_n_cores_2_2(self): def test_2_2_by_cores(self): set_config("Machine", "version", 2) - machine = virtual_machine(n_cores=40) + n_cores = 40 + machine = virtual_machine_by_cores(n_cores) self.assertEqual(4, machine.n_chips) + self.assertEqual(2, machine.width) + self.assertEqual(2, machine.height) + self.assertGreaterEqual(machine.total_available_user_cores, n_cores) + machine2 = virtual_machine_by_boards(1) + self.assertEqual(4, machine2.n_chips) + self.assertEqual(2, machine2.width) + self.assertEqual(2, machine2.height) def test_2_2_by_cores_too_many(self): set_config("Machine", "version", 2) - version = MachineDataView.get_machine_version() - n_cores = sum(version.chip_core_map.values()) - n_cores -= version.n_chips_per_board with self.assertRaises(SpinnMachineException): - machine = virtual_machine(n_cores=100) - self.assertEqual(2, machine.width) - self.assertEqual(2, machine.height) - self.assertEqual(n_cores, machine.total_available_user_cores) + virtual_machine_by_cores(100) + with self.assertRaises(SpinnMachineException): + virtual_machine_by_boards(2) def test_8_8_by_cores_1_board(self): set_config("Machine", "version", 5) version = MachineDataView.get_machine_version() n_cores = sum(version.chip_core_map.values()) n_cores -= version.n_chips_per_board - machine = virtual_machine(n_cores=n_cores) + machine = virtual_machine_by_cores(n_cores) + self.assertEqual(8, machine.width) + self.assertEqual(8, machine.height) + self.assertEqual(n_cores, machine.total_available_user_cores) + machine = virtual_machine_by_boards(1) self.assertEqual(8, machine.width) self.assertEqual(8, machine.height) self.assertEqual(n_cores, machine.total_available_user_cores) @@ -1118,7 +1128,12 @@ def test_8_8_by_cores_3_boards(self): version = MachineDataView.get_machine_version() n_cores = sum(version.chip_core_map.values()) n_cores -= version.n_chips_per_board - machine = virtual_machine(n_cores=n_cores * 2) + machine = virtual_machine_by_cores(n_cores * 2) + # despite asking for two boards you get a triad + self.assertEqual(16, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores*3, machine.total_available_user_cores) + machine = virtual_machine_by_boards(2) # despite asking for two boards you get a triad self.assertEqual(16, machine.width) self.assertEqual(16, machine.height) @@ -1129,7 +1144,11 @@ def test_8_8_by_cores_6_boards(self): version = MachineDataView.get_machine_version() n_cores = sum(version.chip_core_map.values()) n_cores -= version.n_chips_per_board - machine = virtual_machine(n_cores=n_cores * 5) + machine = virtual_machine_by_cores(n_cores * 5) + self.assertEqual(28, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores * 6, machine.total_available_user_cores) + machine = virtual_machine_by_boards(4) self.assertEqual(28, machine.width) self.assertEqual(16, machine.height) self.assertEqual(n_cores * 6, machine.total_available_user_cores) @@ -1139,7 +1158,11 @@ def test_8_8_by_cores_12_boards(self): version = MachineDataView.get_machine_version() n_cores = sum(version.chip_core_map.values()) n_cores -= version.n_chips_per_board - machine = virtual_machine(n_cores=n_cores * 9) + machine = virtual_machine_by_cores(n_cores * 9) + self.assertEqual(28, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 12, machine.total_available_user_cores) + machine = virtual_machine_by_boards(10) self.assertEqual(28, machine.width) self.assertEqual(28, machine.height) self.assertEqual(n_cores * 12, machine.total_available_user_cores) @@ -1149,11 +1172,29 @@ def test_8_8_by_cores_18_boards(self): version = MachineDataView.get_machine_version() n_cores = sum(version.chip_core_map.values()) n_cores -= version.n_chips_per_board - machine = virtual_machine(n_cores=n_cores * 12 + 1) + machine = virtual_machine_by_cores(n_cores * 12 + 1) + self.assertEqual(40, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 18, machine.total_available_user_cores) + machine = virtual_machine_by_boards(15) self.assertEqual(40, machine.width) self.assertEqual(28, machine.height) self.assertEqual(n_cores * 18, machine.total_available_user_cores) + def test_by_min_size(self): + set_config("Machine", "version", 5) + machine = virtual_machine_by_min_size(15, 21) + self.assertGreaterEqual(machine.width, 15) + self.assertGreaterEqual(machine.height, 21) + + def test_by_min_size_edge_case(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + width, height = version.board_shape + machine = virtual_machine_by_min_size(width, height + 1) + self.assertGreaterEqual(machine.width, width) + self.assertGreaterEqual(machine.height, height + 1) + if __name__ == '__main__': unittest.main() From 78b62756091b5d47c3d5356e67efb99e33efad78 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 11:31:09 +0100 Subject: [PATCH 33/54] remove hard coded values from tests --- unittests/test_machine.py | 144 ++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 42679a44..ddc9d322 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -20,7 +20,8 @@ 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.virtual_machine import ( + virtual_machine_by_boards, virtual_machine_by_min_size) from spinn_machine.config_setup import unittest_setup from spinn_machine.data import MachineDataView from spinn_machine.exceptions import ( @@ -58,11 +59,13 @@ def _create_chip(self, x, y): self._nearest_ethernet_chip[0], self._nearest_ethernet_chip[1], None) - def test_create_new_machine(self): + def test_create_new_machine_version5(self): """ test creating a new machine """ - new_machine = virtual_machine(8, 8) + # Tests the version 5 values specifically + set_config("Machine", "version", 5) + new_machine = virtual_machine_by_boards(1) self.assertEqual(new_machine.width, 8) self.assertEqual(new_machine.height, 8) @@ -90,7 +93,9 @@ def test_create_new_machine(self): self.assertEqual(1023, new_machine.min_n_router_enteries) def test_summary(self): - machine = virtual_machine(8, 8) + # Strings hard coded to version 5 + set_config("Machine", "version", 5) + machine = virtual_machine_by_boards(1) 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, " @@ -143,38 +148,20 @@ def test_create_new_machine_with_invalid_chips(self): :rtype: None """ - machine = virtual_machine(8, 8) + machine = virtual_machine_by_boards(1) with self.assertRaises(SpinnMachineAlreadyExistsException): 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): - """ - test the add_chip method of the machine object - - :rtype: None - """ - 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, "127.0.0.0") - else: - self.assertIsNone(c.ip_address) - self.assertEqual(c.sdram, self._sdram) - self.assertIsNotNone(c.router) - def test_machine_add_duplicate_chip(self): """ test if adding the same chip twice causes an error :rtype: None """ - new_machine = virtual_machine(8, 8) + new_machine = virtual_machine_by_boards(1) with self.assertRaises(SpinnMachineAlreadyExistsException): new_machine.add_chip(new_machine.get_chip_at(1, 1)) @@ -184,9 +171,11 @@ def test_machine_get_chip_at(self): :rtype: None """ - 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) + new_machine = virtual_machine_by_min_size(2, 2) + self.assertEqual(1, new_machine.get_chip_at(1, 0).x) + self.assertEqual(0, new_machine.get_chip_at(1, 0).y) + self.assertEqual(0, new_machine.get_chip_at(0, 1).x) + self.assertEqual(1, new_machine.get_chip_at(0, 1).y) def test_machine_big_x(self): """ @@ -195,15 +184,18 @@ def test_machine_big_x(self): :rtype: None """ - machine = MachineDataView.get_machine_version().create_machine(8, 8) + version = MachineDataView.get_machine_version() + width, height = version.board_shape + # create an empty Machine + machine = version.create_machine(width, height) machine.add_chip(self._create_chip(0, 0)) # the add does not have the safety code - machine.add_chip(self._create_chip(10, 2)) + machine.add_chip(self._create_chip(width + 2, height // 2)) # however the validate does try: machine.validate() except SpinnMachineException as ex: - self.assertIn("has an x larger than width 8", str(ex)) + self.assertIn(f"has an x larger than width {width}", str(ex)) def test_machine_big_y(self): """ @@ -213,15 +205,17 @@ def test_machine_big_y(self): :rtype: None """ version = MachineDataView.get_machine_version() - new_machine = version.create_machine(8, 8) - new_machine.add_chip(self._create_chip(0, 0)) + width, height = version.board_shape + # create an empty Machine + machine = version.create_machine(width, height) + 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)) + machine.add_chip(self._create_chip(width // 2, height + 2)) # however the validate does try: - new_machine.validate() + machine.validate() except SpinnMachineException as ex: - self.assertIn("has a y larger than height 8", str(ex)) + self.assertIn(f"has a y larger than height {height}", str(ex)) def test_machine_get_chip_at_invalid_location(self): """ @@ -230,8 +224,10 @@ def test_machine_get_chip_at_invalid_location(self): :rtype: None """ - new_machine = virtual_machine(8, 8) - self.assertEqual(None, new_machine.get_chip_at(10, 0)) + version = MachineDataView.get_machine_version() + new_machine = virtual_machine_by_boards(1) + width, height = version.board_shape + self.assertEqual(None, new_machine.get_chip_at(width + 2, height // 2)) def test_machine_is_chip_at_true(self): """ @@ -240,8 +236,10 @@ def test_machine_is_chip_at_true(self): :rtype: None """ - new_machine = virtual_machine(8, 8) - self.assertTrue(new_machine.is_chip_at(3, 0)) + version = MachineDataView.get_machine_version() + new_machine = virtual_machine_by_boards(1) + width, height = version.board_shape + self.assertTrue(new_machine.is_chip_at(width // 2, height // 2)) def test_machine_is_chip_at_false(self): """ @@ -250,17 +248,19 @@ def test_machine_is_chip_at_false(self): :rtype: None """ - new_machine = virtual_machine(8, 8) - self.assertFalse(new_machine.is_chip_at(10, 0)) + version = MachineDataView.get_machine_version() + new_machine = virtual_machine_by_boards(1) + width, height = version.board_shape + self.assertFalse(new_machine.is_chip_at(width + 2, height // 2)) def test_machine_get_chips_on_board(self): - new_machine = virtual_machine(8, 8) + new_machine = virtual_machine_by_boards(3) + version = MachineDataView.get_machine_version() 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_in_machine), 48) + self.assertEqual(len(chips_in_machine), version.n_chips_per_board) + # TODO use version info from other PR with self.assertRaises(KeyError): new_machine.get_spinnaker_link_with_id(1) with self.assertRaises(KeyError): @@ -273,6 +273,8 @@ def test_x_y_over_link(self): Notice that the function only does the math not validate the values. :return: """ + # TODO wrap arrounds in Spin2 + set_config("Machine", "version", 5) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.xy_over_link(0, 0, 4), (23, 23)) @@ -301,6 +303,8 @@ def test_get_global_xy(self): Notice that the function only does the math not validate the values. :return: """ + # TODO wrap arounds in Spin2 + set_config("Machine", "version", 5) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 0)) @@ -319,53 +323,59 @@ def test_get_global_xy(self): self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (25, 4)) def test_no_boot(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + version = MachineDataView.get_machine_version() + width, height = version.board_shape + # create an empty Machine + machine = version.create_machine(width, height) with self.assertRaises(SpinnMachineException): machine.validate() def test_negative_x(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + version = MachineDataView.get_machine_version() + width, height = version.board_shape + # create an empty Machine + machine = version.create_machine(width, height) chip = self._create_chip(2, -1) machine.add_chip(chip) with self.assertRaises(SpinnMachineException): machine.validate() def test_negative_y(self): - machine = MachineDataView.get_machine_version().create_machine(8, 8) + version = MachineDataView.get_machine_version() + width, height = version.board_shape + # create an empty Machine + machine = version.create_machine(width, height) chip = self._create_chip(-1, 3) machine.add_chip(chip) with self.assertRaises(SpinnMachineException): machine.validate() + def _non_ethernet_chip(self, machine): + for chip in machine.chips: + if chip.ip_address is None: + return chip + raise SpinnMachineException("No none Ethernet Chip") + def test_weird_ethernet1(self): - machine = virtual_machine(8, 8) - machine.get_chip_at(1, 3)._ip_address = "1.2.3.4" + machine = virtual_machine_by_boards(1) + self._non_ethernet_chip(machine)._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.get_chip_at(0, 1)._nearest_ethernet_x = 1 + machine = virtual_machine_by_boards(1) + self._non_ethernet_chip(machine)._nearest_ethernet_x = 1 with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_no_chip(self): - machine = virtual_machine(8, 8) - machine.get_chip_at(0, 1)._nearest_ethernet_x = 12 + machine = virtual_machine_by_boards(1) + self._non_ethernet_chip(machine)._nearest_ethernet_x = 12 with self.assertRaises(SpinnMachineException): machine.validate() - def test_getitem(self): - machine = virtual_machine(8, 8) - chip12 = machine[(1, 2)] - self.assertEqual(chip12.x, 1) - self.assertEqual(chip12.y, 2) - self.assertTrue((1, 2) in machine) - self.assertFalse((1, 9) in machine) - def test_concentric_xys(self): - machine = virtual_machine(8, 8) - machine.get_chip_at(1, 3) + machine = virtual_machine_by_min_size(5, 5) found = list(machine.concentric_xys(2, (2, 2))) expected = [ (2, 2), @@ -375,10 +385,10 @@ def test_concentric_xys(self): self.assertListEqual(expected, found) def test_too_few_cores(self): - machine = virtual_machine(8, 8) + machine = virtual_machine_by_boards(1) # Hack to get n_processors return a low number - chip01 = machine.get_chip_at(0, 1) - chip01._placable_processors = tuple([1, 2]) + chip = self._non_ethernet_chip(machine) + chip._placable_processors = tuple([1, 2]) with self.assertRaises(SpinnMachineException): machine.validate() From 340ff52431bb5f1b8264035b455afe08a1cec28e Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 11:37:37 +0100 Subject: [PATCH 34/54] use virtual_machine_by_boards --- unittests/test_json_machine.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 3d997dee..c320ebe9 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -60,12 +60,14 @@ def test_exceptions(self): self.assertEqual(vchip33.tag_ids, chip33.tag_ids) def test_monitor_exceptions(self): - vm = virtual_machine(width=8, height=8) + vm = virtual_machine_by_boards(1) MachineDataWriter.mock().set_machine(vm) - chip02 = vm[0, 2] + for chip in vm.chips: + if chip.ip_address is None: + break # Hack in an extra monitor - chip02._scamp_processors = tuple([0, 1]) - chip02._placable_processors = tuple([2, 3, 4, 5, 6, 7, 8, 9]) + chip._scamp_processors = tuple([0, 1]) + chip._placable_processors = tuple([2, 3, 4, 5, 6, 7, 8, 9]) jpath = mktemp("json") # Should still be able to write json even with more than one monitor to_json_path(jpath) From a082196ca33122f8162d48f10b2c3387b2ccefdb Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 11:41:11 +0100 Subject: [PATCH 35/54] flake8 --- spinn_machine/virtual_machine.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index b2a2e42c..8a6a4c28 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -14,7 +14,7 @@ import math from collections import defaultdict import logging -from typing import Dict, List, Optional, overload, Set, Tuple +from typing import Dict, List, Optional, Set, Tuple from spinn_utilities.config_holder import get_config_str_or_none from spinn_utilities.log import FormatAdapter from spinn_utilities.typing.coords import XY @@ -43,7 +43,8 @@ def virtual_machine(width: int, height: int, validate: bool = True): return factory.machine -def virtual_machine_by_min_size(width: int, height: int, validate: bool = True): +def virtual_machine_by_min_size( + width: int, height: int, validate: bool = True): """ Create a virtual SpiNNaker machine, used for planning execution. From b38c33e9d16276d8a086207c44e298f2927461b3 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 14:16:00 +0100 Subject: [PATCH 36/54] flake8 --- spinn_machine/version/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinn_machine/version/__init__.py b/spinn_machine/version/__init__.py index 489f6f94..586769de 100644 --- a/spinn_machine/version/__init__.py +++ b/spinn_machine/version/__init__.py @@ -15,4 +15,4 @@ from .version_factory import ( ANY_VERSION, BIG_MACHINE, FOUR_PLUS_CHIPS, version_factory) -__all__ = ["ANY_VERSION", "BIG_MACHINE", "FOUR_PLUS_CHIPS", "version_factory"] \ No newline at end of file +__all__ = ["ANY_VERSION", "BIG_MACHINE", "FOUR_PLUS_CHIPS", "version_factory"] From dba7f4ec9fe92bff794f5e3ead9454771b1358db Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 14:27:07 +0100 Subject: [PATCH 37/54] fix tests --- unittests/data/test_data.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index a6a9cbe5..807800d5 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -101,7 +101,7 @@ def test_mock_any(self): set_config("Machine", "version", ANY_VERSION) # check there is a value not what it is machine = MachineDataView.get_machine() - self.assertGreaterEqual(1, machine.n_chips) + self.assertGreaterEqual(machine.n_chips, 1) def test_mock_4_or_more(self): # Should work with any version @@ -110,12 +110,12 @@ def test_mock_4_or_more(self): machine = MachineDataView.get_machine() self.assertGreaterEqual(machine.n_chips, 4) - def test_mockFourPlus(self): + def test_mockAny(self): # Should work with any version set_config("Machine", "version", ANY_VERSION) # check there is a value not what it is machine = MachineDataView.get_machine() - self.assertGreaterEqual(4, machine.n_chips) + self.assertGreaterEqual(machine.n_chips, 1) def test_mock3(self): # Should work with any version From d206dec4c54d3b70add5070f7c40556086fc35bc Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 9 Apr 2024 15:02:52 +0100 Subject: [PATCH 38/54] fix error message --- spinn_machine/version/version_201.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spinn_machine/version/version_201.py b/spinn_machine/version/version_201.py index 9caf5d6c..9ad9b1fc 100644 --- a/spinn_machine/version/version_201.py +++ b/spinn_machine/version/version_201.py @@ -92,9 +92,9 @@ def get_potential_ethernet_chips( @overrides(AbstractVersion._verify_size) def _verify_size(self, width: int, height: int): if width != 1: - raise SpinnMachineException("Unexpected {width=}") + raise SpinnMachineException(f"Unexpected {width=}") if height != 1: - raise SpinnMachineException("Unexpected {height=}") + raise SpinnMachineException(f"Unexpected {height=}") @overrides(AbstractVersion._create_machine) def _create_machine(self, width: int, height: int, origin: str) -> Machine: From 25f0056f4a7d58a222dc9fe5b7b0cf070d6aa5a8 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 10 Apr 2024 07:29:26 +0100 Subject: [PATCH 39/54] use constants for version(s) being tested --- spinn_machine/version/__init__.py | 7 +- spinn_machine/version/version_factory.py | 28 +++- unittests/test_json_machine.py | 18 +-- unittests/test_machine.py | 55 +++++--- unittests/test_using_virtual_machine.py | 169 ++++++++--------------- unittests/test_virtual_machine201.py | 21 +-- 6 files changed, 136 insertions(+), 162 deletions(-) diff --git a/spinn_machine/version/__init__.py b/spinn_machine/version/__init__.py index 586769de..15f8c69b 100644 --- a/spinn_machine/version/__init__.py +++ b/spinn_machine/version/__init__.py @@ -13,6 +13,9 @@ # limitations under the License. from .version_factory import ( - ANY_VERSION, BIG_MACHINE, FOUR_PLUS_CHIPS, version_factory) + ANY_VERSION, BIG_MACHINE, FIVE, FOUR_PLUS_CHIPS, MULTIPLE_BOARDS, + SPIN2_1CHIP, THREE, version_factory, WRAPPABLE) -__all__ = ["ANY_VERSION", "BIG_MACHINE", "FOUR_PLUS_CHIPS", "version_factory"] +__all__ = ["ANY_VERSION", "BIG_MACHINE", "FIVE", "FOUR_PLUS_CHIPS", + "MULTIPLE_BOARDS", "SPIN2_1CHIP", "THREE", "version_factory", + "WRAPPABLE"] diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index e2633848..c9194fa8 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -25,9 +25,27 @@ logger = FormatAdapter(logging.getLogger(__name__)) +# Constant when wanting a specific version +THREE = 3 +FIVE = 5 +# New value subject to change +SPIN2_1CHIP = 201 + +# Flaks to test multiple versions including future ones ANY_VERSION = -1 + FOUR_PLUS_CHIPS = -2 -BIG_MACHINE = -3 + +# A Machine which support multiple boards +# Size of boards does nt matter +MULTIPLE_BOARDS = -3 + +# A Machine with at least 8 * 8 including ones typical on a Version 5 board +BIG_MACHINE = -4 + +# A Machine with multiple boards that could wrap +# Will have hard coded assumption of board size 8 * 8 +WRAPPABLE = -5 def version_factory() -> AbstractVersion: @@ -48,11 +66,11 @@ def version_factory() -> AbstractVersion: if version < 0: # test needs a version but ANY version will work if version == ANY_VERSION: - options = [2, 5, 201] + options = [THREE, FIVE, SPIN2_1CHIP] elif version == FOUR_PLUS_CHIPS: - options = [2, 5] - elif version == BIG_MACHINE: - options = [5] + options = [THREE] + elif version in [BIG_MACHINE, MULTIPLE_BOARDS, WRAPPABLE]: + options = [FIVE] else: raise SpinnMachineException( f"Unexpected cfg [Machine]version {version}") diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 647ff0cd..908ccf12 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -15,11 +15,13 @@ from tempfile import mktemp import unittest from spinn_utilities.config_holder import set_config -from spinn_machine import virtual_machine, virtual_machine_by_boards +from spinn_machine.virtual_machine import ( + virtual_machine, virtual_machine_by_boards, virtual_machine_by_min_size) from spinn_machine.data.machine_data_writer import MachineDataWriter from spinn_machine.config_setup import unittest_setup from spinn_machine.json_machine import (machine_from_json, to_json_path) -from spinn_machine.version import BIG_MACHINE, FOUR_PLUS_CHIPS +from spinn_machine.version import ( + BIG_MACHINE, FOUR_PLUS_CHIPS, FIVE, MULTIPLE_BOARDS, SPIN2_1CHIP, THREE) class TestJsonMachine(unittest.TestCase): @@ -28,7 +30,7 @@ def setUp(self): unittest_setup() def test_json_version_3(self): - set_config("Machine", "version", 3) + set_config("Machine", "version", THREE) vm = virtual_machine(width=2, height=2) MachineDataWriter.mock().set_machine(vm) jpath = mktemp("json") @@ -41,7 +43,7 @@ def test_json_version_3(self): self.assertEqual(str(vchip), str(jchip)) def test_json_version_5(self): - set_config("Machine", "version", 5) + set_config("Machine", "version", FIVE) vm = virtual_machine(width=8, height=8) MachineDataWriter.mock().set_machine(vm) jpath = mktemp("json") @@ -54,7 +56,7 @@ def test_json_version_5(self): self.assertEqual(str(vchip), str(jchip)) def test_json_version_201(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(width=1, height=1) MachineDataWriter.mock().set_machine(vm) jpath = mktemp("json") @@ -70,7 +72,7 @@ def test_json_hole(self): set_config("Machine", "version", BIG_MACHINE) set_config("Machine", "down_chips", "3,3") writer = MachineDataWriter.mock() - vm = virtual_machine_by_boards(1) + vm = virtual_machine_by_min_size(5, 5) writer.set_machine(vm) jpath = mktemp("json") to_json_path(jpath) @@ -102,7 +104,7 @@ def test_exceptions(self): self.assertEqual(vchip10.tag_ids, chip10.tag_ids) def test_monitor_exceptions(self): - set_config("Machine", "version", BIG_MACHINE) + set_config("Machine", "version", FOUR_PLUS_CHIPS) vm = virtual_machine_by_boards(1) MachineDataWriter.mock().set_machine(vm) for chip in vm.chips: @@ -119,7 +121,7 @@ def test_monitor_exceptions(self): machine_from_json(jpath) def test_ethernet_exceptions(self): - set_config("Machine", "version", BIG_MACHINE) + set_config("Machine", "version", MULTIPLE_BOARDS) vm = virtual_machine_by_boards(2) MachineDataWriter.mock().set_machine(vm) eth2 = vm.ethernet_connected_chips[1] diff --git a/unittests/test_machine.py b/unittests/test_machine.py index ddc9d322..09998bd4 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -20,6 +20,9 @@ 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.version import ( + ANY_VERSION, BIG_MACHINE, FIVE, FOUR_PLUS_CHIPS, MULTIPLE_BOARDS, + WRAPPABLE) from spinn_machine.virtual_machine import ( virtual_machine_by_boards, virtual_machine_by_min_size) from spinn_machine.config_setup import unittest_setup @@ -35,7 +38,6 @@ class SpinnMachineTestCase(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) self._sdram = 123469792 @@ -51,11 +53,12 @@ def setUp(self): self._ip = "192.162.240.253" def _create_chip(self, x, y): + n_cores = MachineDataView.get_machine_version().max_cores_per_chip if x == y == 0: - return Chip(x, y, 18, self._router, self._sdram, + return Chip(x, y, n_cores, self._router, self._sdram, self._nearest_ethernet_chip[0], self._nearest_ethernet_chip[1], self._ip) - return Chip(x, y, 18, self._router, self._sdram, + return Chip(x, y, n_cores, self._router, self._sdram, self._nearest_ethernet_chip[0], self._nearest_ethernet_chip[1], None) @@ -64,7 +67,7 @@ def test_create_new_machine_version5(self): test creating a new machine """ # Tests the version 5 values specifically - set_config("Machine", "version", 5) + set_config("Machine", "version", FIVE) new_machine = virtual_machine_by_boards(1) self.assertEqual(new_machine.width, 8) @@ -94,7 +97,7 @@ def test_create_new_machine_version5(self): def test_summary(self): # Strings hard coded to version 5 - set_config("Machine", "version", 5) + set_config("Machine", "version", FIVE) machine = virtual_machine_by_boards(1) self.assertEqual( "Machine on 127.0.0.0 with 48 Chips, 856 cores and 120.0 links. " @@ -142,12 +145,13 @@ def test_summary(self): "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): + def test_chip_already_exists(self): """ - check that building a machine with invalid chips causes errors + check that adding a chip that already exists causes an error :rtype: None """ + set_config("Machine", "version", ANY_VERSION) machine = virtual_machine_by_boards(1) with self.assertRaises(SpinnMachineAlreadyExistsException): machine.add_chip(Chip( @@ -155,22 +159,13 @@ def test_create_new_machine_with_invalid_chips(self): self._nearest_ethernet_chip[0], self._nearest_ethernet_chip[1], self._ip)) - def test_machine_add_duplicate_chip(self): - """ - test if adding the same chip twice causes an error - - :rtype: None - """ - new_machine = virtual_machine_by_boards(1) - with self.assertRaises(SpinnMachineAlreadyExistsException): - new_machine.add_chip(new_machine.get_chip_at(1, 1)) - def test_machine_get_chip_at(self): """ test the get_chip_at function from the machine with a valid request :rtype: None """ + set_config("Machine", "version", FOUR_PLUS_CHIPS) new_machine = virtual_machine_by_min_size(2, 2) self.assertEqual(1, new_machine.get_chip_at(1, 0).x) self.assertEqual(0, new_machine.get_chip_at(1, 0).y) @@ -184,6 +179,7 @@ def test_machine_big_x(self): :rtype: None """ + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -204,6 +200,7 @@ def test_machine_big_y(self): :rtype: None """ + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -224,6 +221,7 @@ def test_machine_get_chip_at_invalid_location(self): :rtype: None """ + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape @@ -236,6 +234,7 @@ def test_machine_is_chip_at_true(self): :rtype: None """ + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape @@ -248,12 +247,14 @@ def test_machine_is_chip_at_false(self): :rtype: None """ + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape self.assertFalse(new_machine.is_chip_at(width + 2, height // 2)) def test_machine_get_chips_on_board(self): + set_config("Machine", "version", MULTIPLE_BOARDS) new_machine = virtual_machine_by_boards(3) version = MachineDataView.get_machine_version() for eth_chip in new_machine._ethernet_connected_chips: @@ -273,8 +274,7 @@ def test_x_y_over_link(self): Notice that the function only does the math not validate the values. :return: """ - # TODO wrap arrounds in Spin2 - set_config("Machine", "version", 5) + set_config("Machine", "version", WRAPPABLE) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.xy_over_link(0, 0, 4), (23, 23)) @@ -303,8 +303,7 @@ def test_get_global_xy(self): Notice that the function only does the math not validate the values. :return: """ - # TODO wrap arounds in Spin2 - set_config("Machine", "version", 5) + set_config("Machine", "version", WRAPPABLE) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 0)) @@ -323,6 +322,7 @@ def test_get_global_xy(self): self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (25, 4)) def test_no_boot(self): + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -331,6 +331,7 @@ def test_no_boot(self): machine.validate() def test_negative_x(self): + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -341,6 +342,7 @@ def test_negative_x(self): machine.validate() def test_negative_y(self): + set_config("Machine", "version", ANY_VERSION) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -357,24 +359,30 @@ def _non_ethernet_chip(self, machine): raise SpinnMachineException("No none Ethernet Chip") def test_weird_ethernet1(self): + set_config("Machine", "version", FOUR_PLUS_CHIPS) machine = virtual_machine_by_boards(1) self._non_ethernet_chip(machine)._ip_address = "1.2.3.4" with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_x(self): + set_config("Machine", "version", FOUR_PLUS_CHIPS) machine = virtual_machine_by_boards(1) - self._non_ethernet_chip(machine)._nearest_ethernet_x = 1 + width, _ = MachineDataView.get_machine_version().board_shape + self._non_ethernet_chip(machine)._nearest_ethernet_x = width + 1 with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_no_chip(self): + set_config("Machine", "version", FOUR_PLUS_CHIPS) machine = virtual_machine_by_boards(1) - self._non_ethernet_chip(machine)._nearest_ethernet_x = 12 + _, height = MachineDataView.get_machine_version().board_shape + self._non_ethernet_chip(machine)._nearest_ethernet_x = height + 1 with self.assertRaises(SpinnMachineException): machine.validate() def test_concentric_xys(self): + set_config("Machine", "version", BIG_MACHINE) machine = virtual_machine_by_min_size(5, 5) found = list(machine.concentric_xys(2, (2, 2))) expected = [ @@ -385,6 +393,7 @@ def test_concentric_xys(self): self.assertListEqual(expected, found) def test_too_few_cores(self): + set_config("Machine", "version", FOUR_PLUS_CHIPS) machine = virtual_machine_by_boards(1) # Hack to get n_processors return a low number chip = self._non_ethernet_chip(machine) diff --git a/unittests/test_using_virtual_machine.py b/unittests/test_using_virtual_machine.py index c83db2b8..b1d5c455 100644 --- a/unittests/test_using_virtual_machine.py +++ b/unittests/test_using_virtual_machine.py @@ -16,10 +16,14 @@ from spinn_utilities.config_holder import set_config from spinn_machine.config_setup import unittest_setup from spinn_machine import Chip, Link, Router, virtual_machine -from spinn_machine.exceptions import ( - SpinnMachineAlreadyExistsException, SpinnMachineException) +from spinn_machine.virtual_machine import ( + virtual_machine_by_boards, virtual_machine_by_min_size) +from spinn_machine.data import MachineDataView +from spinn_machine.exceptions import (SpinnMachineException) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink from spinn_machine.machine_factory import machine_repair +from spinn_machine.version import ( + ANY_VERSION, BIG_MACHINE, FOUR_PLUS_CHIPS, WRAPPABLE) 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) @@ -58,114 +62,47 @@ def _create_chip(self, x, y): nearest_ethernet_chip[1], None) def test_new_vm_with_max_cores(self): - set_config("Machine", "version", 2) - n_cpus = 13 + set_config("Machine", "version", ANY_VERSION) + version = MachineDataView.get_machine_version() + n_cpus = version.max_cores_per_chip - 5 set_config("Machine", "max_machine_core", n_cpus) - vm = virtual_machine(2, 2, validate=True) - _chip = vm[1, 1] - self.assertEqual(n_cpus, _chip.n_processors) - self.assertEqual(n_cpus - 1, _chip.n_placable_processors) - self.assertEqual(1, _chip.n_scamp_processors) - self.assertEqual(n_cpus - 1, len(list(_chip.placable_processors_ids))) - self.assertEqual(1, len(list(_chip.scamp_processors_ids))) - count = sum(_chip.n_processors for _chip in vm.chips) - self.assertEqual(count, 4 * n_cpus) + # HACK Unsupported! Need new the version again after the cfg changed + MachineDataView._MachineDataView__data._machine_version = None + version = MachineDataView.get_machine_version() + vm = virtual_machine_by_boards(1, validate=True) + for chip in vm.chips: + self.assertEqual(n_cpus, chip.n_processors) + self.assertEqual(n_cpus - version.n_scamp_cores, + chip.n_placable_processors) + self.assertEqual(version.n_scamp_cores, chip.n_scamp_processors) + self.assertEqual(n_cpus - version.n_scamp_cores, + len(list(chip.placable_processors_ids))) + self.assertEqual(version.n_scamp_cores, + len(list(chip.scamp_processors_ids))) def test_iter_chips(self): - set_config("Machine", "version", 2) - vm = virtual_machine(2, 2) - self.assertEqual(4, vm.n_chips) + set_config("Machine", "version", ANY_VERSION) + vm = virtual_machine_by_boards(1) + n_chips = MachineDataView.get_machine_version().n_chips_per_board + self.assertEqual(n_chips, vm.n_chips) count = 0 for _chip in vm.chips: count += 1 - self.assertEqual(4, count) + self.assertEqual(n_chips, count) def test_down_chip(self): - set_config("Machine", "version", 2) + set_config("Machine", "version", FOUR_PLUS_CHIPS) down_chips = set() down_chips.add((1, 1)) set_config("Machine", "down_chips", "1,1") - vm = virtual_machine(2, 2) - self.assertEqual(3, vm.n_chips) + vm = virtual_machine_by_boards(1) + n_chips = MachineDataView.get_machine_version().n_chips_per_board + self.assertEqual(n_chips - 1, vm.n_chips) count = 0 for _chip in vm.chip_coordinates: count += 1 self.assertNotIn(_chip, down_chips) - 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_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) - - self.assertTrue(vm.is_chip_at(2, 2)) - _good = vm.get_chip_at(2, 2) - self.assertEqual(_chip, _good) - - _bad = vm.get_chip_at(2, 1) - self.assertIsNone(_bad) - - count = 0 - for _chip in vm.chips: - count += 1 - 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) - - _chip = self._create_chip(2, 2) - vm.add_chip(_chip) - self.assertEqual(4, vm.n_chips) - - self.assertTrue(vm.is_chip_at(2, 2)) - _good = vm.get_chip_at(2, 2) - self.assertEqual(_chip, _good) - - _bad = vm.get_chip_at(2, 1) - self.assertIsNone(_bad) - - _down = vm.get_chip_at(1, 1) - self.assertIsNone(_down) - - count = 0 - for _chip in vm.chips: - count += 1 - 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) - self.assertFalse(vm.is_chip_at(1, 1)) - - _chip = self._create_chip(1, 1) - vm.add_chip(_chip) - self.assertEqual(4, vm.n_chips) - - self.assertTrue(vm.is_chip_at(1, 1)) - _good = vm.get_chip_at(1, 1) - self.assertEqual(_chip, _good) - - _bad = vm.get_chip_at(2, 1) - self.assertIsNone(_bad) - - count = 0 - for _chip in vm.chips: - count += 1 - self.assertEqual(4, count) + self.assertEqual(n_chips - 1, count) def _check_path(self, source, target, path, width, height): new_target = ((source[0] + path[0] - path[2]) % width, @@ -173,7 +110,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) + set_config("Machine", "version", WRAPPABLE) machine = virtual_machine(16, 28, validate=True) for source in machine.chip_coordinates: for target in machine.chip_coordinates: @@ -187,7 +124,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) + set_config("Machine", "version", WRAPPABLE) width = 12 height = 24 machine = virtual_machine(width, height, validate=True) @@ -204,7 +141,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) + set_config("Machine", "version", WRAPPABLE) width = 12 height = 16 machine = virtual_machine(width, height, validate=False) @@ -229,7 +166,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) + set_config("Machine", "version", WRAPPABLE) width = 16 height = 12 machine = virtual_machine(width, height, validate=False) @@ -254,8 +191,8 @@ 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) + set_config("Machine", "version", ANY_VERSION) + machine = virtual_machine_by_boards(1) for x in range(-3, 3): for y in range(-3, 3): min1 = minimise_xyz((x, y, 0)) @@ -263,8 +200,8 @@ def test_minimize(self): self.assertEqual(min1, min2) def test_unreachable_incoming_chips(self): - set_config("Machine", "version", 5) - machine = virtual_machine(8, 8) + set_config("Machine", "version", BIG_MACHINE) + machine = virtual_machine_by_min_size(6, 6) # Delete links incoming to 3, 3 down_links = [ @@ -276,8 +213,8 @@ 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) + set_config("Machine", "version", BIG_MACHINE) + machine = virtual_machine_by_min_size(6, 6) # Delete links outgoing from 3, 3 for link in range(6): @@ -287,7 +224,8 @@ def test_unreachable_outgoing_chips(self): self.assertListEqual([(3, 3)], unreachable) def test_unreachable_incoming_local_chips(self): - set_config("Machine", "version", 5) + set_config("Machine", "version", WRAPPABLE) + # Assumes boards of exactly size 8,8 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) @@ -296,7 +234,8 @@ def test_unreachable_incoming_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_unreachable_outgoing_local_chips(self): - set_config("Machine", "version", 5) + set_config("Machine", "version", WRAPPABLE) + # Assumes boards of exactly size 8,8 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) @@ -305,7 +244,8 @@ def test_unreachable_outgoing_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_repair_with_local_orphan(self): - set_config("Machine", "version", 5) + set_config("Machine", "version", WRAPPABLE) + # Assumes boards of exactly size 8,8 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) @@ -319,8 +259,9 @@ 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) + set_config("Machine", "version", WRAPPABLE) machine = virtual_machine(12, 12) + # Assumes boards of exactly size 8,8 # Delete some links between boards down_links = [ (7, 7, 0), (7, 3, 1), (6, 7, 2), (4, 7, 3), (8, 6, 4), (8, 4, 5)] @@ -334,7 +275,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) + set_config("Machine", "version", WRAPPABLE) machine = virtual_machine(8, 8) # Delete some random links @@ -351,8 +292,8 @@ 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) + set_config("Machine", "version", BIG_MACHINE) + machine = virtual_machine_by_boards(1) del machine._chips[(3, 3)] set_config("Machine", "repair_machine", False) @@ -361,13 +302,13 @@ 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", "version", BIG_MACHINE) 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") set_config("Machine", "down_links", "1,3,3:3,5,3:5,3,3,ignored_ip") - machine = virtual_machine(8, 8) + machine = virtual_machine_by_min_size(8, 8) self.assertFalse(machine.is_chip_at(4, 4)) self.assertFalse(machine.is_chip_at(2, 2)) diff --git a/unittests/test_virtual_machine201.py b/unittests/test_virtual_machine201.py index 0fbeb9f1..416f8a34 100644 --- a/unittests/test_virtual_machine201.py +++ b/unittests/test_virtual_machine201.py @@ -18,6 +18,7 @@ from spinn_machine import Chip, Link, Router, virtual_machine from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) +from spinn_machine.version import SPIN2_1CHIP class TestVirtualMachine201(unittest.TestCase): @@ -51,7 +52,7 @@ def _create_chip(self, x, y): nearest_ethernet_chip[1], None) def test_illegal_vms(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) with self.assertRaises(SpinnMachineException): virtual_machine(width=-1, height=2) with self.assertRaises(SpinnMachineException): @@ -63,8 +64,8 @@ def test_illegal_vms(self): with self.assertRaises(SpinnMachineException): virtual_machine(width=2, height=2) - def test_version_201(self): - set_config("Machine", "version", 201) + def test_version_SPIN2_1CHIP(self): + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(width=1, height=1) self.assertEqual(1, vm.n_chips) self.assertTrue(vm.is_chip_at(0, 0)) @@ -93,7 +94,7 @@ def test_version_201(self): self.assertEqual(0, len(vm._fpga_links)) def test_new_vm_with_max_cores(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) n_cpus = 105 set_config("Machine", "max_machine_core", n_cpus) vm = virtual_machine(1, 1, validate=True) @@ -107,7 +108,7 @@ def test_new_vm_with_max_cores(self): self.assertEqual(count, 1 * n_cpus) def test_iter_chips(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(1, 1) self.assertEqual(1, vm.n_chips) count = 0 @@ -116,14 +117,14 @@ def test_iter_chips(self): self.assertEqual(1, count) def test_add_existing_chip(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(1, 1) _chip = self._create_chip(0, 0) with self.assertRaises(SpinnMachineAlreadyExistsException): vm.add_chip(_chip) def test_chips(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(1, 1) count = 0 for _chip in vm.chips: @@ -131,7 +132,7 @@ def test_chips(self): self.assertEqual(count, 1) def test_ethernet_chips_exist(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(width=1, height=1) for eth_chip in vm._ethernet_connected_chips: self.assertTrue(vm.get_chip_at(eth_chip.x, eth_chip.y), @@ -140,13 +141,13 @@ def test_ethernet_chips_exist(self): .format(eth_chip.x, eth_chip.y)) def test_boot_chip(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(1, 1) # as Chip == its XY self.assertEqual(vm.boot_chip, (0, 0)) def test_get_chips_on_boards(self): - set_config("Machine", "version", 201) + set_config("Machine", "version", SPIN2_1CHIP) vm = virtual_machine(width=1, height=1) # check each chip appears only once on the entire board count00 = 0 From 1a0c5081b40bfc232acac095b3145684b2588b4d Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 10 Apr 2024 07:52:37 +0100 Subject: [PATCH 40/54] move supports_multiple_boards logic to version --- spinn_machine/full_wrap_machine.py | 4 ---- spinn_machine/horizontal_wrap_machine.py | 4 ---- spinn_machine/machine.py | 19 ++----------------- spinn_machine/no_wrap_machine.py | 4 ---- spinn_machine/version/abstract_version.py | 12 ++++++++++++ spinn_machine/version/version_201.py | 5 +++++ spinn_machine/version/version_3.py | 5 +++++ spinn_machine/version/version_5.py | 5 +++++ spinn_machine/vertical_wrap_machine.py | 4 ---- 9 files changed, 29 insertions(+), 33 deletions(-) diff --git a/spinn_machine/full_wrap_machine.py b/spinn_machine/full_wrap_machine.py index f8f38baf..d7fef8fa 100644 --- a/spinn_machine/full_wrap_machine.py +++ b/spinn_machine/full_wrap_machine.py @@ -26,10 +26,6 @@ class FullWrapMachine(Machine): This class provides the more complex maths to deal with wraps. """ - @overrides(Machine.multiple_48_chip_boards) - def multiple_48_chip_boards(self) -> bool: - return self._width % 12 == 0 and self._height % 12 == 0 - @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet( self, ethernet_x: int, ethernet_y: int) -> Iterable[XY]: diff --git a/spinn_machine/horizontal_wrap_machine.py b/spinn_machine/horizontal_wrap_machine.py index 6fdb8adf..6ec9dac9 100644 --- a/spinn_machine/horizontal_wrap_machine.py +++ b/spinn_machine/horizontal_wrap_machine.py @@ -27,10 +27,6 @@ class HorizontalWrapMachine(Machine): This class provides the more complex maths to deal with wraps. """ - @overrides(Machine.multiple_48_chip_boards) - def multiple_48_chip_boards(self) -> bool: - return self._width % 12 == 0 and (self._height - 4) % 12 == 0 - @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet( self, ethernet_x: int, ethernet_y: int) -> Iterable[XY]: diff --git a/spinn_machine/machine.py b/spinn_machine/machine.py index 945f5cf6..081c497d 100644 --- a/spinn_machine/machine.py +++ b/spinn_machine/machine.py @@ -119,21 +119,6 @@ def __init__(self, width: int, height: int, chip_core_map: Dict[XY, int], self._n_router_entries_counter: Counter[int] = Counter() self._sdram_counter: Counter[int] = Counter() - @abstractmethod - def multiple_48_chip_boards(self) -> bool: - """ - Checks that the width and height correspond to the expected size for a - multi-board machine made up of more than one 48 chip board. - - The assumption is that any size machine can be supported but that - only ones with an expected 48 chip board size can have more than one - Ethernet-enabled chip. - - :return: True if this machine can have multiple 48 chip boards - :rtype: bool - """ - raise NotImplementedError - @abstractmethod def get_xys_by_ethernet( self, ethernet_x: int, ethernet_y: int) -> Iterable[XY]: @@ -501,15 +486,15 @@ def validate(self) -> None: if self._boot_ethernet_address is None: raise SpinnMachineException( "no ethernet chip at 0, 0 found") + version = MachineDataView.get_machine_version() if len(self._ethernet_connected_chips) > 1: - if not self.multiple_48_chip_boards(): + if not version.supports_multiple_boards: raise SpinnMachineException( f"A {self.wrap} machine of size {self._width}, " f"{self._height} can not handle multiple ethernet chips") # The fact that self._boot_ethernet_address is set means there is an # Ethernet chip and it is at 0,0 so no need to check that - version = MachineDataView.get_machine_version() for chip in self.chips: if chip.x < 0: raise SpinnMachineException( diff --git a/spinn_machine/no_wrap_machine.py b/spinn_machine/no_wrap_machine.py index d2fee713..c0e5b8a2 100644 --- a/spinn_machine/no_wrap_machine.py +++ b/spinn_machine/no_wrap_machine.py @@ -27,10 +27,6 @@ class NoWrapMachine(Machine): This class provides the simpler maths that do not deal with wraps. """ - @overrides(Machine.multiple_48_chip_boards) - def multiple_48_chip_boards(self) -> bool: - return (self._width - 4) % 12 == 0 and (self._height - 4) % 12 == 0 - @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet( self, ethernet_x: int, ethernet_y: int) -> Iterable[XY]: diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index f21f583d..18435b3f 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -386,9 +386,21 @@ def size_from_n_boards(self, n_boards: int) -> Tuple[int, int]: # Override for versions that support multiple boards if n_boards == 1: return self.board_shape + if self.supports_multiple_boards: + raise NotImplementedError raise SpinnMachineException( f"Version {self} does not support multiple boards") + @property + @abstractmethod + def supports_multiple_boards(self) -> bool: + """ + Specifies if this version allows machines of more than one board + + :return: + """ + raise NotImplementedError + def spinnaker_links(self) -> List[Tuple[int, int, int]]: """ The list of Local X, Y and link Id to add spinnaker links to diff --git a/spinn_machine/version/version_201.py b/spinn_machine/version/version_201.py index 9ad9b1fc..e7faf0d1 100644 --- a/spinn_machine/version/version_201.py +++ b/spinn_machine/version/version_201.py @@ -106,6 +106,11 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: return "Only Chip 0, 0 may be an Ethernet Chip" return None + @property + @overrides(AbstractVersion.supports_multiple_boards) + def supports_multiple_boards(self) -> bool: + return False + @overrides(AbstractVersion.spinnaker_links) def spinnaker_links(self) -> List[Tuple[int, int, int]]: return [] diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index 40a275f4..5ecd6c3d 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -73,6 +73,11 @@ def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]: return "Only Chip 0, 0 may be an Ethernet Chip" return None + @property + @overrides(VersionSpin1.supports_multiple_boards) + def supports_multiple_boards(self) -> bool: + return False + @overrides(VersionSpin1.spinnaker_links) def spinnaker_links(self) -> List[Tuple[int, int, int]]: return [(0, 0, 3), (1, 0, 0)] diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index c6e8336d..0f63d4f9 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -121,6 +121,11 @@ def size_from_n_boards(self, n_boards: int) -> Tuple[int, int]: height = math.ceil(triads / width) return width * 12 + 4, height * 12 + 4 + @property + @overrides(VersionSpin1.supports_multiple_boards) + def supports_multiple_boards(self) -> bool: + return True + @overrides(VersionSpin1.spinnaker_links) def spinnaker_links(self) -> List[Tuple[int, int, int]]: return [(0, 0, 4)] diff --git a/spinn_machine/vertical_wrap_machine.py b/spinn_machine/vertical_wrap_machine.py index c1b16c4e..cbe90102 100644 --- a/spinn_machine/vertical_wrap_machine.py +++ b/spinn_machine/vertical_wrap_machine.py @@ -27,10 +27,6 @@ class VerticalWrapMachine(Machine): This class provides the more complex maths to deal with wraps. """ - @overrides(Machine.multiple_48_chip_boards) - def multiple_48_chip_boards(self) -> bool: - return (self._width - 4) % 12 == 0 and self._height % 12 == 0 - @overrides(Machine.get_xys_by_ethernet) def get_xys_by_ethernet( self, ethernet_x: int, ethernet_y: int) -> Iterable[XY]: From 8f48a2d2d6712d94d9f0d052ad8f83f7371b1547 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 10 Apr 2024 08:07:29 +0100 Subject: [PATCH 41/54] flake8 --- spinn_machine/version/version_5.py | 1 - unittests/test_json_machine.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/spinn_machine/version/version_5.py b/spinn_machine/version/version_5.py index 0f63d4f9..30ac9a59 100644 --- a/spinn_machine/version/version_5.py +++ b/spinn_machine/version/version_5.py @@ -13,7 +13,6 @@ # limitations under the License. import math -from typing import Final, Mapping, Optional, Sequence, Tuple from typing import Final, List, Mapping, Optional, Sequence, Tuple from spinn_utilities.overrides import overrides from spinn_utilities.typing.coords import XY diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 908ccf12..370f3510 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -138,5 +138,6 @@ def test_ethernet_exceptions(self): jeth2 = jm.ethernet_connected_chips[1] self.assertEqual(jeth2.tag_ids, eth2.tag_ids) + if __name__ == '__main__': unittest.main() From 803d1533d1877fe86853887f626652266b0baa45 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 10 Apr 2024 08:18:25 +0100 Subject: [PATCH 42/54] removed special virtual_machine methods from init file --- spinn_machine/__init__.py | 6 ++---- spinn_machine/data/machine_data_writer.py | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spinn_machine/__init__.py b/spinn_machine/__init__.py index 54134e64..57c9644d 100644 --- a/spinn_machine/__init__.py +++ b/spinn_machine/__init__.py @@ -85,12 +85,10 @@ from .multicast_routing_entry import MulticastRoutingEntry from .router import Router from .spinnaker_triad_geometry import SpiNNakerTriadGeometry -from .virtual_machine import ( - virtual_machine, virtual_machine_by_boards, virtual_machine_by_cores) +from .virtual_machine import virtual_machine from .fixed_route_entry import FixedRouteEntry __all__ = ["Chip", "CoreSubset", "CoreSubsets", "FixedRouteEntry", "FrozenCoreSubsets", "Link", "Machine", "MulticastRoutingEntry", - "Router", "SpiNNakerTriadGeometry", "virtual_machine", - "virtual_machine_by_boards", "virtual_machine_by_cores"] + "Router", "SpiNNakerTriadGeometry", "virtual_machine"] diff --git a/spinn_machine/data/machine_data_writer.py b/spinn_machine/data/machine_data_writer.py index f5aec30a..7101bed6 100644 --- a/spinn_machine/data/machine_data_writer.py +++ b/spinn_machine/data/machine_data_writer.py @@ -17,7 +17,8 @@ from spinn_utilities.data.utils_data_writer import UtilsDataWriter from spinn_utilities.overrides import overrides from spinn_utilities.log import FormatAdapter -from spinn_machine import Machine, virtual_machine_by_boards +from spinn_machine import Machine +from spinn_machine.virtual_machine import virtual_machine_by_boards from .machine_data_view import MachineDataView, _MachineDataModel logger = FormatAdapter(logging.getLogger(__name__)) __temp_dir = None From c5327d0ac13007d04a85441a1956dfab3e2ea7d7 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 10 Apr 2024 08:19:11 +0100 Subject: [PATCH 43/54] spelling --- spinn_machine/version/version_factory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index c9194fa8..075f4246 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -37,7 +37,7 @@ FOUR_PLUS_CHIPS = -2 # A Machine which support multiple boards -# Size of boards does nt matter +# Size of boards does not matter MULTIPLE_BOARDS = -3 # A Machine with at least 8 * 8 including ones typical on a Version 5 board From 56baf274c2729de2aa0a0ec88cb3b064ff74d456 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 10 Apr 2024 08:31:16 +0100 Subject: [PATCH 44/54] check for None --- spinn_machine/version/version_factory.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index 075f4246..bdce5c66 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -63,8 +63,7 @@ def version_factory() -> AbstractVersion: version = get_config_int_or_none("Machine", "version") - if version < 0: - # test needs a version but ANY version will work + if version is not None and version < 0: if version == ANY_VERSION: options = [THREE, FIVE, SPIN2_1CHIP] elif version == FOUR_PLUS_CHIPS: From c1af52525d08fe3bdb032e8046f20e07b1f817a8 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 11 Apr 2024 07:41:56 +0100 Subject: [PATCH 45/54] fix spelling --- spinn_machine/version/version_3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spinn_machine/version/version_3.py b/spinn_machine/version/version_3.py index a186ccb6..1b819a75 100644 --- a/spinn_machine/version/version_3.py +++ b/spinn_machine/version/version_3.py @@ -59,9 +59,9 @@ def get_potential_ethernet_chips( @overrides(VersionSpin1._verify_size) def _verify_size(self, width: int, height: int): if width != 2: - raise SpinnMachineException("Unexpected {width=}") + raise SpinnMachineException(f"Unexpected {width=}") if height != 2: - raise SpinnMachineException("Unexpected {height=}") + raise SpinnMachineException(f"Unexpected {height=}") @overrides(VersionSpin1._create_machine) def _create_machine(self, width: int, height: int, origin: str) -> Machine: From c4bf8de592110116c4e9c2b527852934993c162e Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 11 Apr 2024 15:51:51 +0100 Subject: [PATCH 46/54] virtual machine by n chips --- spinn_machine/version/abstract_version.py | 18 +++++++++++++++- spinn_machine/virtual_machine.py | 25 +++++++++++++++++++++++ unittests/test_virtual_machine.py | 16 ++++++++++++--- unittests/version/test_version3.py | 10 ++++++++- unittests/version/test_version5.py | 6 ++++++ 5 files changed, 70 insertions(+), 5 deletions(-) diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index 848bba9b..d1c8efc9 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -360,7 +360,7 @@ def size_from_n_cores(self, n_cores: int) -> Tuple[int, int]: Takes into consideration scamp and monitor cores. Designed for use with virtual boards. - Does not include a safety factor for blacklisted boards. + Does not include a safety factor for blacklisted cores or chips. For real machines a slightly bigger Machine may be needed. :param int n_cores: Number of None Scamp and monitor cores needed @@ -374,6 +374,22 @@ def size_from_n_cores(self, n_cores: int) -> Tuple[int, int]: # Double minus to round up return self.size_from_n_boards(-(-n_cores // cores_per_board)) + def size_from_n_chips(self, n_chips: int) -> Tuple[int, int]: + """ + Returns the size needed to support this many chips. + + Designed for use with virtual boards. + Does not include a safety factor for blacklisted Chips. + For real machines a slightly bigger Machine may be needed. + + :param int n_boards: + :rtype: (int, int) + :raises SpinnMachineException: + If multiple boards are needed but not supported + """ + # Double minus to round up + return self.size_from_n_boards(-(-n_chips // self.n_chips_per_board)) + def size_from_n_boards(self, n_boards: int) -> Tuple[int, int]: """ Returns the size needed to support this many boards. diff --git a/spinn_machine/virtual_machine.py b/spinn_machine/virtual_machine.py index 8a6a4c28..3575842c 100644 --- a/spinn_machine/virtual_machine.py +++ b/spinn_machine/virtual_machine.py @@ -92,6 +92,31 @@ def virtual_machine_by_cores(n_cores: int, validate: bool = True): return virtual_machine(width, height, validate) +def virtual_machine_by_chips(n_chips: int, validate: bool = True): + """ + Create a virtual SpiNNaker machine, used for planning execution. + + Semantic sugar for + + MachineDataView.get_machine_version() + + width, height = version.size_from_n_cchips(n_cores) + + return virtual_machine(width, height, validate) + + :param n_chips: Minimum number of chips + :param bool validate: if True will call the machine validate function + + :returns: a virtual machine (that cannot execute code) + :rtype: ~spinn_machine.Machine + :raises SpinnMachineException: + If multiple boards are needed but not supported + """ + version = MachineDataView.get_machine_version() + width, height = version.size_from_n_chips(n_chips) + return virtual_machine(width, height, validate) + + def virtual_machine_by_boards(n_boards: int, validate: bool = True): """ Create a virtual SpiNNaker machine, used for planning execution. diff --git a/unittests/test_virtual_machine.py b/unittests/test_virtual_machine.py index 3820ca95..b9140003 100644 --- a/unittests/test_virtual_machine.py +++ b/unittests/test_virtual_machine.py @@ -15,9 +15,10 @@ import unittest from spinn_utilities.config_holder import set_config from spinn_machine.config_setup import unittest_setup -from spinn_machine import (Chip, Link, Router, virtual_machine, - virtual_machine_by_boards, virtual_machine_by_cores) -from spinn_machine.virtual_machine import virtual_machine_by_min_size +from spinn_machine import (Chip, Link, Router, virtual_machine) +from spinn_machine.virtual_machine import ( + virtual_machine_by_boards, virtual_machine_by_chips, + virtual_machine_by_cores, virtual_machine_by_min_size) from spinn_machine.data import MachineDataView from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) @@ -1101,6 +1102,10 @@ def test_2_2_by_cores(self): self.assertEqual(4, machine2.n_chips) self.assertEqual(2, machine2.width) self.assertEqual(2, machine2.height) + machine = virtual_machine_by_chips(3) + self.assertEqual(4, machine.n_chips) + self.assertEqual(2, machine.width) + self.assertEqual(2, machine.height) def test_2_2_by_cores_too_many(self): set_config("Machine", "version", 2) @@ -1138,6 +1143,11 @@ def test_8_8_by_cores_3_boards(self): self.assertEqual(16, machine.width) self.assertEqual(16, machine.height) self.assertEqual(n_cores*3, machine.total_available_user_cores) + machine = virtual_machine_by_chips(100) + # despite asking for two boards you get a triad + self.assertEqual(16, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores*3, machine.total_available_user_cores) def test_8_8_by_cores_6_boards(self): set_config("Machine", "version", 5) diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py index 3095fe46..af591d96 100644 --- a/unittests/version/test_version3.py +++ b/unittests/version/test_version3.py @@ -145,7 +145,15 @@ def test_size_from_n_cores(self): self.assertEqual((2, 2), version.size_from_n_cores(10)) self.assertEqual((2, 2), version.size_from_n_cores(17 * 4)) with self.assertRaises(SpinnMachineException): - self.assertEqual((2, 2), version.size_from_n_cores(17 * 4 + 1)) + version.size_from_n_cores(17 * 4 + 1) + + + def test_size_from_n_chips(self): + version = Version3() + self.assertEqual((2, 2), version.size_from_n_chips(1)) + self.assertEqual((2, 2), version.size_from_n_chips(4)) + with self.assertRaises(SpinnMachineException): + version.size_from_n_chips(5) if __name__ == '__main__': diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index 50e0bc2f..363393d9 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -166,6 +166,12 @@ def test_size_from_n_cores(self): self.assertEqual((40, 28), version.size_from_n_cores(n_cores * 18)) self.assertEqual((40, 40), version.size_from_n_cores(n_cores * 18 + 1)) + def test_size_from_n_chips(self): + version = Version5() + self.assertEqual((8, 8), version.size_from_n_chips(1)) + self.assertEqual((8, 8), version.size_from_n_chips(48)) + self.assertEqual((16, 16), version.size_from_n_chips(49)) + if __name__ == '__main__': unittest.main() From c1281e669c38d850ab8ae9082d174d0f823e6749 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 12 Apr 2024 06:54:54 +0100 Subject: [PATCH 47/54] flake8 --- unittests/version/test_version3.py | 1 - 1 file changed, 1 deletion(-) diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py index af591d96..f0dff481 100644 --- a/unittests/version/test_version3.py +++ b/unittests/version/test_version3.py @@ -147,7 +147,6 @@ def test_size_from_n_cores(self): with self.assertRaises(SpinnMachineException): version.size_from_n_cores(17 * 4 + 1) - def test_size_from_n_chips(self): version = Version3() self.assertEqual((2, 2), version.size_from_n_chips(1)) From f2b414a23d37b4f40e3bac10e8f13c690e71d5b7 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 12 Apr 2024 09:31:00 +0100 Subject: [PATCH 48/54] test lost in merge --- unittests/test_virtual_machine201.py | 35 ++++++++-- unittests/test_virtual_machine3.py | 27 ++++++++ unittests/test_virtual_machine5.py | 95 ++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 4 deletions(-) diff --git a/unittests/test_virtual_machine201.py b/unittests/test_virtual_machine201.py index 416f8a34..6c550c51 100644 --- a/unittests/test_virtual_machine201.py +++ b/unittests/test_virtual_machine201.py @@ -19,6 +19,9 @@ from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) from spinn_machine.version import SPIN2_1CHIP +from spinn_machine.virtual_machine import ( + virtual_machine_by_boards, virtual_machine_by_chips, + virtual_machine_by_cores) class TestVirtualMachine201(unittest.TestCase): @@ -219,13 +222,37 @@ def _check_path(self, source, target, path, width, height): self.assertEqual(target, new_target, "{}{}".format(source, path)) def test_n_cores_2_2(self): - set_config("Machine", "version", 2) - machine = virtual_machine(2, 2) + set_config("Machine", "version", SPIN2_1CHIP) + machine = virtual_machine(1, 1) n_cores = sum( cores for (_, cores) in machine.get_xy_cores_by_ethernet(0, 0)) - self.assertEqual(n_cores, 4 * 18) + self.assertEqual(n_cores, 152) n_cores = sum(chip.n_processors for chip in machine.chips) - self.assertEqual(n_cores, 4 * 18) + self.assertEqual(n_cores, 152) + + def test_by(self): + set_config("Machine", "version", SPIN2_1CHIP) + n_cores = 40 + machine = virtual_machine_by_cores(n_cores) + self.assertEqual(1, machine.n_chips) + self.assertEqual(1, machine.width) + self.assertEqual(1, machine.height) + self.assertGreaterEqual(machine.total_available_user_cores, n_cores) + machine2 = virtual_machine_by_boards(1) + self.assertEqual(1, machine2.n_chips) + self.assertEqual(1, machine2.width) + self.assertEqual(1, machine2.height) + machine = virtual_machine_by_chips(1) + self.assertEqual(1, machine.n_chips) + self.assertEqual(1, machine.width) + self.assertEqual(1, machine.height) + + def test_by_cores_too_many(self): + set_config("Machine", "version", SPIN2_1CHIP) + with self.assertRaises(SpinnMachineException): + virtual_machine_by_cores(200) + with self.assertRaises(SpinnMachineException): + virtual_machine_by_boards(2) if __name__ == '__main__': diff --git a/unittests/test_virtual_machine3.py b/unittests/test_virtual_machine3.py index 41c82d60..389ee30a 100644 --- a/unittests/test_virtual_machine3.py +++ b/unittests/test_virtual_machine3.py @@ -19,6 +19,9 @@ from spinn_machine.link_data_objects import SpinnakerLinkData from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) +from spinn_machine.virtual_machine import ( + virtual_machine_by_boards, virtual_machine_by_chips, + virtual_machine_by_cores) class TestVirtualMachine3(unittest.TestCase): @@ -271,6 +274,30 @@ 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_2_2_by(self): + set_config("Machine", "version", 2) + n_cores = 40 + machine = virtual_machine_by_cores(n_cores) + self.assertEqual(4, machine.n_chips) + self.assertEqual(2, machine.width) + self.assertEqual(2, machine.height) + self.assertGreaterEqual(machine.total_available_user_cores, n_cores) + machine2 = virtual_machine_by_boards(1) + self.assertEqual(4, machine2.n_chips) + self.assertEqual(2, machine2.width) + self.assertEqual(2, machine2.height) + machine = virtual_machine_by_chips(3) + self.assertEqual(4, machine.n_chips) + self.assertEqual(2, machine.width) + self.assertEqual(2, machine.height) + + def test_2_2_by_cores_too_many(self): + set_config("Machine", "version", 2) + with self.assertRaises(SpinnMachineException): + virtual_machine_by_cores(100) + with self.assertRaises(SpinnMachineException): + virtual_machine_by_boards(2) + if __name__ == '__main__': unittest.main() diff --git a/unittests/test_virtual_machine5.py b/unittests/test_virtual_machine5.py index 2d599c2b..89196e52 100644 --- a/unittests/test_virtual_machine5.py +++ b/unittests/test_virtual_machine5.py @@ -17,9 +17,13 @@ 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 SpinnMachineException from spinn_machine.link_data_objects import SpinnakerLinkData from spinn_machine.version.version_5 import CHIPS_PER_BOARD +from spinn_machine.virtual_machine import ( + virtual_machine_by_boards, virtual_machine_by_chips, + virtual_machine_by_cores, virtual_machine_by_min_size) class TestVirtualMachine5(unittest.TestCase): @@ -725,6 +729,97 @@ def test_n_cores_8_8(self): n_cores = sum(chip.n_processors for chip in machine.chips) self.assertEqual(n_cores, self.VERSION_5_N_CORES_PER_BOARD) + def test_8_8_by_cores_1_board(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine_by_cores(n_cores) + self.assertEqual(8, machine.width) + self.assertEqual(8, machine.height) + self.assertEqual(n_cores, machine.total_available_user_cores) + machine = virtual_machine_by_boards(1) + self.assertEqual(8, machine.width) + self.assertEqual(8, machine.height) + self.assertEqual(n_cores, machine.total_available_user_cores) + + def test_8_8_by_cores_3_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine_by_cores(n_cores * 2) + # despite asking for two boards you get a triad + self.assertEqual(16, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores*3, machine.total_available_user_cores) + machine = virtual_machine_by_boards(2) + # despite asking for two boards you get a triad + self.assertEqual(16, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores*3, machine.total_available_user_cores) + machine = virtual_machine_by_chips(100) + # despite asking for two boards you get a triad + self.assertEqual(16, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores*3, machine.total_available_user_cores) + + def test_8_8_by_cores_6_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine_by_cores(n_cores * 5) + self.assertEqual(28, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores * 6, machine.total_available_user_cores) + machine = virtual_machine_by_boards(4) + self.assertEqual(28, machine.width) + self.assertEqual(16, machine.height) + self.assertEqual(n_cores * 6, machine.total_available_user_cores) + + def test_8_8_by_cores_12_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine_by_cores(n_cores * 9) + self.assertEqual(28, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 12, machine.total_available_user_cores) + machine = virtual_machine_by_boards(10) + self.assertEqual(28, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 12, machine.total_available_user_cores) + + def test_8_8_by_cores_18_boards(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + n_cores = sum(version.chip_core_map.values()) + n_cores -= version.n_chips_per_board + machine = virtual_machine_by_cores(n_cores * 12 + 1) + self.assertEqual(40, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 18, machine.total_available_user_cores) + machine = virtual_machine_by_boards(15) + self.assertEqual(40, machine.width) + self.assertEqual(28, machine.height) + self.assertEqual(n_cores * 18, machine.total_available_user_cores) + + def test_by_min_size(self): + set_config("Machine", "version", 5) + machine = virtual_machine_by_min_size(15, 21) + self.assertGreaterEqual(machine.width, 15) + self.assertGreaterEqual(machine.height, 21) + + def test_by_min_size_edge_case(self): + set_config("Machine", "version", 5) + version = MachineDataView.get_machine_version() + width, height = version.board_shape + machine = virtual_machine_by_min_size(width, height + 1) + self.assertGreaterEqual(machine.width, width) + self.assertGreaterEqual(machine.height, height + 1) + if __name__ == '__main__': unittest.main() From 4a17c2a9245fd43dff7312ed44d01d0ff38e1c60 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 12 Apr 2024 14:13:28 +0100 Subject: [PATCH 49/54] VersionStrings --- spinn_machine/spinn_machine.cfg | 2 + spinn_machine/version/__init__.py | 8 +-- spinn_machine/version/version_factory.py | 17 +++--- spinn_machine/version/version_strings.py | 68 ++++++++++++++++++++++++ unittests/data/test_data.py | 20 +++---- unittests/test_chip.py | 4 +- unittests/test_json_machine.py | 12 ++--- unittests/test_machine.py | 43 ++++++++------- unittests/test_using_virtual_machine.py | 37 +++++++------ unittests/version/test_version201.py | 5 +- unittests/version/test_version3.py | 5 +- unittests/version/test_version5.py | 5 +- unittests/version/test_version_string.py | 39 ++++++++++++++ 13 files changed, 182 insertions(+), 83 deletions(-) create mode 100644 spinn_machine/version/version_strings.py create mode 100644 unittests/version/test_version_string.py diff --git a/spinn_machine/spinn_machine.cfg b/spinn_machine/spinn_machine.cfg index 8a0a6f60..5cc2cee1 100644 --- a/spinn_machine/spinn_machine.cfg +++ b/spinn_machine/spinn_machine.cfg @@ -2,6 +2,8 @@ [Machine] version = None +# Used Instead of version if multiple versions should be tested! +versions = None width = None height = None # Note: if json_path is set all other configs for virtual boards are ignored diff --git a/spinn_machine/version/__init__.py b/spinn_machine/version/__init__.py index 15f8c69b..83b00d3e 100644 --- a/spinn_machine/version/__init__.py +++ b/spinn_machine/version/__init__.py @@ -12,10 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .version_factory import ( - ANY_VERSION, BIG_MACHINE, FIVE, FOUR_PLUS_CHIPS, MULTIPLE_BOARDS, - SPIN2_1CHIP, THREE, version_factory, WRAPPABLE) +from .version_factory import FIVE, SPIN2_1CHIP, THREE, version_factory -__all__ = ["ANY_VERSION", "BIG_MACHINE", "FIVE", "FOUR_PLUS_CHIPS", - "MULTIPLE_BOARDS", "SPIN2_1CHIP", "THREE", "version_factory", - "WRAPPABLE"] +__all__ = ["FIVE", "SPIN2_1CHIP", "THREE", "version_factory"] diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index bdce5c66..e297a8dd 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -20,6 +20,7 @@ get_config_int_or_none, get_config_str_or_none) from spinn_utilities.log import FormatAdapter from spinn_machine.exceptions import SpinnMachineException +from .version_strings import VersionStrings if TYPE_CHECKING: from .abstract_version import AbstractVersion @@ -62,17 +63,13 @@ def version_factory() -> AbstractVersion: from .version_201 import Version201 version = get_config_int_or_none("Machine", "version") - - if version is not None and version < 0: - if version == ANY_VERSION: - options = [THREE, FIVE, SPIN2_1CHIP] - elif version == FOUR_PLUS_CHIPS: - options = [THREE] - elif version in [BIG_MACHINE, MULTIPLE_BOARDS, WRAPPABLE]: - options = [FIVE] - else: + versions = get_config_str_or_none("Machine", "versions") + if versions is not None: + if version is not None: raise SpinnMachineException( - f"Unexpected cfg [Machine]version {version}") + f"Both {version=} and {versions=} found in cfg") + vs = VersionStrings.from_String(versions) + options = vs.options # Use the fact that we run actions against different python versions minor = sys.version_info.minor version = options[minor % len(options)] diff --git a/spinn_machine/version/version_strings.py b/spinn_machine/version/version_strings.py new file mode 100644 index 00000000..a8e16d1c --- /dev/null +++ b/spinn_machine/version/version_strings.py @@ -0,0 +1,68 @@ +# Copyright (c) 2024 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 enum import StrEnum +from typing import List +from spinn_machine.exceptions import SpinnMachineException + + +class VersionStrings(StrEnum): + """ + A description of strings in cfg settings to say test versions + + As additional Versions are added this should allow easy testing of these + as far as possible. + """ + + ANY = ("Any", [3, 5, 201]) + FOUR_PLUS = ("Four plus", [3, 5]) + # To test stuff with more than four chips. + BIG = ("Big", [5]) + # Specifically to test stuff over multiple boards + MULTIPLE_BOARDS = ("Multiple boards", [5]) + # Specifically to test the various wrapping Machine classes + WRAPPABLE = ("Wrappable", [5]) + + def __new__(cls, *args, **kwds): + s = str.__new__(cls) + s._value_ = args[0] + return s + + # ignore the first param since it's already set by __new__ + def __init__(self, _: str, versions: List[int]): + self._versions = versions + + def __str__(self): + return self.value + + @property + def short_str(self): + return self.shorten(self.value) + + # this makes sure that the description is read-only + @property + def options(self) -> List[int]: + return self._versions + + @classmethod + def shorten(cls, value): + return value.lower().replace("_", "").replace("-", "").replace(" ", "") + + @classmethod + def from_String(cls, value): + value_short = cls.shorten(value) + for vs in cls: + if value_short == vs.short_str: + return vs + raise SpinnMachineException(f"No version for {value=}") diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index 807800d5..a20cb737 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -19,14 +19,14 @@ from spinn_machine.config_setup import unittest_setup from spinn_machine.data import MachineDataView from spinn_machine.data.machine_data_writer import MachineDataWriter -from spinn_machine.version import ANY_VERSION, FOUR_PLUS_CHIPS +from spinn_machine.version import FIVE, THREE +from spinn_machine.version.version_strings import VersionStrings class TestSimulatorData(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) def test_setup(self): # What happens before setup depends on the previous test @@ -38,12 +38,12 @@ def test_setup(self): MachineDataView.get_chip_at(1, 1) def test_mock(self): - MachineDataWriter.mock() + set_config("Machine", "version", FIVE) self.assertEqual(3, MachineDataView.get_chip_at(3, 5).x) self.assertEqual(48, MachineDataView.get_machine().n_chips) def test_machine(self): - set_config("Machine", "version", 3) + set_config("Machine", "version", THREE) writer = MachineDataWriter.setup() with self.assertRaises(DataNotYetAvialable): @@ -59,6 +59,7 @@ def test_machine(self): self.assertTrue(MachineDataView.has_machine()) def test_where_is_mocked(self): + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) writer = MachineDataWriter.mock() self.assertEqual( "No Machine created yet", @@ -76,6 +77,7 @@ def test_where_is_mocked(self): MachineDataView.where_is_chip(machine.get_chip_at(2, 8))) def test_where_is_setup(self): + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) writer = MachineDataWriter.setup() self.assertEqual( "No Machine created yet", @@ -98,24 +100,24 @@ def test_where_is_setup(self): def test_mock_any(self): # Should work with any version - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) # check there is a value not what it is machine = MachineDataView.get_machine() self.assertGreaterEqual(machine.n_chips, 1) def test_mock_4_or_more(self): # Should work with any version - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) # check there is a value not what it is machine = MachineDataView.get_machine() self.assertGreaterEqual(machine.n_chips, 4) - def test_mockAny(self): + def test_mock_big(self): # Should work with any version - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.BIG.value) # check there is a value not what it is machine = MachineDataView.get_machine() - self.assertGreaterEqual(machine.n_chips, 1) + self.assertGreaterEqual(machine.n_chips, 48) def test_mock3(self): # Should work with any version diff --git a/unittests/test_chip.py b/unittests/test_chip.py index 0d0fac6f..dd309865 100644 --- a/unittests/test_chip.py +++ b/unittests/test_chip.py @@ -17,14 +17,14 @@ from spinn_utilities.ordered_set import OrderedSet from spinn_machine import Link, Router, Chip from spinn_machine.config_setup import unittest_setup -from spinn_machine.version import ANY_VERSION +from spinn_machine.version.version_strings import VersionStrings class TestingChip(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) self._x = 0 self._y = 1 diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 370f3510..93f1a036 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -20,8 +20,8 @@ from spinn_machine.data.machine_data_writer import MachineDataWriter from spinn_machine.config_setup import unittest_setup from spinn_machine.json_machine import (machine_from_json, to_json_path) -from spinn_machine.version import ( - BIG_MACHINE, FOUR_PLUS_CHIPS, FIVE, MULTIPLE_BOARDS, SPIN2_1CHIP, THREE) +from spinn_machine.version import (FIVE, SPIN2_1CHIP, THREE) +from spinn_machine.version.version_strings import VersionStrings class TestJsonMachine(unittest.TestCase): @@ -69,7 +69,7 @@ def test_json_version_201(self): self.assertEqual(str(vchip), str(jchip)) def test_json_hole(self): - set_config("Machine", "version", BIG_MACHINE) + set_config("Machine", "versions", VersionStrings.BIG.value) set_config("Machine", "down_chips", "3,3") writer = MachineDataWriter.mock() vm = virtual_machine_by_min_size(5, 5) @@ -84,7 +84,7 @@ def test_json_hole(self): self.assertEqual(str(vchip), str(jchip)) def test_exceptions(self): - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) writer = MachineDataWriter.mock() vm = virtual_machine_by_boards(1) writer.set_machine(vm) @@ -104,7 +104,7 @@ def test_exceptions(self): self.assertEqual(vchip10.tag_ids, chip10.tag_ids) def test_monitor_exceptions(self): - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) vm = virtual_machine_by_boards(1) MachineDataWriter.mock().set_machine(vm) for chip in vm.chips: @@ -121,7 +121,7 @@ def test_monitor_exceptions(self): machine_from_json(jpath) def test_ethernet_exceptions(self): - set_config("Machine", "version", MULTIPLE_BOARDS) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) vm = virtual_machine_by_boards(2) MachineDataWriter.mock().set_machine(vm) eth2 = vm.ethernet_connected_chips[1] diff --git a/unittests/test_machine.py b/unittests/test_machine.py index 09998bd4..f8422c46 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -20,9 +20,8 @@ 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.version import ( - ANY_VERSION, BIG_MACHINE, FIVE, FOUR_PLUS_CHIPS, MULTIPLE_BOARDS, - WRAPPABLE) +from spinn_machine.version import FIVE +from spinn_machine.version.version_strings import VersionStrings from spinn_machine.virtual_machine import ( virtual_machine_by_boards, virtual_machine_by_min_size) from spinn_machine.config_setup import unittest_setup @@ -151,7 +150,7 @@ def test_chip_already_exists(self): :rtype: None """ - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) machine = virtual_machine_by_boards(1) with self.assertRaises(SpinnMachineAlreadyExistsException): machine.add_chip(Chip( @@ -165,7 +164,7 @@ def test_machine_get_chip_at(self): :rtype: None """ - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) new_machine = virtual_machine_by_min_size(2, 2) self.assertEqual(1, new_machine.get_chip_at(1, 0).x) self.assertEqual(0, new_machine.get_chip_at(1, 0).y) @@ -179,7 +178,7 @@ def test_machine_big_x(self): :rtype: None """ - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -200,7 +199,7 @@ def test_machine_big_y(self): :rtype: None """ - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -221,7 +220,7 @@ def test_machine_get_chip_at_invalid_location(self): :rtype: None """ - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape @@ -234,7 +233,7 @@ def test_machine_is_chip_at_true(self): :rtype: None """ - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape @@ -247,14 +246,14 @@ def test_machine_is_chip_at_false(self): :rtype: None """ - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape self.assertFalse(new_machine.is_chip_at(width + 2, height // 2)) def test_machine_get_chips_on_board(self): - set_config("Machine", "version", MULTIPLE_BOARDS) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) new_machine = virtual_machine_by_boards(3) version = MachineDataView.get_machine_version() for eth_chip in new_machine._ethernet_connected_chips: @@ -274,7 +273,7 @@ def test_x_y_over_link(self): Notice that the function only does the math not validate the values. :return: """ - set_config("Machine", "version", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.xy_over_link(0, 0, 4), (23, 23)) @@ -303,7 +302,7 @@ def test_get_global_xy(self): Notice that the function only does the math not validate the values. :return: """ - set_config("Machine", "version", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 0)) @@ -322,7 +321,7 @@ def test_get_global_xy(self): self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (25, 4)) def test_no_boot(self): - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -331,7 +330,7 @@ def test_no_boot(self): machine.validate() def test_negative_x(self): - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -342,7 +341,7 @@ def test_negative_x(self): machine.validate() def test_negative_y(self): - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -359,14 +358,14 @@ def _non_ethernet_chip(self, machine): raise SpinnMachineException("No none Ethernet Chip") def test_weird_ethernet1(self): - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) machine = virtual_machine_by_boards(1) self._non_ethernet_chip(machine)._ip_address = "1.2.3.4" with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_x(self): - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) machine = virtual_machine_by_boards(1) width, _ = MachineDataView.get_machine_version().board_shape self._non_ethernet_chip(machine)._nearest_ethernet_x = width + 1 @@ -374,7 +373,7 @@ def test_bad_ethernet_chip_x(self): machine.validate() def test_bad_ethernet_chip_no_chip(self): - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) machine = virtual_machine_by_boards(1) _, height = MachineDataView.get_machine_version().board_shape self._non_ethernet_chip(machine)._nearest_ethernet_x = height + 1 @@ -382,7 +381,7 @@ def test_bad_ethernet_chip_no_chip(self): machine.validate() def test_concentric_xys(self): - set_config("Machine", "version", BIG_MACHINE) + set_config("Machine", "versions", VersionStrings.BIG.value) machine = virtual_machine_by_min_size(5, 5) found = list(machine.concentric_xys(2, (2, 2))) expected = [ @@ -393,10 +392,10 @@ def test_concentric_xys(self): self.assertListEqual(expected, found) def test_too_few_cores(self): - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.ANY.value) machine = virtual_machine_by_boards(1) # Hack to get n_processors return a low number - chip = self._non_ethernet_chip(machine) + chip = next(machine.chips) chip._placable_processors = tuple([1, 2]) with self.assertRaises(SpinnMachineException): machine.validate() diff --git a/unittests/test_using_virtual_machine.py b/unittests/test_using_virtual_machine.py index b1d5c455..841ed4c2 100644 --- a/unittests/test_using_virtual_machine.py +++ b/unittests/test_using_virtual_machine.py @@ -22,8 +22,7 @@ from spinn_machine.exceptions import (SpinnMachineException) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink from spinn_machine.machine_factory import machine_repair -from spinn_machine.version import ( - ANY_VERSION, BIG_MACHINE, FOUR_PLUS_CHIPS, WRAPPABLE) +from spinn_machine.version.version_strings import VersionStrings 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) @@ -62,7 +61,7 @@ def _create_chip(self, x, y): nearest_ethernet_chip[1], None) def test_new_vm_with_max_cores(self): - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) version = MachineDataView.get_machine_version() n_cpus = version.max_cores_per_chip - 5 set_config("Machine", "max_machine_core", n_cpus) @@ -81,7 +80,7 @@ def test_new_vm_with_max_cores(self): len(list(chip.scamp_processors_ids))) def test_iter_chips(self): - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) vm = virtual_machine_by_boards(1) n_chips = MachineDataView.get_machine_version().n_chips_per_board self.assertEqual(n_chips, vm.n_chips) @@ -91,7 +90,7 @@ def test_iter_chips(self): self.assertEqual(n_chips, count) def test_down_chip(self): - set_config("Machine", "version", FOUR_PLUS_CHIPS) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) down_chips = set() down_chips.add((1, 1)) set_config("Machine", "down_chips", "1,1") @@ -110,7 +109,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", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) machine = virtual_machine(16, 28, validate=True) for source in machine.chip_coordinates: for target in machine.chip_coordinates: @@ -124,7 +123,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", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) width = 12 height = 24 machine = virtual_machine(width, height, validate=True) @@ -141,7 +140,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", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) width = 12 height = 16 machine = virtual_machine(width, height, validate=False) @@ -166,7 +165,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", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) width = 16 height = 12 machine = virtual_machine(width, height, validate=False) @@ -191,7 +190,7 @@ def test_vertical_wrap_shortest_path(self): self._check_path(source, target, path, width, height) def test_minimize(self): - set_config("Machine", "version", ANY_VERSION) + set_config("Machine", "versions", VersionStrings.ANY.value) machine = virtual_machine_by_boards(1) for x in range(-3, 3): for y in range(-3, 3): @@ -200,7 +199,7 @@ def test_minimize(self): self.assertEqual(min1, min2) def test_unreachable_incoming_chips(self): - set_config("Machine", "version", BIG_MACHINE) + set_config("Machine", "versions", VersionStrings.BIG.value) machine = virtual_machine_by_min_size(6, 6) # Delete links incoming to 3, 3 @@ -213,7 +212,7 @@ def test_unreachable_incoming_chips(self): self.assertListEqual([(3, 3)], unreachable) def test_unreachable_outgoing_chips(self): - set_config("Machine", "version", BIG_MACHINE) + set_config("Machine", "versions", VersionStrings.BIG.value) machine = virtual_machine_by_min_size(6, 6) # Delete links outgoing from 3, 3 @@ -224,7 +223,7 @@ def test_unreachable_outgoing_chips(self): self.assertListEqual([(3, 3)], unreachable) def test_unreachable_incoming_local_chips(self): - set_config("Machine", "version", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) # Assumes boards of exactly size 8,8 down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) @@ -234,7 +233,7 @@ def test_unreachable_incoming_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_unreachable_outgoing_local_chips(self): - set_config("Machine", "version", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) # Assumes boards of exactly size 8,8 down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) @@ -244,7 +243,7 @@ def test_unreachable_outgoing_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_repair_with_local_orphan(self): - set_config("Machine", "version", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) # Assumes boards of exactly size 8,8 down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) @@ -259,7 +258,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", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) machine = virtual_machine(12, 12) # Assumes boards of exactly size 8,8 # Delete some links between boards @@ -275,7 +274,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", WRAPPABLE) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) machine = virtual_machine(8, 8) # Delete some random links @@ -292,7 +291,7 @@ def test_oneway_link_no_repair(self): self.assertIsNotNone(new_machine) def test_removed_chip_repair(self): - set_config("Machine", "version", BIG_MACHINE) + set_config("Machine", "versions", VersionStrings.BIG.value) machine = virtual_machine_by_boards(1) del machine._chips[(3, 3)] @@ -302,7 +301,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", BIG_MACHINE) + set_config("Machine", "versions", VersionStrings.BIG.value) 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") diff --git a/unittests/version/test_version201.py b/unittests/version/test_version201.py index b36734e8..c30f4638 100644 --- a/unittests/version/test_version201.py +++ b/unittests/version/test_version201.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 The University of Manchester +# Copyright (c) 2024 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. @@ -24,8 +24,7 @@ class TestVersion201(unittest.TestCase): - """ Tests of IPTag - """ + def setUp(self): unittest_setup() diff --git a/unittests/version/test_version3.py b/unittests/version/test_version3.py index 50a7f575..c837392e 100644 --- a/unittests/version/test_version3.py +++ b/unittests/version/test_version3.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 The University of Manchester +# 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. @@ -24,8 +24,7 @@ class TestVersion3(unittest.TestCase): - """ Tests of IPTag - """ + def setUp(self): unittest_setup() diff --git a/unittests/version/test_version5.py b/unittests/version/test_version5.py index 65195811..8faf84ac 100644 --- a/unittests/version/test_version5.py +++ b/unittests/version/test_version5.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 The University of Manchester +# 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. @@ -27,8 +27,7 @@ class TestVersion5(unittest.TestCase): - """ Tests of IPTag - """ + def setUp(self): unittest_setup() diff --git a/unittests/version/test_version_string.py b/unittests/version/test_version_string.py new file mode 100644 index 00000000..31510e88 --- /dev/null +++ b/unittests/version/test_version_string.py @@ -0,0 +1,39 @@ +# Copyright (c) 2024 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 Versions +""" +import unittest +from spinn_machine.config_setup import unittest_setup +from spinn_machine.exceptions import SpinnMachineException +from spinn_machine.version.version_strings import VersionStrings + + +class TestVersionString(unittest.TestCase): + + def setUp(self): + unittest_setup() + + def test_names(self): + vs = VersionStrings.from_String("any") + self.assertEqual(vs.value, "Any") + vs = VersionStrings.from_String("FourPlus") + self.assertEqual(vs.value, "Four plus") + with self.assertRaises(SpinnMachineException): + vs = VersionStrings.from_String("Foo") + + +if __name__ == '__main__': + unittest.main() From e89fa3f022e5de60fbb629f054ca5fe324b17a6d Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 12 Apr 2024 15:27:26 +0100 Subject: [PATCH 50/54] VersionStrings as simple Enum --- spinn_machine/version/version_strings.py | 27 +++++++++--------- unittests/data/test_data.py | 10 +++---- unittests/test_chip.py | 2 +- unittests/test_json_machine.py | 8 +++--- unittests/test_machine.py | 36 ++++++++++++------------ unittests/test_using_virtual_machine.py | 34 +++++++++++----------- unittests/version/test_version_string.py | 4 +-- 7 files changed, 61 insertions(+), 60 deletions(-) diff --git a/spinn_machine/version/version_strings.py b/spinn_machine/version/version_strings.py index a8e16d1c..fc33120c 100644 --- a/spinn_machine/version/version_strings.py +++ b/spinn_machine/version/version_strings.py @@ -12,12 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from enum import StrEnum +from enum import Enum from typing import List from spinn_machine.exceptions import SpinnMachineException -class VersionStrings(StrEnum): +class VersionStrings(Enum): """ A description of strings in cfg settings to say test versions @@ -25,30 +25,31 @@ class VersionStrings(StrEnum): as far as possible. """ - ANY = ("Any", [3, 5, 201]) - FOUR_PLUS = ("Four plus", [3, 5]) + ANY = (1, "Any", [3, 5, 201]) + FOUR_PLUS = (2, "Four plus", [3, 5]) # To test stuff with more than four chips. - BIG = ("Big", [5]) + BIG = (3, "Big", [5]) # Specifically to test stuff over multiple boards - MULTIPLE_BOARDS = ("Multiple boards", [5]) + MULTIPLE_BOARDS = (4, "Multiple boards", [5]) # Specifically to test the various wrapping Machine classes - WRAPPABLE = ("Wrappable", [5]) + WRAPPABLE = (5, "Wrappable", [5]) def __new__(cls, *args, **kwds): - s = str.__new__(cls) - s._value_ = args[0] - return s + vs = object.__new__(cls) + vs._value_ = args[0] + return vs # ignore the first param since it's already set by __new__ - def __init__(self, _: str, versions: List[int]): + def __init__(self, _: str, text: str, versions: List[int]): + self.text = text self._versions = versions def __str__(self): - return self.value + return self.text @property def short_str(self): - return self.shorten(self.value) + return self.shorten(self.text) # this makes sure that the description is read-only @property diff --git a/unittests/data/test_data.py b/unittests/data/test_data.py index a20cb737..d9447d0b 100644 --- a/unittests/data/test_data.py +++ b/unittests/data/test_data.py @@ -59,7 +59,7 @@ def test_machine(self): self.assertTrue(MachineDataView.has_machine()) def test_where_is_mocked(self): - set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.text) writer = MachineDataWriter.mock() self.assertEqual( "No Machine created yet", @@ -77,7 +77,7 @@ def test_where_is_mocked(self): MachineDataView.where_is_chip(machine.get_chip_at(2, 8))) def test_where_is_setup(self): - set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.text) writer = MachineDataWriter.setup() self.assertEqual( "No Machine created yet", @@ -100,21 +100,21 @@ def test_where_is_setup(self): def test_mock_any(self): # Should work with any version - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) # check there is a value not what it is machine = MachineDataView.get_machine() self.assertGreaterEqual(machine.n_chips, 1) def test_mock_4_or_more(self): # Should work with any version - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) # check there is a value not what it is machine = MachineDataView.get_machine() self.assertGreaterEqual(machine.n_chips, 4) def test_mock_big(self): # Should work with any version - set_config("Machine", "versions", VersionStrings.BIG.value) + set_config("Machine", "versions", VersionStrings.BIG.text) # check there is a value not what it is machine = MachineDataView.get_machine() self.assertGreaterEqual(machine.n_chips, 48) diff --git a/unittests/test_chip.py b/unittests/test_chip.py index dd309865..f80749f7 100644 --- a/unittests/test_chip.py +++ b/unittests/test_chip.py @@ -24,7 +24,7 @@ class TestingChip(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) self._x = 0 self._y = 1 diff --git a/unittests/test_json_machine.py b/unittests/test_json_machine.py index 93f1a036..372f0f72 100644 --- a/unittests/test_json_machine.py +++ b/unittests/test_json_machine.py @@ -69,7 +69,7 @@ def test_json_version_201(self): self.assertEqual(str(vchip), str(jchip)) def test_json_hole(self): - set_config("Machine", "versions", VersionStrings.BIG.value) + set_config("Machine", "versions", VersionStrings.BIG.text) set_config("Machine", "down_chips", "3,3") writer = MachineDataWriter.mock() vm = virtual_machine_by_min_size(5, 5) @@ -84,7 +84,7 @@ def test_json_hole(self): self.assertEqual(str(vchip), str(jchip)) def test_exceptions(self): - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) writer = MachineDataWriter.mock() vm = virtual_machine_by_boards(1) writer.set_machine(vm) @@ -104,7 +104,7 @@ def test_exceptions(self): self.assertEqual(vchip10.tag_ids, chip10.tag_ids) def test_monitor_exceptions(self): - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vm = virtual_machine_by_boards(1) MachineDataWriter.mock().set_machine(vm) for chip in vm.chips: @@ -121,7 +121,7 @@ def test_monitor_exceptions(self): machine_from_json(jpath) def test_ethernet_exceptions(self): - set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.text) vm = virtual_machine_by_boards(2) MachineDataWriter.mock().set_machine(vm) eth2 = vm.ethernet_connected_chips[1] diff --git a/unittests/test_machine.py b/unittests/test_machine.py index f8422c46..835c2e8c 100644 --- a/unittests/test_machine.py +++ b/unittests/test_machine.py @@ -150,7 +150,7 @@ def test_chip_already_exists(self): :rtype: None """ - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) machine = virtual_machine_by_boards(1) with self.assertRaises(SpinnMachineAlreadyExistsException): machine.add_chip(Chip( @@ -164,7 +164,7 @@ def test_machine_get_chip_at(self): :rtype: None """ - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) new_machine = virtual_machine_by_min_size(2, 2) self.assertEqual(1, new_machine.get_chip_at(1, 0).x) self.assertEqual(0, new_machine.get_chip_at(1, 0).y) @@ -178,7 +178,7 @@ def test_machine_big_x(self): :rtype: None """ - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -199,7 +199,7 @@ def test_machine_big_y(self): :rtype: None """ - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -220,7 +220,7 @@ def test_machine_get_chip_at_invalid_location(self): :rtype: None """ - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape @@ -233,7 +233,7 @@ def test_machine_is_chip_at_true(self): :rtype: None """ - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape @@ -246,14 +246,14 @@ def test_machine_is_chip_at_false(self): :rtype: None """ - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() new_machine = virtual_machine_by_boards(1) width, height = version.board_shape self.assertFalse(new_machine.is_chip_at(width + 2, height // 2)) def test_machine_get_chips_on_board(self): - set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.value) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.text) new_machine = virtual_machine_by_boards(3) version = MachineDataView.get_machine_version() for eth_chip in new_machine._ethernet_connected_chips: @@ -273,7 +273,7 @@ def test_x_y_over_link(self): Notice that the function only does the math not validate the values. :return: """ - set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.xy_over_link(0, 0, 4), (23, 23)) @@ -302,7 +302,7 @@ def test_get_global_xy(self): Notice that the function only does the math not validate the values. :return: """ - set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) # full wrap around machine = MachineDataView.get_machine_version().create_machine(24, 24) self.assertEqual(machine.get_global_xy(1, 4, 4, 20), (5, 0)) @@ -321,7 +321,7 @@ def test_get_global_xy(self): self.assertEqual(machine.get_global_xy(5, 0, 20, 4), (25, 4)) def test_no_boot(self): - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -330,7 +330,7 @@ def test_no_boot(self): machine.validate() def test_negative_x(self): - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -341,7 +341,7 @@ def test_negative_x(self): machine.validate() def test_negative_y(self): - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() width, height = version.board_shape # create an empty Machine @@ -358,14 +358,14 @@ def _non_ethernet_chip(self, machine): raise SpinnMachineException("No none Ethernet Chip") def test_weird_ethernet1(self): - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) machine = virtual_machine_by_boards(1) self._non_ethernet_chip(machine)._ip_address = "1.2.3.4" with self.assertRaises(SpinnMachineException): machine.validate() def test_bad_ethernet_chip_x(self): - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) machine = virtual_machine_by_boards(1) width, _ = MachineDataView.get_machine_version().board_shape self._non_ethernet_chip(machine)._nearest_ethernet_x = width + 1 @@ -373,7 +373,7 @@ def test_bad_ethernet_chip_x(self): machine.validate() def test_bad_ethernet_chip_no_chip(self): - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) machine = virtual_machine_by_boards(1) _, height = MachineDataView.get_machine_version().board_shape self._non_ethernet_chip(machine)._nearest_ethernet_x = height + 1 @@ -381,7 +381,7 @@ def test_bad_ethernet_chip_no_chip(self): machine.validate() def test_concentric_xys(self): - set_config("Machine", "versions", VersionStrings.BIG.value) + set_config("Machine", "versions", VersionStrings.BIG.text) machine = virtual_machine_by_min_size(5, 5) found = list(machine.concentric_xys(2, (2, 2))) expected = [ @@ -392,7 +392,7 @@ def test_concentric_xys(self): self.assertListEqual(expected, found) def test_too_few_cores(self): - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) machine = virtual_machine_by_boards(1) # Hack to get n_processors return a low number chip = next(machine.chips) diff --git a/unittests/test_using_virtual_machine.py b/unittests/test_using_virtual_machine.py index 841ed4c2..6a0c0111 100644 --- a/unittests/test_using_virtual_machine.py +++ b/unittests/test_using_virtual_machine.py @@ -61,7 +61,7 @@ def _create_chip(self, x, y): nearest_ethernet_chip[1], None) def test_new_vm_with_max_cores(self): - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) version = MachineDataView.get_machine_version() n_cpus = version.max_cores_per_chip - 5 set_config("Machine", "max_machine_core", n_cpus) @@ -80,7 +80,7 @@ def test_new_vm_with_max_cores(self): len(list(chip.scamp_processors_ids))) def test_iter_chips(self): - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) vm = virtual_machine_by_boards(1) n_chips = MachineDataView.get_machine_version().n_chips_per_board self.assertEqual(n_chips, vm.n_chips) @@ -90,7 +90,7 @@ def test_iter_chips(self): self.assertEqual(n_chips, count) def test_down_chip(self): - set_config("Machine", "versions", VersionStrings.FOUR_PLUS.value) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) down_chips = set() down_chips.add((1, 1)) set_config("Machine", "down_chips", "1,1") @@ -109,7 +109,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", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) machine = virtual_machine(16, 28, validate=True) for source in machine.chip_coordinates: for target in machine.chip_coordinates: @@ -123,7 +123,7 @@ def test_nowrap_shortest_path(self): self._check_path(source, target, path, 1000000, 1000000) def test_fullwrap_shortest_path(self): - set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) width = 12 height = 24 machine = virtual_machine(width, height, validate=True) @@ -140,7 +140,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", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) width = 12 height = 16 machine = virtual_machine(width, height, validate=False) @@ -165,7 +165,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", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) width = 16 height = 12 machine = virtual_machine(width, height, validate=False) @@ -190,7 +190,7 @@ def test_vertical_wrap_shortest_path(self): self._check_path(source, target, path, width, height) def test_minimize(self): - set_config("Machine", "versions", VersionStrings.ANY.value) + set_config("Machine", "versions", VersionStrings.ANY.text) machine = virtual_machine_by_boards(1) for x in range(-3, 3): for y in range(-3, 3): @@ -199,7 +199,7 @@ def test_minimize(self): self.assertEqual(min1, min2) def test_unreachable_incoming_chips(self): - set_config("Machine", "versions", VersionStrings.BIG.value) + set_config("Machine", "versions", VersionStrings.BIG.text) machine = virtual_machine_by_min_size(6, 6) # Delete links incoming to 3, 3 @@ -212,7 +212,7 @@ def test_unreachable_incoming_chips(self): self.assertListEqual([(3, 3)], unreachable) def test_unreachable_outgoing_chips(self): - set_config("Machine", "versions", VersionStrings.BIG.value) + set_config("Machine", "versions", VersionStrings.BIG.text) machine = virtual_machine_by_min_size(6, 6) # Delete links outgoing from 3, 3 @@ -223,7 +223,7 @@ def test_unreachable_outgoing_chips(self): self.assertListEqual([(3, 3)], unreachable) def test_unreachable_incoming_local_chips(self): - set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) # Assumes boards of exactly size 8,8 down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) @@ -233,7 +233,7 @@ def test_unreachable_incoming_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_unreachable_outgoing_local_chips(self): - set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) # Assumes boards of exactly size 8,8 down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) @@ -243,7 +243,7 @@ def test_unreachable_outgoing_local_chips(self): self.assertListEqual([(8, 7)], unreachable) def test_repair_with_local_orphan(self): - set_config("Machine", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) # Assumes boards of exactly size 8,8 down_chips = [(8, 6), (9, 7), (9, 8)] down_str = ":".join([f"{x},{y}" for x, y in down_chips]) @@ -258,7 +258,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", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) machine = virtual_machine(12, 12) # Assumes boards of exactly size 8,8 # Delete some links between boards @@ -274,7 +274,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", "versions", VersionStrings.WRAPPABLE.value) + set_config("Machine", "versions", VersionStrings.WRAPPABLE.text) machine = virtual_machine(8, 8) # Delete some random links @@ -291,7 +291,7 @@ def test_oneway_link_no_repair(self): self.assertIsNotNone(new_machine) def test_removed_chip_repair(self): - set_config("Machine", "versions", VersionStrings.BIG.value) + set_config("Machine", "versions", VersionStrings.BIG.text) machine = virtual_machine_by_boards(1) del machine._chips[(3, 3)] @@ -301,7 +301,7 @@ def test_removed_chip_repair(self): self.assertFalse(new_machine.is_link_at(2, 2, 1)) def test_ignores(self): - set_config("Machine", "versions", VersionStrings.BIG.value) + set_config("Machine", "versions", VersionStrings.BIG.text) 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") diff --git a/unittests/version/test_version_string.py b/unittests/version/test_version_string.py index 31510e88..67abf459 100644 --- a/unittests/version/test_version_string.py +++ b/unittests/version/test_version_string.py @@ -28,9 +28,9 @@ def setUp(self): def test_names(self): vs = VersionStrings.from_String("any") - self.assertEqual(vs.value, "Any") + self.assertEqual(vs.text, "Any") vs = VersionStrings.from_String("FourPlus") - self.assertEqual(vs.value, "Four plus") + self.assertEqual(vs.text, "Four plus") with self.assertRaises(SpinnMachineException): vs = VersionStrings.from_String("Foo") From f4030e7ec727102e51eac320f9516f4d78313213 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 12 Apr 2024 15:57:55 +0100 Subject: [PATCH 51/54] flake8 --- spinn_machine/version/version_factory.py | 2 +- spinn_machine/version/version_strings.py | 32 +++++++++++++++++++++--- unittests/version/test_version_string.py | 6 ++--- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index e297a8dd..d205c2a4 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -68,7 +68,7 @@ def version_factory() -> AbstractVersion: if version is not None: raise SpinnMachineException( f"Both {version=} and {versions=} found in cfg") - vs = VersionStrings.from_String(versions) + vs = VersionStrings.from_string(versions) options = vs.options # Use the fact that we run actions against different python versions minor = sys.version_info.minor diff --git a/spinn_machine/version/version_strings.py b/spinn_machine/version/version_strings.py index fc33120c..43930aeb 100644 --- a/spinn_machine/version/version_strings.py +++ b/spinn_machine/version/version_strings.py @@ -48,20 +48,46 @@ def __str__(self): return self.text @property - def short_str(self): + def short_str(self) -> str: + """ + The text but in a shortened version + + This makes the text lower case and removes some special characters + + :rtype: str + """ return self.shorten(self.text) # this makes sure that the description is read-only @property def options(self) -> List[int]: + """ + The list of the versions covered by this string + + This list can grow as new versions are added + + :rtype: list(int) + """ return self._versions @classmethod - def shorten(cls, value): + def shorten(cls, value: str) -> str: + """ + Makes the String lower case and removes some special characters + + :param str value: + :rtype: str + """ return value.lower().replace("_", "").replace("-", "").replace(" ", "") @classmethod - def from_String(cls, value): + def from_string(cls, value: str) -> "VersionStrings": + """ + Gets a VersionString object from a String + + :param str value: + :rtype: VersionStrings + """ value_short = cls.shorten(value) for vs in cls: if value_short == vs.short_str: diff --git a/unittests/version/test_version_string.py b/unittests/version/test_version_string.py index 67abf459..eeda4db1 100644 --- a/unittests/version/test_version_string.py +++ b/unittests/version/test_version_string.py @@ -27,12 +27,12 @@ def setUp(self): unittest_setup() def test_names(self): - vs = VersionStrings.from_String("any") + vs = VersionStrings.from_string("any") self.assertEqual(vs.text, "Any") - vs = VersionStrings.from_String("FourPlus") + vs = VersionStrings.from_string("FourPlus") self.assertEqual(vs.text, "Four plus") with self.assertRaises(SpinnMachineException): - vs = VersionStrings.from_String("Foo") + vs = VersionStrings.from_string("Foo") if __name__ == '__main__': From 7e719aa406733222b72dd7b90535d8b12da811fd Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Fri, 12 Apr 2024 16:32:42 +0100 Subject: [PATCH 52/54] multiple values moved to VersionString --- spinn_machine/version/version_factory.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/spinn_machine/version/version_factory.py b/spinn_machine/version/version_factory.py index d205c2a4..fd3dc798 100644 --- a/spinn_machine/version/version_factory.py +++ b/spinn_machine/version/version_factory.py @@ -32,22 +32,6 @@ # New value subject to change SPIN2_1CHIP = 201 -# Flaks to test multiple versions including future ones -ANY_VERSION = -1 - -FOUR_PLUS_CHIPS = -2 - -# A Machine which support multiple boards -# Size of boards does not matter -MULTIPLE_BOARDS = -3 - -# A Machine with at least 8 * 8 including ones typical on a Version 5 board -BIG_MACHINE = -4 - -# A Machine with multiple boards that could wrap -# Will have hard coded assumption of board size 8 * 8 -WRAPPABLE = -5 - def version_factory() -> AbstractVersion: """ From 605cc1a38ccce18a929baaf6806c0e5f9bb8f74d Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 16 Apr 2024 08:06:40 +0100 Subject: [PATCH 53/54] fix merge --- spinn_machine/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spinn_machine/__init__.py b/spinn_machine/__init__.py index d61cdf8e..b0d624b0 100644 --- a/spinn_machine/__init__.py +++ b/spinn_machine/__init__.py @@ -90,4 +90,5 @@ __all__ = ["Chip", "CoreSubset", "CoreSubsets", "FrozenCoreSubsets", "Link", "Machine", "MulticastRoutingEntry", - "Router", "SpiNNakerTriadGeometry", "virtual_machine"] + "Router", "RoutingEntry", "SpiNNakerTriadGeometry", + "virtual_machine"] From cdec11090a4a46769732493be64bd9c1e4123fe2 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 17 Apr 2024 07:05:23 +0100 Subject: [PATCH 54/54] fix add_monitor_core to all_cores --- spinn_machine/data/machine_data_writer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spinn_machine/data/machine_data_writer.py b/spinn_machine/data/machine_data_writer.py index f5aec30a..080111e1 100644 --- a/spinn_machine/data/machine_data_writer.py +++ b/spinn_machine/data/machine_data_writer.py @@ -105,7 +105,7 @@ def set_machine_generator(self, machine_generator: Callable[[], None]): raise TypeError("machine_generator must be callable") self.__data._machine_generator = machine_generator - def add_monitor_core(self, all_cores: bool): + def add_monitor_core(self, all_chips: bool): """ Accepts a simple of the monitor cores to be added. @@ -114,12 +114,12 @@ def add_monitor_core(self, all_cores: bool): Only affect is to change the numbers reported by the get_all/ethernet_monitor methods. - :param bool all_cores: - If True assumes that this Vertex will be placed on all cores + :param bool all_chips: + If True assumes that this Vertex will be placed on all chips including Ethernet ones. If False assumes that this Vertex type will only be placed on Ethernet Vertices """ self.__data._ethernet_monitor_cores += 1 - if all_cores: + if all_chips: self.__data._all_monitor_cores += 1