Skip to content

Commit

Permalink
merged in master
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian-B committed Apr 26, 2024
2 parents f3b760f + ffead2a commit a6d1e99
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 86 deletions.
77 changes: 14 additions & 63 deletions spinn_machine/chip.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@
# 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 (Collection, Iterable, Iterator, Optional, Tuple)
from typing import (Iterable, Iterator, Optional, Tuple)

from spinn_utilities.ordered_set import OrderedSet
from spinn_utilities.typing.coords import XY

from spinn_machine.data import MachineDataView
from .router import Router


Expand All @@ -29,31 +28,31 @@ class Chip(XY):
# tag 0 is reserved for stuff like IO STD
_IPTAG_IDS = OrderedSet(range(1, 8))

def __new__(cls, x: int, y: int, n_processors: int, router: Router,
def __new__(cls, x: int, y: int, scamp_processors: Iterable[int],
placable_processors: Iterable[int], router: Router,
sdram: int, nearest_ethernet_x: int, nearest_ethernet_y: int,
ip_address: Optional[str] = None,
tag_ids: Optional[Iterable[int]] = None,
down_cores: Optional[Collection[int]] = None,
parent_link: Optional[int] = None,
v_to_p_map: Optional[bytes] = None):
parent_link: Optional[int] = None):
return tuple.__new__(cls, (x, y))

# pylint: disable=too-many-arguments, wrong-spelling-in-docstring
# pylint: disable=unused-argument
def __init__(self, x: int, y: int, n_processors: int, router: Router,
def __init__(self, x: int, y: int, scamp_processors: Iterable[int],
placable_processors: Iterable[int], router: Router,
sdram: int, nearest_ethernet_x: int, nearest_ethernet_y: int,
ip_address: Optional[str] = None,
tag_ids: Optional[Iterable[int]] = None,
down_cores: Optional[Collection[int]] = None,
parent_link: Optional[int] = None,
v_to_p_map: Optional[bytes] = None):
parent_link: Optional[int] = None):
"""
:param int x: the x-coordinate of the chip's position in the
two-dimensional grid of chips
:param int y: the y-coordinate of the chip's position in the
two-dimensional grid of chips
:param int n_processors:
the number of processors including monitor processors.
:param iterable(int) scamp_processors:
the ids of scamp processors
:param iterable(int) placable_processors:
the ids of processors excluding scamp processors.
:param ~spinn_machine.Router router: a router for the chip
:param int sdram: an SDRAM for the chip
:param ip_address:
Expand All @@ -67,8 +66,6 @@ def __init__(self, x: int, y: int, n_processors: int, router: Router,
:type nearest_ethernet_x: int or None
:param nearest_ethernet_y: the nearest Ethernet y coordinate
:type nearest_ethernet_y: int or None
:param down_cores: Ids of cores that are down for this Chip
:type down_cores: iterable(int) or None
:param parent_link: The link down which the parent chips is found in
the tree of chips towards the root (boot) chip
:type parent_link: int or None
Expand All @@ -80,10 +77,8 @@ def __init__(self, x: int, y: int, n_processors: int, router: Router,
``processor_id``
"""
# X and Y set by new
self._scamp_processors = tuple(range(
MachineDataView.get_machine_version().n_scamp_cores))
self._placable_processors = self.__generate_processors(
n_processors, down_cores)
self._scamp_processors = tuple(scamp_processors)
self._placable_processors = tuple(placable_processors)
self._router = router
self._sdram = sdram
self._ip_address = ip_address
Expand All @@ -96,24 +91,6 @@ def __init__(self, x: int, y: int, n_processors: int, router: Router,
self._nearest_ethernet_x = nearest_ethernet_x
self._nearest_ethernet_y = nearest_ethernet_y
self._parent_link = parent_link
self._v_to_p_map = v_to_p_map

def __generate_processors(
self, n_processors: int,
down_cores: Optional[Collection[int]]) -> Tuple[int, ...]:
n_monitors = MachineDataView.get_machine_version().n_scamp_cores
if down_cores is None:
return tuple(range(n_monitors, n_processors))
else:
processors = list()
for i in range(n_monitors):
if i in down_cores:
raise NotImplementedError(
f"Declaring monitor core {i} as down is not supported")
for i in range(n_monitors, n_processors):
if i not in down_cores:
processors.append(i)
return tuple(processors)

def is_processor_with_id(self, processor_id: int) -> bool:
"""
Expand Down Expand Up @@ -267,40 +244,14 @@ def parent_link(self) -> Optional[int]:
"""
return self._parent_link

def get_physical_core_id(self, virtual_p: int) -> Optional[int]:
"""
Get the physical core ID from a virtual core ID.
:param int virtual_p: The virtual core ID
:rtype: int or None if core not in map
"""
if (self._v_to_p_map is None or virtual_p >= len(self._v_to_p_map) or
self._v_to_p_map[virtual_p] == 0xFF):
return None
return self._v_to_p_map[virtual_p]

def get_physical_core_string(self, virtual_p: int) -> str:
"""
Get a string that can be appended to a core to show the physical
core, or an empty string if not possible.
:param int virtual_p: The virtual core ID
:rtype: str
"""
physical_p = self.get_physical_core_id(virtual_p)
if physical_p is None:
return ""
return f" (ph: {physical_p})"

def __str__(self) -> str:
if self._ip_address:
ip_info = f"ip_address={self.ip_address} "
else:
ip_info = ""
return (
f"[Chip: x={self[0]}, y={self[1]}, {ip_info}"
f"n_cores={self.n_processors}, "
f"mon={self.get_physical_core_id(0)}]")
f"n_cores={self.n_processors}]")

