Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian-B committed Mar 5, 2024
2 parents a5dd539 + e416aa3 commit 8394f24
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 42 deletions.
141 changes: 113 additions & 28 deletions spinn_machine/chip.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
from .processor import Processor
from .router import Router

# global values so Chip objects can share processor dict objects
# One dict for each number of processors (none dead)
standard_processors = {}
# One dict for the standard monitor processors
standard_monitor_processors = None # pylint: disable=invalid-name


class Chip(object):
Expand All @@ -35,9 +39,10 @@ class Chip(object):
_IPTAG_IDS = OrderedSet(range(1, 8))

__slots__ = (
"_x", "_y", "_p", "_router", "_sdram", "_ip_address",
"_x", "_y", "_router", "_sdram", "_ip_address",
"_tag_ids", "_nearest_ethernet_x", "_nearest_ethernet_y",
"_n_user_processors", "_parent_link", "_v_to_p_map"
"_user_processors", "_monitor_processors", "_parent_link",
"_v_to_p_map"
)

# pylint: disable=too-many-arguments, wrong-spelling-in-docstring
Expand Down Expand Up @@ -82,7 +87,9 @@ def __init__(self, x: int, y: int, n_processors: int, router: Router,
"""
self._x = x
self._y = y
self._p = self.__generate_processors(n_processors, down_cores)
self._monitor_processors = self.__generate_monitors()
self._user_processors = self.__generate_processors(
n_processors, down_cores)
self._router = router
self._sdram = sdram
self._ip_address = ip_address
Expand All @@ -97,30 +104,40 @@ def __init__(self, x: int, y: int, n_processors: int, router: Router,
self._parent_link = parent_link
self._v_to_p_map = v_to_p_map

def __generate_monitors(self):
"""
Generates the monitors assuming all Chips have the same monitor cores
:return: Dict[int, Processor]
"""
global standard_monitor_processors # pylint: disable=global-statement
if standard_monitor_processors is None:
standard_monitor_processors = dict()
for i in range(
MachineDataView.get_machine_version().n_non_user_cores):
standard_monitor_processors[i] = Processor.factory(i, True)
return standard_monitor_processors

def __generate_processors(
self, n_processors: int,
down_cores: Optional[Collection[int]]) -> Dict[int, Processor]:
n_monitors = MachineDataView.get_machine_version().n_non_user_cores
if down_cores is None:
if n_processors not in standard_processors:
processors = dict()
processors[0] = Processor.factory(0, True)
for i in range(1, n_processors):
for i in range(n_monitors, n_processors):
processors[i] = Processor.factory(i)
standard_processors[n_processors] = processors
self._n_user_processors = n_processors - 1
return standard_processors[n_processors]
else:
processors = dict()
if 0 in down_cores:
raise NotImplementedError(
"Declaring core 0 as down is not supported")
processors[0] = Processor.factory(0, True)
for i in range(1, n_processors):
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[i] = Processor.factory(i)
self._n_user_processors = (
n_processors - len(down_cores) -
MachineDataView.get_machine_version().n_non_user_cores)
return processors

def is_processor_with_id(self, processor_id: int) -> bool:
Expand All @@ -132,7 +149,9 @@ def is_processor_with_id(self, processor_id: int) -> bool:
:return: Whether the processor with the given ID exists
:rtype: bool
"""
return processor_id in self._p
if processor_id in self._user_processors:
return True
return processor_id in self._monitor_processors

def get_processor_with_id(self, processor_id: int) -> Optional[Processor]:
"""
Expand All @@ -145,7 +164,9 @@ def get_processor_with_id(self, processor_id: int) -> Optional[Processor]:
or ``None`` if no such processor
:rtype: Processor or None
"""
return self._p.get(processor_id)
if processor_id in self._user_processors:
return self._user_processors[processor_id]
return self._monitor_processors.get(processor_id)

@property
def x(self) -> int:
Expand All @@ -168,11 +189,32 @@ def y(self) -> int:
@property
def processors(self) -> Iterator[Processor]:
"""
An iterable of available processors.
An iterable of available all processors.
Deprecated: There are many more efficient methods instead.
- all_processor_ids
- n_processors
- n_user_processors
- user_processors
- user_processors_ids
- n_monitor_processors
- monitor_processors
- monitor_processors_ids
:rtype: iterable(Processor)
"""
return iter(self._p.values())
yield from self._monitor_processors.values()
yield from self._user_processors.values()

@property
def all_processor_ids(self) -> Iterator[int]:
"""
An iterable of id's of all available processors
:rtype: iterable(int)
"""
yield from self._monitor_processors.keys()
yield from self._user_processors.keys()

@property
def n_processors(self) -> int:
Expand All @@ -181,7 +223,25 @@ def n_processors(self) -> int:
:rtype: int
"""
return len(self._p)
return len(self._monitor_processors) + len(self._user_processors)

@property
def user_processors(self) -> Iterator[Processor]:
"""
An iterable of available user processors.
:rtype: iterable(Processor)
"""
yield from self._user_processors.values()

@property
def user_processors_ids(self) -> Iterator[int]:
"""
An iterable of available user processors.
:rtype: iterable(Processor)
"""
yield from self._user_processors

@property
def n_user_processors(self) -> int:
Expand All @@ -190,7 +250,34 @@ def n_user_processors(self) -> int:
:rtype: int
"""
return self._n_user_processors
return len(self._user_processors)

@property
def monitor_processors(self) -> Iterator[Processor]:
"""
An iterable of available monitor processors.
:rtype: iterable(Processor)
"""
return self._monitor_processors.values()

@property
def monitor_processors_ids(self) -> Iterator[int]:
"""
An iterable of available user processors.
:rtype: iterable(Processor)
"""
yield from self._monitor_processors

@property
def n_monitor_processors(self) -> int:
"""
The total number of processors that are not monitors.
:rtype: int
"""
return len(self._monitor_processors)

@property
def router(self) -> Router:
Expand Down Expand Up @@ -247,16 +334,14 @@ def tag_ids(self) -> Iterable[int]:
"""
return self._tag_ids

def get_first_none_monitor_processor(self) -> Optional[Processor]:
def get_first_none_monitor_processor(self) -> Processor:
"""
Get the first processor in the list which is not a monitor core.
:rtype: Processor or None
:rtype: Processor
;raises StopIteration: If there is no user processor
"""
for processor in self.processors:
if not processor.is_monitor:
return processor
return None
return next(iter(self._user_processors.values()))

@property
def parent_link(self) -> Optional[int]:
Expand Down Expand Up @@ -302,8 +387,8 @@ def __iter__(self) -> Iterator[int]:
:rtype: iterable(int)
"""
yield self._x
yield self._y
yield from self._monitor_processors.items()
yield from self._user_processors.items()

def __getitem__(self, xy_id: int) -> int:
"""
Expand Down
3 changes: 1 addition & 2 deletions spinn_machine/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -1093,8 +1093,7 @@ def total_cores(self) -> int:
:rtype: int
"""
return sum(
1 for chip in self.chips for _processor in chip.processors)
return sum(chip.n_processors for chip in self.chips)

def unreachable_outgoing_chips(self) -> List[XY]:
"""
Expand Down
22 changes: 21 additions & 1 deletion unittests/test_chip.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import unittest
from spinn_utilities.config_holder import set_config
from spinn_utilities.ordered_set import OrderedSet
from spinn_machine import Link, Router, Chip
from spinn_machine.config_setup import unittest_setup
Expand All @@ -22,6 +23,7 @@ class TestingChip(unittest.TestCase):

def setUp(self):
unittest_setup()
set_config("Machine", "version", 5)
self._x = 0
self._y = 1

Expand Down Expand Up @@ -73,13 +75,31 @@ def test_get_first_none_monitor_processor(self):
self.assertFalse(non_monitor.is_monitor)

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])

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

def test_processors(self):
new_chip = self._create_chip(self._x, self._y, self.n_processors,
self._router, self._sdram, self._ip)
all_p = set()
for id in new_chip.all_processor_ids:
all_p.add(new_chip[id])
self.assertEqual(len(all_p), new_chip.n_processors)
users = set(new_chip.user_processors)
self.assertEqual(len(users), new_chip.n_user_processors)
self.assertEqual(len(users), len(set(new_chip.user_processors_ids)))
monitors = set(new_chip.monitor_processors)
self.assertEqual(users.union(monitors), all_p)
self.assertEqual(len(monitors),
len(set(new_chip.monitor_processors_ids)))


if __name__ == '__main__':
Expand Down
6 changes: 5 additions & 1 deletion unittests/test_json_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ def test_monitor_exceptions(self):
MachineDataWriter.mock().set_machine(vm)
chip02 = vm[0, 2]
# Hack in an extra monitor
chip02._n_user_processors -= 1
users = dict(chip02._user_processors)
monitors = dict(chip02._monitor_processors)
monitors[1] = users.pop(1)
chip02._monitor_processors = monitors
chip02._user_processors = users
jpath = mktemp("json")
# Should still be able to write json even with more than one monitor
to_json_path(jpath)
Expand Down
4 changes: 3 additions & 1 deletion unittests/test_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ def test_concentric_xys(self):
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]
chip01 = machine.get_chip_at(0, 1)
chip01._user_processors = dict(
list(chip01._user_processors.items())[:2])
with self.assertRaises(SpinnMachineException):
machine.validate()

Expand Down
13 changes: 4 additions & 9 deletions unittests/test_virtual_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,10 @@ def test_new_vm_with_monitor(self):
vm = virtual_machine(2, 2, n_cpus_per_chip=n_cpus, validate=True)
_chip = vm[1, 1]
self.assertEqual(n_cpus, _chip.n_processors)
monitors = 0
normal = 0
for core in _chip.processors:
if core.is_monitor:
monitors += 1
else:
normal += 1
self.assertEqual(n_cpus - 1, normal)
self.assertEqual(1, monitors)
self.assertEqual(n_cpus - 1, _chip.n_user_processors)
self.assertEqual(1, _chip.n_monitor_processors)
self.assertEqual(n_cpus - 1, len(list(_chip.user_processors)))
self.assertEqual(1, len(list(_chip.monitor_processors)))

def test_iter_chips(self):
set_config("Machine", "version", 2)
Expand Down

0 comments on commit 8394f24

Please sign in to comment.