Source code for pacman.operations.router_compressors.malloc_based_route_merger
# Copyright (c) 2017-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/>.
from spinn_utilities.progress_bar import ProgressBar
from spinn_machine import MulticastRoutingEntry
from pacman.model.routing_tables import (
MulticastRoutingTable, MulticastRoutingTables)
from pacman.exceptions import PacmanRoutingException
_32_BITS = 0xFFFFFFFF
[docs]class MallocBasedRouteMerger(object):
""" Routing table entry merging function, that merges based off a\
malloc memory style.
"""
__slots__ = []
def __call__(self, router_tables):
tables = MulticastRoutingTables()
progress = ProgressBar(
len(router_tables.routing_tables) * 2,
"Compressing Routing Tables")
# Create all masks without holes
allowed_masks = [_32_BITS - ((2 ** i) - 1) for i in range(33)]
# Check that none of the masks have "holes" e.g. 0xFFFF0FFF has a hole
for router_table in router_tables.routing_tables:
for entry in router_table.multicast_routing_entries:
if entry.mask not in allowed_masks:
raise PacmanRoutingException(
"Only masks without holes are allowed in tables for"
" MallocBasedRouteMerger (disallowed mask={})".format(
hex(entry.mask)))
for router_table in progress.over(router_tables.routing_tables):
new_table = self._merge_routes(router_table)
tables.add_routing_table(new_table)
n_entries = len([
entry for entry in new_table.multicast_routing_entries
if not entry.defaultable])
print("Reduced from {} to {}".format(
len(router_table.multicast_routing_entries),
n_entries))
if n_entries > 1023:
raise PacmanRoutingException(
"Cannot make table small enough: {} entries".format(
n_entries))
return tables
def _merge_routes(self, router_table):
merged_routes = MulticastRoutingTable(router_table.x, router_table.y)
# Order the routes by key
entries = sorted(
router_table.multicast_routing_entries,
key=lambda entry: entry.routing_entry_key)
# Find adjacent entries that can be merged
pos = 0
last_key_added = 0
while pos < len(entries):
links = entries[pos].link_ids
processors = entries[pos].processor_ids
next_pos = pos + 1
# Keep going until routes are not the same or too many keys are
# generated
base_key = int(entries[pos].routing_entry_key)
while (next_pos < len(entries) and
entries[next_pos].link_ids == links and
entries[next_pos].processor_ids == processors and
(base_key & entries[next_pos].routing_entry_key) >
last_key_added):
base_key = (
base_key & entries[next_pos].routing_entry_key)
next_pos += 1
next_pos -= 1
# print("Pre decision", hex(base_key))
# If there is something to merge, merge it if possible
merge_done = False
if next_pos != pos:
# print("At merge, base_key =", hex(base_key))
# Find the next nearest power of 2 to the number of keys
# that will be covered
last_key = (
entries[next_pos].routing_entry_key +
(~entries[next_pos].mask & _32_BITS))
n_keys = (1 << (last_key - base_key).bit_length()) - 1
n_keys_mask = ~n_keys & _32_BITS
base_key = base_key & n_keys_mask
if ((base_key + n_keys) >= last_key and
base_key > last_key_added and
(next_pos + 1 >= len(entries) or
entries[pos].routing_entry_key + n_keys <
entries[next_pos + 1].routing_entry_key)):
last_key_added = base_key + n_keys
merged_routes.add_multicast_routing_entry(
MulticastRoutingEntry(
int(base_key), n_keys_mask,
processors, links, defaultable=False))
pos = next_pos
merge_done = True
if not merge_done:
merged_routes.add_multicast_routing_entry(entries[pos])
last_key_added = (
entries[pos].routing_entry_key +
(~entries[pos].mask & _32_BITS))
pos += 1
return merged_routes