Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overlap #542

Merged
merged 11 commits into from
Jul 24, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -154,19 +154,6 @@ def allocate(self, extra_allocations: _XAlloc) -> RoutingInfo:

return self.__allocate()

def __insert_fixed(
self, identifier: str, vertex: AbstractVertex, km: BaseKeyAndMask):
is_app = isinstance(vertex, ApplicationVertex)
for (_, vertex2), km2 in self.__fixed_partitions.items():
if is_app and isinstance(vertex2, MachineVertex) and \
(vertex == vertex2.app_vertex):
continue
# check if any keys could overlap
if (km.key & km2.mask) == (km2.key & km.mask):
raise PacmanRouteInfoAllocationException(
f"{vertex} has {km} which overlaps with {vertex2} {km2}")
self.__fixed_partitions[identifier, vertex] = km

def __find_fixed(self) -> None:
"""
Looks for FixedKeyAmdMask Constraints and keeps track of these.
Expand Down Expand Up @@ -199,7 +186,7 @@ def __find_fixed(self) -> None:
f"For application vertex {pre}, the fixed key for "
f"machine vertex {vert} of {key_and_mask} does "
f"not align with the app key {app_key_and_mask}")
self.__insert_fixed(identifier, vert, key_and_mask)
self.__fixed_partitions[identifier, vert] = key_and_mask
else:
if is_fixed_m_key:
raise PacmanRouteInfoAllocationException(
Expand All @@ -216,8 +203,9 @@ def __find_fixed(self) -> None:
f"On {pre} only a fixed app key has been provided,"
" but there is more than one machine vertex.")
# pylint:disable=undefined-loop-variable
self.__insert_fixed(identifier, vert, app_key_and_mask)
self.__insert_fixed(identifier, pre, app_key_and_mask)
self.__fixed_partitions[
identifier, vert] = app_key_and_mask
self.__fixed_partitions[identifier, pre] = app_key_and_mask

def __calculate_zones(self) -> None:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
UnCompressedMulticastRoutingTable, MulticastRoutingTables)
from pacman.model.graphs import AbstractVertex
from pacman.model.routing_info import RoutingInfo
from pacman.model.routing_info.base_key_and_mask import BaseKeyAndMask


def basic_routing_table_generator() -> MulticastRoutingTables:
Expand Down Expand Up @@ -59,13 +60,25 @@ def __create_routing_table(
:rtype: MulticastRoutingTable
"""
table = UnCompressedMulticastRoutingTable(x, y)
sources_by_key_mask: Dict[BaseKeyAndMask,
Tuple[AbstractVertex, str]] = dict()
for source_vertex, partition_id in partitions_in_table:
r_info = routing_infos.get_routing_info_from_pre_vertex(
source_vertex, partition_id)
# Should be there; skip if not
if r_info is None:
continue
entry = partitions_in_table[source_vertex, partition_id]
if r_info.key_and_mask in sources_by_key_mask:
if (sources_by_key_mask[r_info.key_and_mask]
!= (source_vertex, partition_id)):
raise KeyError(
f"Source {source_vertex}, {partition_id} is trying to "
f"send to the same key and mask as "
f"{sources_by_key_mask[r_info.key_and_mask]}")
else:
sources_by_key_mask[r_info.key_and_mask] = (
source_vertex, partition_id)
table.add_multicast_routing_entry(MulticastRoutingEntry(
key=r_info.key_and_mask.key_combo,
mask=r_info.key_and_mask.mask, routing_entry=entry))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
RoutingInfo, AppVertexRoutingInfo, MachineVertexRoutingInfo)
from pacman.model.graphs import AbstractVertex
from pacman.model.graphs.machine.machine_vertex import MachineVertex
from pacman.model.routing_info.base_key_and_mask import BaseKeyAndMask


