Source code for pacman.operations.routing_table_generators.merged_routing_table_generator

# Copyright (c) 2017 The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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 spinn_utilities.progress_bar import ProgressBar
from spinn_machine import MulticastRoutingEntry
from pacman.data import PacmanDataView
from pacman.exceptions import PacmanRoutingException
from pacman.model.routing_tables import (
    UnCompressedMulticastRoutingTable, MulticastRoutingTables)
from pacman.model.graphs.application import ApplicationVertex


[docs]def merged_routing_table_generator(): """ Creates routing entries by merging adjacent entries from the same application vertex when possible. :rtype: MulticastRoutingTables """ routing_table_by_partitions = ( PacmanDataView.get_routing_table_by_partition()) routing_infos = PacmanDataView.get_routing_infos() progress = ProgressBar( routing_table_by_partitions.n_routers, "Generating routing tables") routing_tables = MulticastRoutingTables() for x, y in progress.over(routing_table_by_partitions.get_routers()): parts = routing_table_by_partitions.get_entries_for_router(x, y) routing_tables.add_routing_table(__create_routing_table( x, y, parts, routing_infos)) return routing_tables
def __create_routing_table(x, y, partitions_in_table, routing_info): """ :param int x: :param int y: :param partitions_in_table: :type partitions_in_table: dict(((ApplicationVertex or MachineVertex), str), MulticastRoutingTableByPartitionEntry) :param RoutingInfo routing_infos: :rtype: MulticastRoutingTable """ table = UnCompressedMulticastRoutingTable(x, y) iterator = _IteratorWithNext(partitions_in_table.items()) while iterator.has_next: (vertex, part_id), entry = iterator.pop() r_info = routing_info.get_routing_info_from_pre_vertex(vertex, part_id) if r_info is None: raise PacmanRoutingException( f"Missing Routing information for {vertex}, {part_id}") entries = [(vertex, part_id, entry, r_info)] while __match(iterator, vertex, part_id, r_info, entry, routing_info): (vertex, part_id), entry = iterator.pop() r_info = routing_info.get_routing_info_from_pre_vertex( vertex, part_id) entries.append((vertex, part_id, entry, r_info)) # Now attempt to merge sources together as much as possible for entry in __merged_keys_and_masks(entries, routing_info): table.add_multicast_routing_entry(entry) return table def __match(iterator, vertex, part_id, r_info, entry, routing_info): if not iterator.has_next: return False if isinstance(vertex, ApplicationVertex): return False (next_vertex, next_part_id), next_entry = iterator.peek() if isinstance(next_vertex, ApplicationVertex): return False if part_id != next_part_id: return False if __mask_has_holes(r_info.mask): return False next_r_info = routing_info.get_routing_info_from_pre_vertex( next_vertex, next_part_id) if next_r_info is None: raise KeyError( f"No routing info found for {next_vertex}, {next_part_id}") if next_r_info.index != r_info.index + 1: return False app_src = vertex.app_vertex next_app_src = next_vertex.app_vertex return next_app_src == app_src and entry.has_same_route(next_entry) def __mask_has_holes(mask): """ Detect if the mask has a "hole" somewhere other than at the bottom. :param int mask: The mask to check :rtype: bool """ # The mask is inverted and then add 1. If this number is a power of 2, # the mask doesn't have holes inv_mask = (~mask & 0xFFFFFFFF) + 1 # a & ~a == 0 if a is a power of 2 return (inv_mask & (inv_mask - 1)) != 0 def __merged_keys_and_masks(entries, routing_info): if not entries: return (vertex, part_id, entry, r_info) = entries[0] if isinstance(vertex, ApplicationVertex) or len(entries) == 1: yield MulticastRoutingEntry( r_info.key, r_info.mask, defaultable=entry.defaultable, spinnaker_route=entry.spinnaker_route) else: app_r_info = routing_info.get_routing_info_from_pre_vertex( vertex.app_vertex, part_id) yield from app_r_info.merge_machine_entries(entries) class _IteratorWithNext(object): def __init__(self, iterable): self.__iterator = iter(iterable) try: self.__next = next(self.__iterator) self.__has_next = True except StopIteration: self.__next = None self.__has_next = False def peek(self): return self.__next @property def has_next(self): return self.__has_next def pop(self): if not self.__has_next: raise StopIteration nxt = self.__next try: self.__next = next(self.__iterator) self.__has_next = True except StopIteration: self.__next = None self.__has_next = False return nxt