def __repr__(self) -> str:
return self.__str__()
68 changes: 66 additions & 2 deletions spinn_machine/data/machine_data_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from typing import Callable, Optional, TYPE_CHECKING
from typing import Callable, Dict, Optional, TYPE_CHECKING
from spinn_utilities.typing.coords import XY
from spinn_utilities.data import UtilsDataView
from spinn_machine.exceptions import SpinnMachineException
Expand Down Expand Up @@ -48,7 +48,8 @@ class _MachineDataModel(object):
"_machine",
"_machine_generator",
"_machine_version",
"_user_accessed_machine"
"_user_accessed_machine",
"_v_to_p_map"
]

def __new__(cls) -> '_MachineDataModel':
Expand Down Expand Up @@ -78,6 +79,7 @@ def _hard_reset(self) -> None:
self._all_monitor_cores: int = 0
self._ethernet_monitor_cores: int = 0
self._machine: Optional[Machine] = None
self._v_to_p_map: Optional[Dict[XY, bytes]] = None
self._user_accessed_machine = False

def _soft_reset(self) -> None:
Expand Down Expand Up @@ -268,6 +270,68 @@ def get_machine_version(cls) -> AbstractVersion:
cls.__data._machine_version = version_factory()
return cls.__data._machine_version

@classmethod
def set_v_to_p_map(cls, v_to_p_map: Dict[XY, bytes]):
"""
Registers the mapping from Virtual to int physical core ids
Note: Only expected to be used in Version 1
:param dict((int, int), bytes) v_to_p_map:
"""
if cls.__data._v_to_p_map is None:
cls.__data._v_to_p_map = v_to_p_map
else:
raise SpinnMachineException(
"Unexpected second call to set_v_to_p_map")

@classmethod
def get_physical_core_id(cls, xy: XY, virtual_p: int) -> Optional[int]:
"""
Get the physical core ID from a virtual core ID.
Note: This call only works for Version 1
:param (int, int) xy: The Chip or its XY coordinates
:param int virtual_p: The virtual core ID
:rtype: int or None if core not in map
"""
if cls.__data._v_to_p_map is None:
version = cls.get_machine_version()
# delayed import to avoid circular reference
# pylint: disable=import-outside-toplevel
from spinn_machine.version.version_spin1 import VersionSpin1
if isinstance(version, VersionSpin1):
return None
else:
# TODO Spin2
raise SpinnMachineException(
f"This call is not supported when using Version {version}")
if xy in cls.__data._v_to_p_map:
v_to_p_map = cls.__data._v_to_p_map[xy]
else:
return None
if (virtual_p >= len(v_to_p_map) or v_to_p_map[virtual_p] == 0xFF):
return None
return v_to_p_map[virtual_p]

