diff --git a/fec_integration_tests/file_convertor_tests/test_write_json_machine.py b/fec_integration_tests/file_convertor_tests/test_write_json_machine.py index d9b8e07943..43b789d0cb 100644 --- a/fec_integration_tests/file_convertor_tests/test_write_json_machine.py +++ b/fec_integration_tests/file_convertor_tests/test_write_json_machine.py @@ -39,7 +39,6 @@ class TestWriteJson(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) class_file = sys.modules[self.__module__].__file__ path = os.path.dirname(os.path.abspath(class_file)) os.chdir(path) diff --git a/fec_integration_tests/interface/interface_functions/test_database_interface.py b/fec_integration_tests/interface/interface_functions/test_database_interface.py index 1a4fce795a..237f892315 100644 --- a/fec_integration_tests/interface/interface_functions/test_database_interface.py +++ b/fec_integration_tests/interface/interface_functions/test_database_interface.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from spinn_utilities.config_holder import set_config +from spinn_machine.version.version_strings import VersionStrings from spinn_machine.tags.iptag import IPTag from pacman.model.graphs.application import ApplicationVertex, ApplicationEdge from pacman.model.graphs.machine import SimpleMachineVertex @@ -23,6 +24,7 @@ from pacman.model.tags.tags import Tags from pacman.model.partitioner_splitters import AbstractSplitterCommon from pacman.model.graphs.common.slice import Slice +from spinn_front_end_common.data import FecDataView from spinn_front_end_common.data.fec_data_writer import FecDataWriter from spinn_front_end_common.interface.interface_functions import ( database_interface) @@ -90,21 +92,31 @@ def _add_rinfo( partition_id, m_vertex, i)) -def _place_vertices(app_vertex, placements, chips): - chip_iter = iter(chips) - x, y = next(chip_iter) - to_go = 14 - for m_vertex in app_vertex.machine_vertices: - if to_go == 0: - x, y = next(chip_iter) - to_go = 14 - placements.add_placement(Placement(m_vertex, x, y, 16 - to_go)) - to_go -= 1 +def _place_vertices(app_vertexes, placements): + machine = FecDataView.get_machine() + chips = machine.chips + chip = next(chips) + x, y = chip + placable_processors_ids = chip.placable_processors_ids + i = 0 + for app_vertex in app_vertexes: + for m_vertex in app_vertex.machine_vertices: + while placements.is_processor_occupied( + x, y, placable_processors_ids[i]): + i += 1 + if i >= len(placable_processors_ids): + chip = next(chips) + x, y = chip + placable_processors_ids = chip.placable_processors_ids + i = 0 + placements.add_placement( + Placement(m_vertex, x, y, placable_processors_ids[i])) + return placements def test_database_interface(): unittest_setup() - set_config("Machine", "version", 5) + set_config("Machine", "versions", VersionStrings.ANY.text) set_config("Database", "create_database", "True") set_config("Database", "create_routing_info_to_neuron_id_mapping", "True") @@ -125,8 +137,8 @@ def test_database_interface(): writer.add_edge(ApplicationEdge(app_vertex_1, lpg_vertex), "Test") lpg_vertex.splitter.create_sys_vertices(placements) - _place_vertices(app_vertex_1, placements, [(0, 0)]) - _place_vertices(app_vertex_2, placements, [(0, 1), (1, 1)]) + + _place_vertices([app_vertex_1, app_vertex_2], placements) writer.set_placements(placements) lpg_vertex.splitter.get_source_specific_in_coming_vertices( diff --git a/fec_integration_tests/interface/interface_functions/test_front_end_common_insert_lpgs.py b/fec_integration_tests/interface/interface_functions/test_front_end_common_insert_lpgs.py index 5229dd2650..d6ab0798cc 100644 --- a/fec_integration_tests/interface/interface_functions/test_front_end_common_insert_lpgs.py +++ b/fec_integration_tests/interface/interface_functions/test_front_end_common_insert_lpgs.py @@ -14,7 +14,8 @@ import unittest from spinn_utilities.config_holder import set_config -from spinn_machine import virtual_machine +from spinn_machine.version.version_strings import VersionStrings +from spinn_machine.virtual_machine import virtual_machine_by_boards from spinnman.messages.eieio import EIEIOType from pacman.model.graphs.machine import MachineVertex from pacman.model.placements import Placements @@ -39,11 +40,11 @@ class TestInsertLPGs(unittest.TestCase): """ def setUp(self): unittest_setup() - set_config("Machine", "version", 5) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.text) def test_that_3_lpgs_are_generated_on_3_board_app_graph(self): writer = FecDataWriter.mock() - writer.set_machine(virtual_machine(width=12, height=12)) + writer.set_machine(virtual_machine_by_boards(3)) default_params = { 'use_prefix': False, diff --git a/spinn_front_end_common/data/fec_data_view.py b/spinn_front_end_common/data/fec_data_view.py index 508757ae57..7e97f9690d 100644 --- a/spinn_front_end_common/data/fec_data_view.py +++ b/spinn_front_end_common/data/fec_data_view.py @@ -629,7 +629,7 @@ def get_n_chips_needed(cls) -> int: return cls.__fec_data._n_chips_required if cls.__fec_data._n_chips_in_graph: return cls.__fec_data._n_chips_in_graph - raise cls._exception("n_chips_requiredr") + raise cls._exception("n_chips_required") @classmethod def has_n_chips_needed(cls) -> bool: diff --git a/spinn_front_end_common/interface/interface_functions/host_bit_field_router_compressor.py b/spinn_front_end_common/interface/interface_functions/host_bit_field_router_compressor.py index 6796584794..7cebbf7f51 100644 --- a/spinn_front_end_common/interface/interface_functions/host_bit_field_router_compressor.py +++ b/spinn_front_end_common/interface/interface_functions/host_bit_field_router_compressor.py @@ -580,7 +580,7 @@ def _run_algorithm( the set of router tables that together need to be merged into 1 router table :return: compressor router table - :rtype: list(MulticastRoutingEntry) + :rtype: list(RTEntry) :throws MinimisationFailedError: if it fails to compress to the correct length. """ diff --git a/spinn_front_end_common/interface/interface_functions/virtual_machine_generator.py b/spinn_front_end_common/interface/interface_functions/virtual_machine_generator.py index 8a3deca11a..40949507cc 100644 --- a/spinn_front_end_common/interface/interface_functions/virtual_machine_generator.py +++ b/spinn_front_end_common/interface/interface_functions/virtual_machine_generator.py @@ -14,9 +14,14 @@ import logging from spinn_utilities.config_holder import ( - get_config_int, get_config_str_or_none, is_config_none) + get_config_int, get_config_int_or_none, get_config_str_or_none, + is_config_none) from spinn_utilities.log import FormatAdapter -from spinn_machine import json_machine, virtual_machine, Machine +from spinn_machine import json_machine, Machine +from spinn_machine.virtual_machine import ( + virtual_machine, virtual_machine_by_boards, virtual_machine_by_chips) +from spinn_front_end_common.data import FecDataView +from spinn_front_end_common.utilities.exceptions import ConfigurationException logger = FormatAdapter(logging.getLogger(__name__)) @@ -28,15 +33,32 @@ def virtual_machine_generator() -> Machine: :rtype: ~spinn_machine.Machine :raises Exception: If given bad arguments """ - height = get_config_int("Machine", "height") - width = get_config_int("Machine", "width") json_path = get_config_str_or_none("Machine", "json_path") if json_path is None: - assert width is not None and height is not None - machine = virtual_machine(width=width, height=height, validate=True) + if is_config_none("Machine", "width") or \ + is_config_none("Machine", "height"): + if FecDataView.has_n_boards_required(): + n_boards = FecDataView.get_n_boards_required() + machine = virtual_machine_by_boards((n_boards)) + elif FecDataView.has_n_chips_needed(): + n_chips = FecDataView.get_n_chips_needed() + machine = virtual_machine_by_chips((n_chips)) + else: + height = get_config_int_or_none("Machine", "height") + width = get_config_int_or_none("Machine", "width") + raise ConfigurationException( + "Unable to create a VirtualMachine at this time unless " + "both width and heigth are specified in the cfg found " + f"found {width=} {height=}") + else: + height = get_config_int("Machine", "height") + width = get_config_int("Machine", "width") + machine = virtual_machine( + width=width, height=height, validate=True) else: - if (height is not None or width is not None or + if (not is_config_none("Machine", "width") or + not is_config_none("Machine", "height") or not is_config_none("Machine", "down_chips") or not is_config_none("Machine", "down_cores") or not is_config_none("Machine", "down_links")): diff --git a/unittests/data/test_simulator_data.py b/unittests/data/test_simulator_data.py index 88891006de..c663d62c28 100644 --- a/unittests/data/test_simulator_data.py +++ b/unittests/data/test_simulator_data.py @@ -21,6 +21,7 @@ from spinn_utilities.data.utils_data_writer import _UtilsDataModel from spinn_utilities.exceptions import ( DataNotYetAvialable, NotSetupException) +from spinn_machine.version.version_strings import VersionStrings from spinnman.messages.scp.enums.signal import Signal from spinn_utilities.socket_address import SocketAddress from spinnman.model import ExecutableTargets @@ -574,7 +575,7 @@ def test_executable_targets(self): def test_gatherer_map(self): writer = FecDataWriter.mock() - set_config("Machine", "version", 5) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) with self.assertRaises(DataNotYetAvialable): FecDataView.get_gatherer_by_xy(0, 0) with self.assertRaises(DataNotYetAvialable): @@ -623,7 +624,7 @@ def test_gatherer_map(self): def test_monitor_map(self): writer = FecDataWriter.mock() - set_config("Machine", "version", 5) + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) self.assertFalse(FecDataView.has_monitors()) with self.assertRaises(DataNotYetAvialable): FecDataView.get_monitor_by_xy(0, 0) diff --git a/unittests/interface/buffer_management/test_buffered_database.py b/unittests/interface/buffer_management/test_buffered_database.py index 1c58f1b533..63eaa402b4 100644 --- a/unittests/interface/buffer_management/test_buffered_database.py +++ b/unittests/interface/buffer_management/test_buffered_database.py @@ -15,6 +15,7 @@ import unittest import os from spinn_utilities.config_holder import set_config +from spinn_machine.version.version_strings import VersionStrings from pacman.model.graphs.machine import SimpleMachineVertex from pacman.model.placements import Placement, Placements from spinn_front_end_common.data.fec_data_writer import FecDataWriter @@ -27,9 +28,9 @@ class TestBufferedDatabase(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) def test_use_database(self): + set_config("Machine", "versions", VersionStrings.ANY.text) f = BufferDatabase.default_database_file() self.assertFalse(os.path.isfile(f), "no existing DB at first") @@ -51,6 +52,7 @@ def test_use_database(self): self.assertTrue(os.path.isfile(f), "DB still exists") def test_placements(self): + set_config("Machine", "versions", VersionStrings.BIG.text) writer = FecDataWriter.mock() info = Placements([]) p1 = Placement(SimpleMachineVertex(None, label="V1"), 1, 2, 3) diff --git a/unittests/interface/ds/test_ds.py b/unittests/interface/ds/test_ds.py index 647fca73c9..6c8b0d2a61 100644 --- a/unittests/interface/ds/test_ds.py +++ b/unittests/interface/ds/test_ds.py @@ -17,7 +17,8 @@ from spinn_utilities.config_holder import set_config from spinn_utilities.overrides import overrides from spinn_machine import Chip, Router -from spinn_machine.virtual_machine import virtual_machine +from spinn_machine.version.version_strings import VersionStrings +from spinn_machine.virtual_machine import virtual_machine_by_min_size from spinnman.model.enums import ExecutableType from pacman.model.graphs.machine import SimpleMachineVertex from spinn_front_end_common.abstract_models import AbstractHasAssociatedBinary @@ -52,9 +53,9 @@ class TestDataSpecification(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) def test_init(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex1 = _TestVertexWithBinary( "off_board__system", ExecutableType.SYSTEM) with DsSqlliteDatabase() as db: @@ -62,19 +63,24 @@ def test_init(self): DataSpecificationReloader(0, 1, 2, db) def test_none_ds_vertex(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex = SimpleMachineVertex(0) with DsSqlliteDatabase() as db: with self.assertRaises(AttributeError): DataSpecificationGenerator(0, 1, 2, vertex, db) def test_bad_x_y_ds_vertex(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex = _TestVertexWithBinary( "off_board__system", ExecutableType.SYSTEM) + width, height = FecDataView.get_machine_version().board_shape with DsSqlliteDatabase() as db: with self.assertRaises(KeyError): - DataSpecificationGenerator(10, 10, 2, vertex, db) + # x, y to high + DataSpecificationGenerator(width, height, 2, vertex, db) def test_repeat_x_y_ds_vertex(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex1 = _TestVertexWithBinary( "v1", ExecutableType.SYSTEM) vertex2 = _TestVertexWithBinary( @@ -85,7 +91,9 @@ def test_repeat_x_y_ds_vertex(self): DataSpecificationGenerator(0, 1, 2, vertex2, db) def test_core_infos(self): - FecDataWriter.mock().set_machine(virtual_machine(16, 16)) + set_config("Machine", "versions", VersionStrings.MULTIPLE_BOARDS.text) + writer = FecDataWriter.mock() + writer.set_machine(virtual_machine_by_min_size(9, 9)) with DsSqlliteDatabase() as db: self.assertEqual([], db.get_core_infos(True)) s1 = _TestVertexWithBinary("S1", ExecutableType.SYSTEM) @@ -107,16 +115,19 @@ def test_core_infos(self): self.assertEqual(app_infos, db.get_core_infos(False)) def test_bad_ethernet(self): + set_config("Machine", "versions", VersionStrings.ANY.text) router = Router([], 123) - bad = Chip(10, 10, 15, router, 100, 8, 8) + width, height = FecDataView.get_machine_version().board_shape + bad = Chip(width, height, 15, router, 100, 8, 8) FecDataView.get_machine().add_chip(bad) vertex = _TestVertexWithBinary( "bad", ExecutableType.SYSTEM) with DsSqlliteDatabase() as db: with self.assertRaises(IntegrityError): - DataSpecificationGenerator(10, 10, 2, vertex, db) + DataSpecificationGenerator(width, height, 2, vertex, db) def test_reserve_memory_region(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex = _TestVertexWithBinary( "binary", ExecutableType.SYSTEM) with DsSqlliteDatabase() as db: @@ -158,10 +169,11 @@ def test_reserve_memory_region(self): self.assertEqual(0, db.get_total_regions_size(0, 1, 3)) def test_switch_write_focus(self): + set_config("Machine", "versions", VersionStrings.ANY.text) vertex = _TestVertexWithBinary( "binary", ExecutableType.SYSTEM) with DsSqlliteDatabase() as db: - dsg = DataSpecificationGenerator(0, 1, 2, vertex, db) + dsg = DataSpecificationGenerator(0, 0, 2, vertex, db) dsg.reserve_memory_region(10, 123456, "test_region") dsg.switch_write_focus(10) # check internal fields used later are correct @@ -171,6 +183,7 @@ def test_switch_write_focus(self): dsg.switch_write_focus(8) def test_pointers(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) # You can use a reference before defining it vertex = _TestVertexWithBinary( "binary1", ExecutableType.SYSTEM) @@ -236,6 +249,7 @@ def test_pointers(self): db.get_region_pointer(1, 2, 3, 9) def test_write(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex = _TestVertexWithBinary( "binary", ExecutableType.SYSTEM) @@ -288,6 +302,7 @@ def test_write(self): 0, 1, 4, 5, bytearray(b'\x0c\x00\x00\x00'), "test") def test_ds_cores(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex = _TestVertexWithBinary( "binary", ExecutableType.SYSTEM) with DsSqlliteDatabase() as db: @@ -296,15 +311,16 @@ def test_ds_cores(self): DataSpecificationGenerator(0, 1, 3, vertex, db) DataSpecificationGenerator(0, 1, 4, vertex, db) - DataSpecificationGenerator(0, 2, 3, vertex, db) + DataSpecificationGenerator(1, 0, 3, vertex, db) self.assertEqual(3, db.get_n_ds_cores()) cores = list(db.get_ds_cores()) self.assertEqual(3, len(cores)) self.assertIn((0, 1, 3), cores) self.assertIn((0, 1, 4), cores) - self.assertIn((0, 2, 3), cores) + self.assertIn((1, 0, 3), cores) def test_memory_to_write(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) vertex = _TestVertexWithBinary( "binary", ExecutableType.SYSTEM) with DsSqlliteDatabase() as db: diff --git a/unittests/interface/interface_functions/test_front_end_common_dsg_region_reloader.py b/unittests/interface/interface_functions/test_front_end_common_dsg_region_reloader.py index 44786c28db..749e7479d4 100644 --- a/unittests/interface/interface_functions/test_front_end_common_dsg_region_reloader.py +++ b/unittests/interface/interface_functions/test_front_end_common_dsg_region_reloader.py @@ -17,6 +17,7 @@ from typing import BinaryIO, Optional, Sequence, Tuple, Union from spinn_utilities.config_holder import set_config from spinn_utilities.overrides import overrides +from spinn_machine.version.version_strings import VersionStrings from spinnman.model.enums import ExecutableType from pacman.model.placements import Placements, Placement from spinn_front_end_common.abstract_models import ( @@ -129,7 +130,7 @@ class TestFrontEndCommonDSGRegionReloader(unittest.TestCase): def setUp(self): unittest_setup() - set_config("Machine", "version", 5) + set_config("Machine", "versions", VersionStrings.ANY.text) def test_with_good_sizes(self): """ Test that an application vertex's data is rewritten correctly diff --git a/unittests/interface/interface_functions/test_load_data_specification.py b/unittests/interface/interface_functions/test_load_data_specification.py index ae889dfd8f..9a46ab88db 100644 --- a/unittests/interface/interface_functions/test_load_data_specification.py +++ b/unittests/interface/interface_functions/test_load_data_specification.py @@ -18,6 +18,7 @@ import unittest from spinn_utilities.config_holder import set_config from spinn_utilities.overrides import overrides +from spinn_machine.version.version_strings import VersionStrings from spinnman.transceiver.version5transceiver import Version5Transceiver from spinnman.model.enums import ExecutableType from pacman.model.graphs.machine import SimpleMachineVertex @@ -93,9 +94,9 @@ class TestLoadDataSpecification(unittest.TestCase): def setUp(self): unittest_setup() set_config("Machine", "enable_advanced_monitor_support", "False") - set_config("Machine", "version", 5) def test_call(self): + set_config("Machine", "versions", VersionStrings.ANY.text) writer = FecDataWriter.mock() transceiver = _MockTransceiver() writer.set_transceiver(transceiver) @@ -162,6 +163,7 @@ def test_call(self): header_and_table_size + 16) def test_multi_spec_with_references(self): + set_config("Machine", "versions", VersionStrings.ANY.text) writer = FecDataWriter.mock() transceiver = _MockTransceiver() writer.set_transceiver(transceiver) @@ -235,6 +237,7 @@ def test_multi_spec_with_references(self): self.assertEqual(header_data[2][2 * 3], header_data[1][2 * 3]) def test_multispec_with_reference_error(self): + set_config("Machine", "versions", VersionStrings.ANY.text) writer = FecDataWriter.mock() transceiver = _MockTransceiver() writer.set_transceiver(transceiver) @@ -262,6 +265,7 @@ def test_multispec_with_reference_error(self): load_application_data_specs() def test_multispec_with_double_reference(self): + set_config("Machine", "versions", VersionStrings.ANY.text) writer = FecDataWriter.mock() transceiver = _MockTransceiver() writer.set_transceiver(transceiver) @@ -275,6 +279,7 @@ def test_multispec_with_double_reference(self): spec.reserve_memory_region(1, 12, reference=1) def test_multispec_with_wrong_chip_reference(self): + set_config("Machine", "versions", VersionStrings.FOUR_PLUS.text) writer = FecDataWriter.mock() transceiver = _MockTransceiver() writer.set_transceiver(transceiver) diff --git a/unittests/interface/interface_functions/test_virtual_machine_generator.py b/unittests/interface/interface_functions/test_virtual_machine_generator.py new file mode 100644 index 0000000000..4790eea642 --- /dev/null +++ b/unittests/interface/interface_functions/test_virtual_machine_generator.py @@ -0,0 +1,62 @@ +# 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. + +import unittest +from spinn_utilities.config_holder import set_config +from spinn_front_end_common.data.fec_data_writer import FecDataWriter +from spinn_front_end_common.interface.config_setup import unittest_setup +from spinn_front_end_common.interface.interface_functions import ( + virtual_machine_generator) +from spinn_front_end_common.utilities.exceptions import ConfigurationException + + +class TestVirtualMachineGenerator(unittest.TestCase): + + def setUp(self): + unittest_setup() + + def test_only_width(self): + set_config("Machine", "version", 5) + set_config("Machine", "virtual_board", "True") + set_config("Machine", "width", "8") + with self.assertRaises(ConfigurationException): + virtual_machine_generator() + + def test_by_boards(self): + set_config("Machine", "version", 5) + set_config("Machine", "virtual_board", "True") + # Called by sim.setup + FecDataWriter.mock().set_n_required(3, None) + machine = virtual_machine_generator() + self.assertEqual(3, len(machine.ethernet_connected_chips)) + + def test_by_set_chips(self): + set_config("Machine", "version", 5) + set_config("Machine", "virtual_board", "True") + # Called by sim.setup + FecDataWriter.mock().set_n_chips_in_graph(100) + machine = virtual_machine_generator() + self.assertEqual(3, len(machine.ethernet_connected_chips)) + + def test_by_chips(self): + set_config("Machine", "version", 5) + set_config("Machine", "virtual_board", "True") + # Called after partitioning + FecDataWriter.mock().set_n_chips_in_graph(1) + machine = virtual_machine_generator() + self.assertEqual(1, len(machine.ethernet_connected_chips)) + + +if __name__ == "__main__": + unittest.main()