Source code for pacman.operations.algorithm_reports.routing_compression_checker_report

# 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 collections import OrderedDict
import logging
import os
from spinn_utilities.log import FormatAdapter
from spinn_utilities.progress_bar import ProgressBar
from pacman.exceptions import PacmanRoutingException
from pacman.operations.algorithm_reports import reports

logger = FormatAdapter(logging.getLogger(__name__))
WILDCARD = "*"
LINE_FORMAT = "0x{:08X} 0x{:08X} 0x{:08X} {: <7s} {}\n"


[docs]def codify(route, length=32): """ This method discovers all the routing keys covered by this route. Starts of with the assumption that the key is always covered. Whenever a mask bit is zero the list of covered keys is doubled to\ include both the key with a zero and a one at that place. :param route: single routing Entry :type route: :py:class:`spinn_machine.MulticastRoutingEntry` :param length: length in bits of the key and mask (defaults to 32) :type length: int :return: set of routing_keys covered by this route :rtype: str """ mask = route.mask key = route.routing_entry_key code = "" # Check each bit in the mask for i in range(length): bit_value = 2**i # If the mask bit is zero then both zero and one acceptable if mask & bit_value: code = str(int(key & bit_value != 0)) + code else: # Safety key 1 with mask 0 is an error assert key & bit_value == 0, \ "Bit {} on the mask:{} is 0 but 1 in the key:{}".format( i, bin(mask), bin(key)) code = WILDCARD + code return code
[docs]def codify_table(table, length=32): code_dict = OrderedDict() for route in table.multicast_routing_entries: code_dict[codify(route, length)] = route return code_dict
[docs]def covers(o_code, c_code): if o_code == c_code: return True for o_char, c_char in zip(o_code, c_code): if o_char == "1" and c_char == "0": return False if o_char == "0" and c_char == "1": return False # o_char = c_char or either wildcard is some cover return True
[docs]def calc_remainders(o_code, c_code): if o_code == c_code: # "" = "" so also the terminator case return [] remainders = [] for tail in calc_remainders(o_code[1:], c_code[1:]): remainders.append(o_code[0] + tail) if o_code[0] == WILDCARD: if c_code[0] == "0": remainders.append("1" + o_code[1:]) if c_code[0] == "1": remainders.append("0" + o_code[1:]) return remainders
[docs]def compare_route(o_route, compressed_dict, o_code=None, start=0, f=None): if o_code is None: o_code = codify(o_route) keys = list(compressed_dict.keys()) for i in range(start, len(keys)): c_code = keys[i] if covers(o_code, c_code): c_route = compressed_dict[c_code] if f is not None: f.write("\t\t{}\n".format(reports.format_route(c_route))) if o_route.processor_ids != c_route.processor_ids: if set(o_route.processor_ids) != set(c_route.processor_ids): raise PacmanRoutingException( "Compressed route {} covers original route {} but has " "a different processor_ids.".format(c_route, o_route)) if o_route.link_ids != c_route.link_ids: if set(o_route.link_ids) != set(c_route.link_ids): raise PacmanRoutingException( "Compressed route {} covers original route {} but has " "a different link_ids.".format(c_route, o_route)) if not o_route.defaultable and c_route.defaultable: if o_route == c_route: raise PacmanRoutingException( "Compressed route {} while original route {} but has " "a different defaultable value.".format( c_route, o_route)) else: compare_route(o_route, compressed_dict, o_code=o_code, start=i + 1, f=f) else: remainders = calc_remainders(o_code, c_code) for remainder in remainders: compare_route(o_route, compressed_dict, o_code=remainder, start=i + 1, f=f) return if not o_route.defaultable: # print("No route found {}".format(o_route)) raise PacmanRoutingException("No route found {}".format(o_route))
[docs]def compare_tables(original, compressed): """ Compares the two tables without generating any out :param original: The orginal routing tables :param compressed: The compressed routing tables. Which will be considered in order. :raises: PacmanRoutingException if there is any error """ compressed_dict = codify_table(compressed) for o_route in original.multicast_routing_entries: compare_route(o_route, compressed_dict)
[docs]def generate_routing_compression_checker_report( report_folder, routing_tables, compressed_routing_tables): """ Make a full report of how the compressed covers all routes in the\ and uncompressed routing table :param report_folder: the folder to store the resulting report :param routing_tables: the original routing tables :param compressed_routing_tables: the compressed routing tables :rtype: None """ file_name = os.path.join( report_folder, "routing_compression_checker_report.rpt") try: with open(file_name, "w") as f: progress = ProgressBar( routing_tables.routing_tables, "Generating routing compression checker report") f.write("If this table did not raise an exception compression " "was fully checked. \n\n") f.write("The format is:\n" "Chip x, y\n" "\t Uncompressed Route\n" "\t\tCompressed Route\n\n") for original in progress.over(routing_tables.routing_tables): x = original.x y = original.y f.write("Chip: X:{} Y:{} \n".format(x, y)) compressed_table = compressed_routing_tables.\ get_routing_table_for_chip(x, y) compressed_dict = codify_table(compressed_table) for o_route in original.multicast_routing_entries: f.write("\t{}\n".format(reports.format_route(o_route))) compare_route(o_route, compressed_dict, f=f) except IOError: logger.exception("Generate_router_comparison_reports: Can't open file" " {} for writing.", file_name)