Source code for spinn_front_end_common.interface.provenance.provides_provenance_data_from_machine_impl

# 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/>.

import struct
from enum import Enum
from six import add_metaclass
from spinn_utilities.abstract_base import AbstractBase, abstractproperty
from data_specification.utility_calls import get_region_base_address_offset
from .abstract_provides_provenance_data_from_machine import (
    AbstractProvidesProvenanceDataFromMachine)
from spinn_front_end_common.utilities.utility_objs import ProvenanceDataItem
from spinn_front_end_common.utilities.constants import BYTES_PER_WORD

_ONE_WORD = struct.Struct("<I")


[docs]@add_metaclass(AbstractBase) class ProvidesProvenanceDataFromMachineImpl( AbstractProvidesProvenanceDataFromMachine): """ An implementation that gets provenance data from a region of ints on\ the machine. """ __slots__ = ()
[docs] class PROVENANCE_DATA_ENTRIES(Enum): """entries for the provenance data generated by models using provides\ provenance vertex""" TRANSMISSION_EVENT_OVERFLOW = 0 CALLBACK_QUEUE_OVERLOADED = 1 DMA_QUEUE_OVERLOADED = 2 TIMER_TIC_HAS_OVERRUN = 3 MAX_NUMBER_OF_TIMER_TIC_OVERRUN = 4
NUM_PROVENANCE_DATA_ENTRIES = len(PROVENANCE_DATA_ENTRIES) @abstractproperty def _provenance_region_id(self): """ :return: provenance_region_id """ @abstractproperty def _n_additional_data_items(self): """ :return: n_additional_data_items """
[docs] def reserve_provenance_data_region(self, spec): spec.reserve_memory_region( self._provenance_region_id, self.get_provenance_data_size(self._n_additional_data_items), label="Provenance", empty=True)
[docs] @staticmethod def get_provenance_data_size(n_additional_data_items): return ( (ProvidesProvenanceDataFromMachineImpl.NUM_PROVENANCE_DATA_ENTRIES + n_additional_data_items) * BYTES_PER_WORD)
def _get_provenance_region_address(self, transceiver, placement): # Get the App Data for the core app_data_base_address = transceiver.get_cpu_information_from_core( placement.x, placement.y, placement.p).user[0] # Get the provenance region base address base_address_offset = get_region_base_address_offset( app_data_base_address, self._provenance_region_id) base_address = transceiver.read_memory( placement.x, placement.y, base_address_offset, BYTES_PER_WORD) return _ONE_WORD.unpack(base_address)[0] def _read_provenance_data(self, transceiver, placement): provenance_address = self._get_provenance_region_address( transceiver, placement) data = transceiver.read_memory( placement.x, placement.y, provenance_address, self.get_provenance_data_size(self._n_additional_data_items)) return struct.unpack_from("<{}I".format( self.NUM_PROVENANCE_DATA_ENTRIES + self._n_additional_data_items), data) @staticmethod def _get_placement_details(placement): label = placement.vertex.label x = placement.x y = placement.y p = placement.p names = ["{}_{}_{}_{}".format(x, y, p, label)] return label, x, y, p, names @staticmethod def _add_name(names, name): new_names = list(names) new_names.append(name) return new_names @staticmethod def _add_names(names, extra_names): new_names = list(names) new_names.extend(extra_names) return new_names def _read_basic_provenance_items(self, provenance_data, placement): transmission_event_overflow = provenance_data[ self.PROVENANCE_DATA_ENTRIES.TRANSMISSION_EVENT_OVERFLOW.value] callback_queue_overloaded = provenance_data[ self.PROVENANCE_DATA_ENTRIES.CALLBACK_QUEUE_OVERLOADED.value] dma_queue_overloaded = provenance_data[ self.PROVENANCE_DATA_ENTRIES.DMA_QUEUE_OVERLOADED.value] number_of_times_timer_tic_over_ran = provenance_data[ self.PROVENANCE_DATA_ENTRIES.TIMER_TIC_HAS_OVERRUN.value] max_number_of_times_timer_tic_over_ran = provenance_data[ self.PROVENANCE_DATA_ENTRIES.MAX_NUMBER_OF_TIMER_TIC_OVERRUN.value] # create provenance data items for returning label, x, y, p, names = self._get_placement_details(placement) data_items = list() data_items.append(ProvenanceDataItem( self._add_name(names, "Times_the_transmission_of_spikes_overran"), transmission_event_overflow, report=transmission_event_overflow != 0, message=( "The transmission buffer for {} on {}, {}, {} was blocked " "on {} occasions. This is often a sign that the system is " "experiencing back pressure from the communication fabric. " "Please either: " "1. spread the load over more cores, " "2. reduce your peak transmission load," "3. adjust your mapping algorithm.".format( label, x, y, p, transmission_event_overflow)))) data_items.append(ProvenanceDataItem( self._add_name(names, "Times_the_callback_queue_was_overloaded"), callback_queue_overloaded, report=callback_queue_overloaded != 0, message=( "The callback queue for {} on {}, {}, {} overloaded on {} " "occasions. This is often a sign that the system is running " "too quickly for the number of neurons per core. Please " "increase the machine time step or time_scale_factor or " "decrease the number of neurons per core.".format( label, x, y, p, callback_queue_overloaded)))) data_items.append(ProvenanceDataItem( self._add_name(names, "Times_the_dma_queue_was_overloaded"), dma_queue_overloaded, report=dma_queue_overloaded != 0, message=( "The DMA queue for {} on {}, {}, {} overloaded on {} " "occasions. This is often a sign that the system is running " "too quickly for the number of neurons per core. Please " "increase the machine time step or time_scale_factor or " "decrease the number of neurons per core.".format( label, x, y, p, dma_queue_overloaded)))) data_items.append(ProvenanceDataItem( self._add_name(names, "Times_the_timer_tic_over_ran"), number_of_times_timer_tic_over_ran, report=number_of_times_timer_tic_over_ran != 0, message=( "A Timer tick callback was still executing when the next " "timer tick callback was fired off for {} on {}, {}, {}, {} " "times. This is a sign of the system being overloaded and " "therefore the results are likely incorrect. Please increase " "the machine time step or time_scale_factor or decrease the " "number of neurons per core".format( label, x, y, p, number_of_times_timer_tic_over_ran)))) data_items.append(ProvenanceDataItem( self._add_name(names, "max_number_of_times_timer_tic_over_ran"), max_number_of_times_timer_tic_over_ran, report=max_number_of_times_timer_tic_over_ran > 4, message=( "The timer for {} on {}, {}, {} fell behind by up to {} " "ticks. This is a sign of the system being overloaded and " "therefore the results are likely incorrect. Please increase " "the machine time step or time_scale_factor or decrease the " "number of neurons per core".format( label, x, y, p, max_number_of_times_timer_tic_over_ran)))) return data_items def _get_remaining_provenance_data_items(self, provenance_data): return provenance_data[self.NUM_PROVENANCE_DATA_ENTRIES:]
[docs] def get_provenance_data_from_machine(self, transceiver, placement): provenance_data = self._read_provenance_data( transceiver, placement) return self._read_basic_provenance_items(provenance_data, placement)