def merged_routing_table_generator() -> MulticastRoutingTables:
Expand Down Expand Up @@ -64,6 +65,8 @@ def __create_routing_table(
:rtype: MulticastRoutingTable
"""
table = UnCompressedMulticastRoutingTable(x, y)
sources_by_key_mask: Dict[BaseKeyAndMask,
Tuple[AbstractVertex, str]] = dict()
iterator = _IteratorWithNext(partitions_in_table.items())
while iterator.has_next:
(vertex, part_id), entry = iterator.pop()
Expand All @@ -72,6 +75,16 @@ def __create_routing_table(
raise PacmanRoutingException(
f"Missing Routing information for {vertex}, {part_id}")

if r_info.key_and_mask in sources_by_key_mask:
if (sources_by_key_mask[r_info.key_and_mask] != (vertex, part_id)):
raise KeyError(
f"Source {vertex}, {part_id} is trying to "
f"send to the same key and mask as "
f"{sources_by_key_mask[r_info.key_and_mask]}")
else:
sources_by_key_mask[r_info.key_and_mask] = (
vertex, part_id)

# If we have an application vertex, just put the entry in and move on
if isinstance(vertex, ApplicationVertex):
table.add_multicast_routing_entry(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from spinn_utilities.overrides import overrides
from pacman.config_setup import unittest_setup
from pacman.data import PacmanDataView
from pacman.exceptions import PacmanRouteInfoAllocationException
from pacman.operations.routing_info_allocator_algorithms.\
zoned_routing_info_allocator import (flexible_allocate, global_allocate)
from pacman.model.graphs.application import ApplicationEdge, ApplicationVertex
Expand Down Expand Up @@ -299,13 +298,11 @@ def test_fixed_only():


def test_overlap():
# This should work here; overlap is allowed provided routes don't overlap
# (which is found elsewhere)
unittest_setup()
create_graphs_only_fixed(overlap=True)
try:
flexible_allocate([])
raise ValueError
except PacmanRouteInfoAllocationException:
pass
flexible_allocate([])


def test_no_edge():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
# limitations under the License.

import unittest
from typing import Optional, cast
from typing_extensions import Self
from spinn_utilities.config_holder import set_config
from pacman.config_setup import unittest_setup
from pacman.data.pacman_data_writer import PacmanDataWriter
Expand All @@ -30,6 +32,27 @@
from pacman.operations.routing_table_generators import (
basic_routing_table_generator)
from pacman_test_objects import SimpleTestVertex
from pacman.model.graphs.application.abstract import (
AbstractOneAppOneMachineVertex)
from pacman.model.routing_info.base_key_and_mask import BaseKeyAndMask
from pacman.model.partitioner_splitters import SplitterOneAppOneMachine


class FixedKeyAppVertex(AbstractOneAppOneMachineVertex):

def __init__(
self, fixed_key_and_mask, label: Optional[str] = None,
n_atoms: int = 1):
AbstractOneAppOneMachineVertex.__init__(
self, SimpleMachineVertex(ConstantSDRAM(1000)), label,
n_atoms=n_atoms)
self.__fixed_key_and_mask = fixed_key_and_mask
self._splitter = SplitterOneAppOneMachine()
self._splitter.set_governed_app_vertex(cast(Self, self))

def get_fixed_key_and_mask(
self, partition_id: str) -> Optional[BaseKeyAndMask]:
return self.__fixed_key_and_mask


class TestBasic(unittest.TestCase):
Expand Down Expand Up @@ -86,3 +109,62 @@ def test_graph3_with_system(self):
self.assertEqual(31, data.get_max_number_of_entries())
self.assertEqual(108, data.get_total_number_of_entries())
self.assertEqual(5, len(list(data.routing_tables)))

def test_overlapping(self):
# Two vertices in the same router can't send with the same key
writer = PacmanDataWriter.mock()
v_target = SimpleTestVertex(1, splitter=SplitterFixedLegacy())
v1 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
v2 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
writer.add_vertex(v_target)
writer.add_vertex(v1)
writer.add_vertex(v2)
writer.add_edge(ApplicationEdge(v1, v_target), "Test")
writer.add_edge(ApplicationEdge(v2, v_target), "Test")
system_placements = Placements()
system_placements.add_placement(Placement(v1.machine_vertex, 0, 0, 1))
system_placements.add_placement(Placement(v2.machine_vertex, 0, 0, 2))
self.make_infos(writer, system_placements)
with self.assertRaises(KeyError):
basic_routing_table_generator()

def test_overlapping_different_chips(self):
# Two vertices in the same router can't send with the same key
writer = PacmanDataWriter.mock()
v_target = SimpleTestVertex(1, splitter=SplitterFixedLegacy())
v1 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
v2 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
writer.add_vertex(v_target)
writer.add_vertex(v1)
writer.add_vertex(v2)
writer.add_edge(ApplicationEdge(v1, v_target), "Test")
writer.add_edge(ApplicationEdge(v2, v_target), "Test")
system_placements = Placements()
system_placements.add_placement(Placement(v1.machine_vertex, 1, 0, 1))
system_placements.add_placement(Placement(v2.machine_vertex, 0, 0, 2))
self.make_infos(writer, system_placements)
with self.assertRaises(KeyError):
basic_routing_table_generator()

def test_non_overlapping_different_chips(self):
# Two vertices with non-overlapping routes can use the same key
writer = PacmanDataWriter.mock()
v_target_1 = FixedKeyAppVertex(None)
v_target_2 = FixedKeyAppVertex(None)
v1 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
v2 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
writer.add_vertex(v_target_1)
writer.add_vertex(v_target_2)
writer.add_vertex(v1)
writer.add_vertex(v2)
writer.add_edge(ApplicationEdge(v1, v_target_1), "Test")
writer.add_edge(ApplicationEdge(v2, v_target_2), "Test")
system_placements = Placements()
system_placements.add_placement(Placement(v1.machine_vertex, 1, 0, 1))
system_placements.add_placement(
Placement(v_target_1.machine_vertex, 1, 0, 2))
system_placements.add_placement(Placement(v2.machine_vertex, 0, 0, 2))
system_placements.add_placement(
Placement(v_target_2.machine_vertex, 0, 0, 3))
self.make_infos(writer, system_placements)
basic_routing_table_generator()
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
from pacman.operations.routing_table_generators.merged_routing_table_generator\
import (merged_routing_table_generator, _IteratorWithNext)
from pacman_test_objects import SimpleTestVertex
from pacman.model.routing_info import BaseKeyAndMask
from .test_basic import FixedKeyAppVertex


class TestMerged(unittest.TestCase):
Expand Down Expand Up @@ -153,3 +155,62 @@ def test_iterator_with_next(self):
# this needs to work even with a debugger look at ten here
check.append(ten.pop())
self.assertEqual(10, len(check))

def test_overlapping(self):
# Two vertices in the same router can't send with the same key
writer = PacmanDataWriter.mock()
v_target = SimpleTestVertex(1, splitter=SplitterFixedLegacy())
v1 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
v2 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
writer.add_vertex(v_target)
writer.add_vertex(v1)
writer.add_vertex(v2)
writer.add_edge(ApplicationEdge(v1, v_target), "Test")
writer.add_edge(ApplicationEdge(v2, v_target), "Test")
system_placements = Placements()
system_placements.add_placement(Placement(v1.machine_vertex, 0, 0, 1))
system_placements.add_placement(Placement(v2.machine_vertex, 0, 0, 2))
self.make_infos(writer, system_placements)
with self.assertRaises(KeyError):
merged_routing_table_generator()

def test_overlapping_different_chips(self):
# Two vertices in the same router can't send with the same key
writer = PacmanDataWriter.mock()
v_target = SimpleTestVertex(1, splitter=SplitterFixedLegacy())
v1 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
v2 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
writer.add_vertex(v_target)
writer.add_vertex(v1)
writer.add_vertex(v2)
writer.add_edge(ApplicationEdge(v1, v_target), "Test")
writer.add_edge(ApplicationEdge(v2, v_target), "Test")
system_placements = Placements()
system_placements.add_placement(Placement(v1.machine_vertex, 1, 0, 1))
system_placements.add_placement(Placement(v2.machine_vertex, 0, 0, 2))
self.make_infos(writer, system_placements)
with self.assertRaises(KeyError):
merged_routing_table_generator()

def test_non_overlapping_different_chips(self):
# Two vertices with non-overlapping routes can use the same key
writer = PacmanDataWriter.mock()
v_target_1 = FixedKeyAppVertex(None)
v_target_2 = FixedKeyAppVertex(None)
v1 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
v2 = FixedKeyAppVertex(BaseKeyAndMask(0x1, 0xFFFFFFFF))
writer.add_vertex(v_target_1)
writer.add_vertex(v_target_2)
writer.add_vertex(v1)
writer.add_vertex(v2)
writer.add_edge(ApplicationEdge(v1, v_target_1), "Test")
writer.add_edge(ApplicationEdge(v2, v_target_2), "Test")
system_placements = Placements()
system_placements.add_placement(Placement(v1.machine_vertex, 1, 0, 1))
system_placements.add_placement(
Placement(v_target_1.machine_vertex, 1, 0, 2))
system_placements.add_placement(Placement(v2.machine_vertex, 0, 0, 2))
system_placements.add_placement(
Placement(v_target_2.machine_vertex, 0, 0, 3))
self.make_infos(writer, system_placements)
merged_routing_table_generator()