Skip to content

Commit

Permalink
Merge pull request #226 from SpiNNakerManchester/too_few_cores
Browse files Browse the repository at this point in the history
check too few cores and let version check ethernet
  • Loading branch information
Christian-B authored Oct 18, 2023
2 parents e785c39 + 33623c1 commit 78b2765
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 19 deletions.
50 changes: 33 additions & 17 deletions spinn_machine/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,19 @@ def where_is_chip(self, chip: Chip) -> str:
:return: A human-readable description of the location of a chip.
:rtype: str
"""
chip00 = self[0, 0]
local00 = self[chip.nearest_ethernet_x, chip.nearest_ethernet_y]
(localx, localy) = self.get_local_xy(chip)
return (f"global chip {chip.x}, {chip.y} on {chip00.ip_address} "
f"is chip {localx}, {localy} on {local00.ip_address}")
try:
chip00 = self[0, 0]
try:
local00 = self[chip.nearest_ethernet_x,
chip.nearest_ethernet_y]
ip_address = f"on {local00.ip_address}"
except KeyError:
ip_address = ""
(localx, localy) = self.get_local_xy(chip)
return (f"global chip {chip.x}, {chip.y} on {chip00.ip_address} "
f"is chip {localx}, {localy} {ip_address}")
except Exception: # pylint: disable=broad-except
return str(Chip)

def where_is_xy(self, x: int, y: int) -> str:
"""
Expand Down Expand Up @@ -501,36 +509,44 @@ def validate(self) -> None:
# 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(f"{chip} has a negative x")
raise SpinnMachineException(
f"{self.where_is_chip(chip)} has a negative x")
if chip.y < 0:
raise SpinnMachineException(f"{chip} has a negative y")
raise SpinnMachineException(
f"{self.where_is_chip(chip)} has a negative y")
if chip.x >= self._width:
raise SpinnMachineException(
f"{chip} has an x larger than width {self._width}")
f"{self.where_is_chip(chip)} has an x larger "
f"than width {self._width}")
if chip.y >= self._height:
raise SpinnMachineException(
f"{chip} has a y larger than height {self._height}")
f"{self.where_is_chip(chip)} has a y larger "
f"than height {self._height}")
if chip.n_processors < version.minimum_cores_expected:
raise SpinnMachineException(
f"{self.where_is_chip(chip)} has too few cores "
f"found {chip.n_processors}")
if chip.ip_address:
# Ethernet Chip checks
if chip.x % 4 != 0:
raise SpinnMachineException(
f"Ethernet {chip} has a x which is not divisible by 4")
if (chip.x + chip.y) % 12 != 0:
error = version.illegal_ethernet_message(chip.x, chip.y)
if error is not None:
raise SpinnMachineException(
f"Ethernet {chip} has an x,y pair that "
"does not add up to 12")
f"{self.where_is_chip(chip)} {error}")
else:
# Non-Ethernet chip checks
if not self.is_chip_at(
chip.nearest_ethernet_x, chip.nearest_ethernet_y):
raise SpinnMachineException(
f"{chip} has an invalid ethernet chip")
f"{self.where_is_chip(chip)} "
f"has an invalid ethernet chip")
local_xy = self.get_local_xy(chip)
if local_xy not in self._chip_core_map:
raise SpinnMachineException(
f"{chip} has an unexpected local xy of {local_xy}")
f"{self.where_is_chip(chip)} "
f"has an unexpected local xy of {local_xy}")

@property
@abstractmethod
Expand Down
34 changes: 34 additions & 0 deletions spinn_machine/version/abstract_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,37 @@ def _create_machine(self, width: int, height: int, origin: str) -> Machine:
:rtype: ~spinn_machine.Machine
"""
raise NotImplementedError

@property
@abstractmethod
def minimum_cores_expected(self) -> int:
"""
The minimum number of Chip that we expect from a Chip
If there are less that this number of Cores Machine.validate and
other methods are allowed to raise an exception
:rtype: int
:return: The lowest number of cores to accept before flagging a
Chip to be blacklisted
"""
raise NotImplementedError

@abstractmethod
def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]:
"""
Checks if x and y could be for an Ethernet.
This method will return an explanation if the values for x and y are
known be illegal for an Ethernet chip.
Due to the limited information available this method will generate
False negatives.
So this method returning None does not imply that x, y is an
Ethernet location
:param int x:
:param int y:
:return: An explanation that the x and y can never be an Ethernet
"""
raise NotImplementedError
8 changes: 7 additions & 1 deletion spinn_machine/version/version_3.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 typing import Final, Mapping, Sequence, Tuple
from typing import Final, Mapping, Optional, Sequence, Tuple
from spinn_utilities.overrides import overrides
from spinn_utilities.typing.coords import XY
from .version_spin1 import VersionSpin1
Expand Down Expand Up @@ -66,3 +66,9 @@ def _verify_size(self, width: int, height: int):
@overrides(VersionSpin1._create_machine)
def _create_machine(self, width: int, height: int, origin: str) -> Machine:
return FullWrapMachine(width, height, CHIPS_PER_BOARD, origin)

@overrides(VersionSpin1.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
11 changes: 10 additions & 1 deletion spinn_machine/version/version_5.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 typing import Final, Mapping, Sequence, Tuple
from typing import Final, Mapping, Optional, Sequence, Tuple
from spinn_utilities.overrides import overrides
from spinn_utilities.typing.coords import XY
from spinn_machine.exceptions import SpinnMachineException
Expand Down Expand Up @@ -98,3 +98,12 @@ def _create_machine(self, width: int, height: int, origin: str) -> Machine:
width, height, CHIPS_PER_BOARD, origin)
else:
return NoWrapMachine(width, height, CHIPS_PER_BOARD, origin)

@overrides(VersionSpin1.illegal_ethernet_message)
def illegal_ethernet_message(self, x: int, y: int) -> Optional[str]:
if x % 4 != 0:
return "Only Chip with X divisible by 4 may be an Ethernet Chip"
if (x + y) % 12 != 0:
return "Only Chip with x + y divisible by 12 " \
"may be an Ethernet Chip"
return None
5 changes: 5 additions & 0 deletions spinn_machine/version/version_spin1.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ def n_non_user_cores(self) -> int:
@overrides(AbstractVersion.n_router_entries)
def n_router_entries(self) -> int:
return 1023

@property
@overrides(AbstractVersion.minimum_cores_expected)
def minimum_cores_expected(self) -> int:
return 5
7 changes: 7 additions & 0 deletions unittests/test_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,13 @@ def test_concentric_xys(self):
(2, 4), (1, 3), (0, 2), (0, 1), (0, 0), (1, 0)]
self.assertListEqual(expected, found)

def test_too_few_cores(self):
machine = virtual_machine(8, 8)
# Hack to get n_processors return a low number
machine.get_chip_at(0, 1)._p = [1, 2, 3]
with self.assertRaises(SpinnMachineException):
machine.validate()


if __name__ == '__main__':
unittest.main()

0 comments on commit 78b2765

Please sign in to comment.