Source code for pacman.operations.routing_info_allocator_algorithms.zoned_routing_info_allocator
# Copyright (c) 2019 The University of Manchester
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import math
from spinn_utilities.progress_bar import ProgressBar
from pacman.model.routing_info import (
RoutingInfo, PartitionRoutingInfo, BaseKeyAndMask)
from pacman.utilities.utility_calls import (
check_algorithm_can_support_constraints)
from pacman.exceptions import PacmanRouteInfoAllocationException
from pacman.model.constraints.key_allocator_constraints import (
AbstractKeyAllocatorConstraint, ContiguousKeyRangeContraint)
from pacman.model.graphs.common import EdgeTrafficType
KEY_SIZE = 32
[docs]class ZonedRoutingInfoAllocator(object):
""" An basic algorithm that can produce routing keys and masks for\
edges in a graph based on the x,y,p of the placement\
of the preceding vertex.
.. note::
No constraints are supported, and that the number of keys\
required by each edge must be 2048 or less, and that all edges coming\
out of a vertex will be given the same key/mask assignment.
"""
__slots__ = [
# Passed in paramateres
"_application_graph",
"_graph_mapper",
"_machine_graph",
"_placements",
"_n_keys_map",
"_max_app_keys_bites",
"_key_bites_per_app"
]
# pylint: disable=attribute-defined-outside-init
def __call__(self, application_graph, graph_mapper, machine_graph,
placements, n_keys_map):
"""
:param machine_graph:\
The machine graph to allocate the routing info for
:type machine_graph:\
:py:class:`pacman.model.graphs.machine.MachineGraph`
:param placements: The placements of the vertices
:type placements:\
:py:class:`pacman.model.placements.placements.Placements`
:param n_keys_map:\
A map between the edges and the number of keys required by the\
edges
:type n_keys_map:\
:py:class:`pacman.model.routing_info.AbstractMachinePartitionNKeysMap`
:return: The routing information
:rtype:\
:py:class:`pacman.model.routing_info.PartitionRoutingInfo`
:raise pacman.exceptions.PacmanRouteInfoAllocationException: \
If something goes wrong with the allocation
"""
# check that this algorithm supports the constraints put onto the
# partitions
self._application_graph = application_graph
self._graph_mapper = graph_mapper
self._machine_graph = machine_graph
self._placements = placements
self._n_keys_map = n_keys_map
check_algorithm_can_support_constraints(
constrained_vertices=machine_graph.outgoing_edge_partitions,
supported_constraints=[ContiguousKeyRangeContraint],
abstract_constraint_type=AbstractKeyAllocatorConstraint)
if self._caluculate_zones() != 1:
raise NotImplementedError()
return self._simple_allocate()
def _caluculate_zones(self):
progress = ProgressBar(
self._application_graph.n_vertices, "Calculating zones")
self._max_app_keys_bites = 0
source_zones = 0
max_partitions = 0
self._key_bites_per_app = dict()
for app_vertex in progress.over(self._application_graph.vertices):
app_max_partitions = 0
machine_vertices = self._graph_mapper.get_machine_vertices(
app_vertex)
max_keys = 0
for vertex in machine_vertices:
partitions = self._machine_graph.\
get_outgoing_edge_partitions_starting_at_vertex(vertex)
app_max_partitions = max(app_max_partitions, len(partitions))
# Do we need to check type here
for partition in partitions:
if partition.traffic_type == EdgeTrafficType.MULTICAST:
n_keys = self._n_keys_map.n_keys_for_partition(
partition)
max_keys = max(max_keys, n_keys)
if max_keys > 0:
max_partitions = max(max_partitions, app_max_partitions)
source_zones += app_max_partitions
key_bites = self._bites_needed(max_keys)
machine_bites = self._bites_needed(len(machine_vertices))
self._max_app_keys_bites = max(
self._max_app_keys_bites, machine_bites + key_bites)
self._key_bites_per_app[app_vertex] = key_bites
source_bites = self._bites_needed(source_zones)
if source_bites + self._max_app_keys_bites > KEY_SIZE:
raise PacmanRouteInfoAllocationException(
"Unable to use ZonedRoutingInfoAllocator please select a "
"different allocator as it needs {} + {} bites".format(
source_bites, self._max_app_keys_bites))
return max_partitions
def _simple_allocate(self):
progress = ProgressBar(
self._application_graph.n_vertices, "Allocating routing keys")
routing_infos = RoutingInfo()
by_app_vertex = dict()
app_mask = 2 ** 32 - 2 ** self._max_app_keys_bites
for source_index, app_vertex in progress.over(
enumerate(self._application_graph.vertices)):
machine_vertices = self._graph_mapper.get_machine_vertices(
app_vertex)
if app_vertex in self._key_bites_per_app:
key_bites = self._key_bites_per_app[app_vertex]
for machine_index, vertex in enumerate(machine_vertices):
partitions = self._machine_graph. \
get_outgoing_edge_partitions_starting_at_vertex(vertex)
partition = partitions.peek()
if partition.traffic_type == EdgeTrafficType.MULTICAST:
mask = 2 ** 32 - 2 ** key_bites
key = source_index << self._max_app_keys_bites | \
machine_index << key_bites
key_and_mask = BaseKeyAndMask(base_key=key, mask=mask)
info = PartitionRoutingInfo([key_and_mask], partition)
routing_infos.add_partition_info(info)
app_key = source_index << self._max_app_keys_bites
by_app_vertex[app_vertex] = BaseKeyAndMask(
base_key=app_key, mask=app_mask)
return routing_infos, by_app_vertex
def _bites_needed(self, size):
return math.ceil(math.log(size, 2))