@classmethod
def get_physical_core_string(cls, xy: XY, virtual_p: int) -> str:
"""
Returns a String representing the physical core
:param (int, int) xy: The Chip or its XY coordinates
:param virtual_p: The virtual (python) id for the core
:rtype: str
"""
if cls.__data._v_to_p_map is not None:
physical_p = cls.get_physical_core_id(xy, virtual_p)
if physical_p is None:
return ""
return f" (ph: {physical_p})"
else:
return ""

@classmethod
def get_all_monitor_cores(cls) -> int:
"""
Expand Down
3 changes: 2 additions & 1 deletion spinn_machine/json_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ def machine_from_json(j_machine: Union[JsonObject, str]) -> Machine:
router = Router(links, router_entries)

# Create and add a chip with this router
n_cores = _int(details["cores"])
chip = Chip(
source_x, source_y, _int(details["cores"]), router, sdram,
source_x, source_y, [0], range(1, n_cores), router, sdram,
_int(board_x), _int(board_y), ip_address, [
_int(tag) for tag in tag_ids])
machine.add_chip(chip)
Expand Down
3 changes: 2 additions & 1 deletion spinn_machine/machine_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ def _machine_ignore(
links.append(link)
router = Router(links, chip.router.n_available_multicast_entries)
chip = Chip(
chip.x, chip.y, chip.n_processors, router, chip.sdram,
chip.x, chip.y, chip.scamp_processors_ids,
chip.placable_processors_ids, router, chip.sdram,
chip.nearest_ethernet_x, chip.nearest_ethernet_y,
chip.ip_address, chip.tag_ids)
new_machine.add_chip(chip)
Expand Down
8 changes: 5 additions & 3 deletions spinn_machine/virtual_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,14 @@ def _create_chip(self, xy: XY, configured_chips: Dict[XY, Tuple[XY, int]],

((eth_x, eth_y), n_cores) = configured_chips[xy]

down_cores = self._unused_cores.get(xy, None)
x, y = xy
sdram = MachineDataView.get_machine_version().max_sdram_per_chip
cores = list(range(1, n_cores))
for down_core in self._unused_cores.get(xy, []):
if down_core in cores:
cores.remove(down_core)
return Chip(
x, y, n_cores, chip_router, sdram, eth_x, eth_y,
ip_address, down_cores=down_cores)
x, y, [0], cores, chip_router, sdram, eth_x, eth_y, ip_address)

def _calculate_links(
self, xy: XY, configured_chips: Dict[XY, Tuple[XY, int]]
Expand Down
24 changes: 24 additions & 0 deletions unittests/data/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,30 @@ def test_where_is_setup(self):
MachineDataView.where_is_chip(None)
)

def test_v_to_p(self):
writer = MachineDataWriter.setup()
# TODO SPIN2
set_config("Machine", "version", FIVE)
# Before setting
self.assertEqual(None, writer.get_physical_core_id((1, 2), 3))
self.assertEqual("", writer.get_physical_core_string((1, 2), 3))

# Set a v_to_p
v_to_p = dict()
v_to_p[(1, 2)] = bytes([10, 11, 12, 13, 14])
writer.set_v_to_p_map(v_to_p)
# XY that exists
self.assertEqual(13, writer.get_physical_core_id((1, 2), 3))
self.assertEqual(" (ph: 13)",
writer.get_physical_core_string((1, 2), 3))
# Xy that does not exist
self.assertEqual(None, writer.get_physical_core_id((1, 4), 3))
self.assertEqual("",
writer.get_physical_core_string((1, 4), 3))
self.assertEqual(None, writer.get_physical_core_id((1, 2), 19))
self.assertEqual("",
writer.get_physical_core_string((1, 2), 19))

def test_mock_any(self):
# Should work with any version
set_config("Machine", "versions", VersionStrings.ANY.text)
Expand Down
14 changes: 6 additions & 8 deletions unittests/test_chip.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def setUp(self):
self._ip = "192.162.240.253"

def _create_chip(self, x, y, processors, r, sdram, ip):
return Chip(x, y, processors, r, sdram, 0, 0, ip)
return Chip(x, y, [0], range(1, processors), r, sdram, 0, 0, ip)

def test_create_chip(self):
new_chip = self._create_chip(self._x, self._y, self.n_processors,
Expand All @@ -59,21 +59,19 @@ def test_create_chip(self):
self.assertEqual(new_chip.n_placable_processors, self.n_processors - 1)
print(new_chip.__repr__())
self.assertEqual(
"[Chip: x=0, y=1, ip_address=192.162.240.253 "
"n_cores=18, mon=None]",
"[Chip: x=0, y=1, ip_address=192.162.240.253 n_cores=18]",
new_chip.__repr__(),)
self.assertEqual(new_chip.tag_ids, OrderedSet([1, 2, 3, 4, 5, 6, 7]))
self.assertTrue(new_chip.is_processor_with_id(3))

def test_0_down(self):
# Chip where 0 the monitor is down
with self.assertRaises(NotImplementedError):
Chip(1, 1, self.n_processors, self._router, self._sdram, 0, 0,
self._ip, down_cores=[0])
Chip(1, 1, [1], range(3, self.n_processors), self._router,
self._sdram, 0, 0, self._ip)

def test_1_chip(self):
# Chip with just 1 processor
new_chip = Chip(1, 1, 1, self._router, self._sdram, 0, 0, self._ip)
new_chip = Chip(1, 1, [0], [], self._router, self._sdram, 0, 0,
self._ip)
with self.assertRaises(Exception):
new_chip.get_first_none_monitor_processor()

Expand Down
8 changes: 4 additions & 4 deletions unittests/test_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ def setUp(self):
def _create_chip(self, x, y):
n_cores = MachineDataView.get_machine_version().max_cores_per_chip
if x == y == 0:
return Chip(x, y, n_cores, self._router, self._sdram,
self._nearest_ethernet_chip[0],
return Chip(x, y, [0], range(1, n_cores), self._router,
self._sdram, self._nearest_ethernet_chip[0],
self._nearest_ethernet_chip[1], self._ip)
return Chip(x, y, n_cores, self._router, self._sdram,
return Chip(x, y, [0], range(1, n_cores), self._router, self._sdram,
self._nearest_ethernet_chip[0],
self._nearest_ethernet_chip[1], None)

Expand Down Expand Up @@ -154,7 +154,7 @@ def test_chip_already_exists(self):
machine = virtual_machine_by_boards(1)
with self.assertRaises(SpinnMachineAlreadyExistsException):
machine.add_chip(Chip(
0, 0, 18, self._router, self._sdram,
0, 0, [0], range(1, 18), self._router, self._sdram,
self._nearest_ethernet_chip[0],
self._nearest_ethernet_chip[1], self._ip))

Expand Down
4 changes: 2 additions & 2 deletions unittests/test_virtual_machine201.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ def _create_chip(self, x, y):
_ip = "192.162.240.253"

if (x == y == 0):
return Chip(x, y, n_processors, _router, _sdram,
return Chip(x, y, [0], range(1, n_processors), _router, _sdram,
nearest_ethernet_chip[0],
nearest_ethernet_chip[1], _ip)
else:
return Chip(x, y, n_processors, _router, _sdram,
return Chip(x, y, [0], range(1, n_processors), _router, _sdram,
nearest_ethernet_chip[0],
nearest_ethernet_chip[1], None)

Expand Down
4 changes: 2 additions & 2 deletions unittests/test_virtual_machine3.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ def _create_chip(self, x, y):
_ip = "192.162.240.253"

if (x == y == 0):
return Chip(x, y, n_processors, _router, _sdram,
return Chip(x, y, [0], range(1, n_processors), _router, _sdram,
nearest_ethernet_chip[0],
nearest_ethernet_chip[1], _ip)
else:
return Chip(x, y, n_processors, _router, _sdram,
return Chip(x, y, [0], range(1, n_processors), _router, _sdram,
nearest_ethernet_chip[0],
nearest_ethernet_chip[1], None)

Expand Down

0 comments on commit a6d1e99

Please sign in to comment.