From eec04f4c8c75fa996e4502dca3d013393e8dbcca Mon Sep 17 00:00:00 2001 From: Andrew Rowley Date: Fri, 23 Aug 2024 09:56:59 +0100 Subject: [PATCH 1/6] Filter internal partitions to the ones being looked at now --- .../router_algorithms/application_router.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pacman/operations/router_algorithms/application_router.py b/pacman/operations/router_algorithms/application_router.py index eeb2a11b5..adf05746e 100644 --- a/pacman/operations/router_algorithms/application_router.py +++ b/pacman/operations/router_algorithms/application_router.py @@ -234,7 +234,8 @@ def route_application_graph() -> MulticastRoutingTableByPartition: _route_source_to_source(source, partition, targets, self_xys) # Deal with internal multicast partitions - internal = source.splitter.get_internal_multicast_partitions() + internal = _get_filtered_internal_partitions( + source, partition.identifier) if internal: self_connected = True _route_internal(internal, targets, self_xys) @@ -258,6 +259,12 @@ def route_application_graph() -> MulticastRoutingTableByPartition: return routing_tables +def _get_filtered_internal_partitions(vertex, identifier): + for partition in vertex.splitter.get_internal_multicast_partitions(): + if partition.identifier == identifier: + yield partition + + def _route_source_to_target( machine: Machine, source: ApplicationVertex, source_xy: XY, all_source_xys: Set[XY], @@ -628,7 +635,7 @@ def _get_outgoing_mapping( for m_vertex in app_vertex.splitter.get_out_going_vertices(partition_id): xy, route = vertex_xy_and_route(m_vertex) outgoing_mapping[xy].append(route) - for in_part in app_vertex.splitter.get_internal_multicast_partitions(): + for in_part in _get_filtered_internal_partitions(app_vertex, partition_id): if in_part.identifier == partition_id: xy, route = vertex_xy_and_route(in_part.pre_vertex) outgoing_mapping[xy].append(route) From 53a440988b91215c01984cff3be25ded5ea48c90 Mon Sep 17 00:00:00 2001 From: Andrew Rowley Date: Fri, 23 Aug 2024 09:57:19 +0100 Subject: [PATCH 2/6] Make sure we get all partitions --- .../routing_algorithm_utilities.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pacman/utilities/algorithm_utilities/routing_algorithm_utilities.py b/pacman/utilities/algorithm_utilities/routing_algorithm_utilities.py index b1cb01216..de0945551 100644 --- a/pacman/utilities/algorithm_utilities/routing_algorithm_utilities.py +++ b/pacman/utilities/algorithm_utilities/routing_algorithm_utilities.py @@ -47,19 +47,18 @@ def get_app_partitions() -> List[ApplicationEdgePartition]: # Find all partitions that need to be dealt with # Make a copy which we can edit partitions = list(PacmanDataView.iterate_partitions()) - sources = frozenset(p.pre_vertex for p in partitions) + sources = set((p.pre_vertex, p.identifier) for p in partitions) # Convert internal partitions to self-connected partitions for v in PacmanDataView.iterate_vertices(): if not isinstance(v, ApplicationVertex) or not v.splitter: continue internal_partitions = v.splitter.get_internal_multicast_partitions() - if v not in sources and internal_partitions: - # guarantee order - for identifier in dict.fromkeys( - p.identifier for p in internal_partitions): + for p in internal_partitions: + if (v, p.identifier) not in sources: # Add a partition with no edges to identify this as internal - partitions.append(ApplicationEdgePartition(identifier, v)) + partitions.append(ApplicationEdgePartition(p.identifier, v)) + sources.add((v, p.identifier)) return partitions From 9ba61933d0c5a247fb9d4d7ee239eae39dac8ab1 Mon Sep 17 00:00:00 2001 From: Andrew Rowley Date: Fri, 23 Aug 2024 09:57:34 +0100 Subject: [PATCH 3/6] Use the utility rather than custom code --- .../zoned_routing_info_allocator.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pacman/operations/routing_info_allocator_algorithms/zoned_routing_info_allocator.py b/pacman/operations/routing_info_allocator_algorithms/zoned_routing_info_allocator.py index 41ce1fafb..a2a910c13 100644 --- a/pacman/operations/routing_info_allocator_algorithms/zoned_routing_info_allocator.py +++ b/pacman/operations/routing_info_allocator_algorithms/zoned_routing_info_allocator.py @@ -17,7 +17,6 @@ from spinn_utilities.log import FormatAdapter from spinn_utilities.progress_bar import ProgressBar from spinn_utilities.ordered_set import OrderedSet -from pacman.data import PacmanDataView from pacman.model.routing_info import ( RoutingInfo, MachineVertexRoutingInfo, BaseKeyAndMask, AppVertexRoutingInfo) @@ -28,6 +27,8 @@ get_key_ranges, allocator_bits_needed) from pacman.exceptions import PacmanRouteInfoAllocationException from pacman.utilities.constants import BITS_IN_KEY, FULL_MASK +from pacman.utilities.algorithm_utilities.routing_algorithm_utilities import ( + get_app_partitions) _XAlloc = Iterable[Tuple[ApplicationVertex, str]] logger = FormatAdapter(logging.getLogger(__name__)) @@ -137,13 +138,8 @@ def allocate(self, extra_allocations: _XAlloc) -> RoutingInfo: """ self.__vertex_partitions = OrderedSet( (p.pre_vertex, p.identifier) - for p in PacmanDataView.iterate_partitions()) + for p in get_app_partitions()) self.__vertex_partitions.update(extra_allocations) - self.__vertex_partitions.update( - (v, p.identifier) - for v in PacmanDataView.iterate_vertices() - if isinstance(v, ApplicationVertex) - for p in v.splitter.get_internal_multicast_partitions()) self.__find_fixed() self.__calculate_zones() From d1b71cc068f53172bf6bafb76f5b0d7a578df557 Mon Sep 17 00:00:00 2001 From: Andrew Rowley Date: Fri, 23 Aug 2024 10:54:41 +0100 Subject: [PATCH 4/6] Also account for the partition here --- .../router_algorithms/application_router.py | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/pacman/operations/router_algorithms/application_router.py b/pacman/operations/router_algorithms/application_router.py index adf05746e..ed1f87c7a 100644 --- a/pacman/operations/router_algorithms/application_router.py +++ b/pacman/operations/router_algorithms/application_router.py @@ -202,7 +202,10 @@ def route_application_graph() -> MulticastRoutingTableByPartition: source_xy = next(iter(source_mappings.keys())) # Get all source chips coordinates - all_source_xys = _get_all_xys(source) + all_source_xys = { + vertex_xy(m_vertex) + for m_vertex in source.splitter.get_out_going_vertices( + partition.identifier)} # Keep track of the source edge chips source_edge_xys: Set[XY] = set() @@ -234,8 +237,8 @@ def route_application_graph() -> MulticastRoutingTableByPartition: _route_source_to_source(source, partition, targets, self_xys) # Deal with internal multicast partitions - internal = _get_filtered_internal_partitions( - source, partition.identifier) + internal = list(_get_filtered_internal_partitions( + source, partition.identifier)) if internal: self_connected = True _route_internal(internal, targets, self_xys) @@ -320,7 +323,8 @@ def _route_source_to_target( overlaps = None else: # Find all coordinates for chips (xy) that are in the target - target_xys = _get_all_xys(target) + target_xys = {vertex_xy(m_vertex) + for m_vertex, _srcs in target_vertices} # Pick one to actually use as a target target_xy, overlaps = _find_target_xy( @@ -642,18 +646,6 @@ def _get_outgoing_mapping( return outgoing_mapping -def _get_all_xys(app_vertex: ApplicationVertex) -> Set[XY]: - """ - Gets the list of all the x,y coordinates that the vertex's machine vertices - are placed on. - - :param ApplicationVertex app_vertex: - :rtype: set(tuple(int, int)) - """ - return {vertex_xy(m_vertex) - for m_vertex in app_vertex.machine_vertices} - - def _route_to_xys( first_xy: XY, all_xys: Set[XY], machine: Machine, routes: Dict[XY, RoutingTree], targets: Iterable[XY], label: str): From be1d8d96d8fdaac3c8fde472d9c2a1a4aae3e8e9 Mon Sep 17 00:00:00 2001 From: Andrew Rowley Date: Wed, 28 Aug 2024 13:13:54 +0100 Subject: [PATCH 5/6] Fix a very specific issue --- pacman/operations/router_algorithms/application_router.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pacman/operations/router_algorithms/application_router.py b/pacman/operations/router_algorithms/application_router.py index ed1f87c7a..5805bf240 100644 --- a/pacman/operations/router_algorithms/application_router.py +++ b/pacman/operations/router_algorithms/application_router.py @@ -204,8 +204,7 @@ def route_application_graph() -> MulticastRoutingTableByPartition: # Get all source chips coordinates all_source_xys = { vertex_xy(m_vertex) - for m_vertex in source.splitter.get_out_going_vertices( - partition.identifier)} + for m_vertex in source.machine_vertices} # Keep track of the source edge chips source_edge_xys: Set[XY] = set() @@ -470,6 +469,7 @@ def _route_internal( """ for in_part in internal_partitions: src = in_part.pre_vertex + xy = vertex_xy(src) for edge in in_part.edges: tgt = edge.post_vertex xy, (_vertex, core, link) = vertex_xy_and_route(tgt) From a74db3ce60e5d3fb41b136431fa9855227dc56bd Mon Sep 17 00:00:00 2001 From: Andrew Rowley Date: Wed, 28 Aug 2024 14:07:07 +0100 Subject: [PATCH 6/6] Add a test --- .../router_algorithms_tests/test_routers.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/unittests/operations_tests/router_algorithms_tests/test_routers.py b/unittests/operations_tests/router_algorithms_tests/test_routers.py index 4c6ae87f5..208be920f 100644 --- a/unittests/operations_tests/router_algorithms_tests/test_routers.py +++ b/unittests/operations_tests/router_algorithms_tests/test_routers.py @@ -268,6 +268,60 @@ def placements(self): return self.__placements +class MockInputOutputSplitter(AbstractSplitterCommon): + def __init__(self, n_incoming, n_outgoing): + super().__init__() + self.__n_incoming = n_incoming + self.__n_outgoing = n_outgoing + self.__incoming_machine_vertices = list() + self.__outgoing_machine_vertices = list() + self.__internal_multicast_partitions = list() + + def create_machine_vertices(self, chip_counter): + self.__incoming_machine_vertices = [ + SimpleMachineVertex( + ConstantSDRAM(0), app_vertex=self.governed_app_vertex, + label=f"{self.governed_app_vertex.label}_input_{j}") + for j in range(self.__n_incoming)] + self.__outgoing_machine_vertices = [ + SimpleMachineVertex( + ConstantSDRAM(0), app_vertex=self.governed_app_vertex, + label=f"{self.governed_app_vertex.label}_output_{j}") + for j in range(self.__n_outgoing)] + for out_v in self.__outgoing_machine_vertices: + self.governed_app_vertex.remember_machine_vertex(out_v) + for in_v in self.__incoming_machine_vertices: + self.governed_app_vertex.remember_machine_vertex(in_v) + + # The partition is from outgoing to incoming + for start_v in self.__outgoing_machine_vertices: + part = MulticastEdgePartition(start_v, "internal") + self.__internal_multicast_partitions.append(part) + for end_v in self.__incoming_machine_vertices: + part.add_edge(MachineEdge(start_v, end_v)) + + def get_out_going_slices(self): + return None + + def get_in_coming_slices(self): + return None + + def get_out_going_vertices(self, partition_id): + return self.__outgoing_machine_vertices + + def get_in_coming_vertices(self, partition_id): + return self.__incoming_machine_vertices + + def machine_vertices_for_recording(self, variable_to_record): + return [] + + def get_internal_multicast_partitions(self): + return self.__internal_multicast_partitions + + def reset_called(self): + pass + + class MockAppVertex(ApplicationVertex): def __init__(self, n_atoms, label): super(MockAppVertex, self).__init__(label) @@ -313,6 +367,15 @@ def _make_vertices_split( return vertex +def _make_input_output_vertices( + writer, n_atoms, n_incoming, n_outgoing, label): + vertex = MockAppVertex(n_atoms, label) + vertex.splitter = MockInputOutputSplitter(n_incoming, n_outgoing) + writer.add_vertex(vertex) + vertex.splitter.create_machine_vertices(None) + return vertex + + def _get_entry(routing_tables, x, y, source_vertex, partition_id, allow_none): app_entry = routing_tables.get_entry_on_coords_for_edge( source_vertex.app_vertex, partition_id, x, y) @@ -826,3 +889,22 @@ def test_route_around(): print(nodes) print(nodes_fixed) + + +def test_internal_io_routes(params): + algorithm, _n_vertices, _n_m_vertices = params + unittest_setup() + set_config("Machine", "versions", VersionStrings.BIG.text) + machine = PacmanDataView.get_machine() + writer = PacmanDataWriter.mock() + writer.set_machine(machine) + vertex = _make_input_output_vertices(writer, 1, 1, 3, "app_vertex") + placements = Placements() + for i, m_vertex in enumerate(vertex.splitter.get_out_going_vertices(None)): + placements.add_placement(Placement(m_vertex, 0, 1, i)) + + for i, m_vertex in enumerate(vertex.splitter.get_in_coming_vertices(None)): + placements.add_placement(Placement(m_vertex, 0, 0, i)) + writer.set_placements(placements) + routing_tables = _route_and_time(algorithm) + _check_edges(routing_tables)