Source code for spinn_front_end_common.utility_models.command_sender_machine_vertex

from enum import Enum
from collections import Counter

from pacman.model.decorators import overrides
from pacman.model.graphs.machine import MachineVertex
from spinn_front_end_common.abstract_models import AbstractHasAssociatedBinary
from spinn_front_end_common.interface.provenance \
    import ProvidesProvenanceDataFromMachineImpl
from spinn_front_end_common.interface.simulation.simulation_utilities \
    import get_simulation_header_array
from spinn_front_end_common.utilities.constants \
    import SYSTEM_BYTES_REQUIREMENT
from spinn_front_end_common.utilities.utility_objs import ExecutableStartType


[docs]class CommandSenderMachineVertex( MachineVertex, ProvidesProvenanceDataFromMachineImpl, AbstractHasAssociatedBinary): # Regions for populations DATA_REGIONS = Enum( value="DATA_REGIONS", names=[('SYSTEM_REGION', 0), ('SETUP', 1), ('COMMANDS_WITH_ARBITRARY_TIMES', 2), ('COMMANDS_AT_START_RESUME', 3), ('COMMANDS_AT_STOP_PAUSE', 4), ('PROVENANCE_REGION', 5)]) # 4 for key, 4 for has payload, 4 for payload 4 for repeats, 4 for delays _COMMAND_WITH_PAYLOAD_SIZE = 20 # 4 for the time stamp _COMMAND_TIMESTAMP_SIZE = 4 # 4 for the int to represent the number of commands _N_COMMANDS_SIZE = 4 # bool for if the command has a payload (true = 1) _HAS_PAYLOAD = 1 # bool for if the command does not have a payload (false = 0) _HAS_NO_PAYLOAD = 0 # Setup data size (one word) _SETUP_DATA_SIZE = 4 # the number of malloc requests used by the dsg TOTAL_REQUIRED_MALLOCS = 5 # The name of the binary file BINARY_FILE_NAME = 'command_sender_multicast_source.aplx' def __init__( self, constraints, resources_required, label, commands_at_start_resume, commands_at_pause_stop, timed_commands): ProvidesProvenanceDataFromMachineImpl.__init__(self) MachineVertex.__init__(self, label, constraints) # container of different types of command self._timed_commands = timed_commands self._commands_at_start_resume = commands_at_start_resume self._commands_at_pause_stop = commands_at_pause_stop self._resources = resources_required @property @overrides(ProvidesProvenanceDataFromMachineImpl._provenance_region_id) def _provenance_region_id(self): return self.DATA_REGIONS.PROVENANCE_REGION.value @property @overrides(ProvidesProvenanceDataFromMachineImpl._n_additional_data_items) def _n_additional_data_items(self): return 0 @property @overrides(MachineVertex.resources_required) def resources_required(self): return self._resources
[docs] def generate_data_specification( self, spec, placement, machine_time_step, time_scale_factor, n_machine_time_steps): timed_commands_size = \ self.get_timed_commands_bytes(self._timed_commands) start_resume_commands_size = \ self.get_n_command_bytes(self._commands_at_start_resume) pause_stop_commands_size = \ self.get_n_command_bytes(self._commands_at_pause_stop) # reverse memory regions self._reserve_memory_regions( spec, timed_commands_size, start_resume_commands_size, pause_stop_commands_size, placement.vertex) # Write system region spec.comment("\n*** Spec for multicast source ***\n\n") spec.switch_write_focus( CommandSenderMachineVertex.DATA_REGIONS.SYSTEM_REGION.value) spec.write_array(get_simulation_header_array( self.get_binary_file_name(), machine_time_step, time_scale_factor)) # Write setup region # Find the maximum number of commands per timestep max_n_commands = 0 if len(self._timed_commands) > 0: counter = Counter(self._timed_commands) max_n_commands = counter.most_common(1)[0][1] max_n_commands = max([ max_n_commands, len(self._commands_at_start_resume), len(self._commands_at_pause_stop)]) time_between_commands = 0 if max_n_commands > 0: time_between_commands = ( (machine_time_step * time_scale_factor / 2) / max_n_commands) spec.switch_write_focus( CommandSenderMachineVertex.DATA_REGIONS.SETUP.value) spec.write_value(time_between_commands) # write commands spec.switch_write_focus( region=CommandSenderMachineVertex.DATA_REGIONS. COMMANDS_WITH_ARBITRARY_TIMES.value) # write commands to spec for timed commands self._write_timed_commands(self._timed_commands, spec) # write commands fired off during a start or resume spec.switch_write_focus( region=CommandSenderMachineVertex.DATA_REGIONS. COMMANDS_AT_START_RESUME.value) self._write_basic_commands(self._commands_at_start_resume, spec) # write commands fired off during a pause or end spec.switch_write_focus( region=CommandSenderMachineVertex.DATA_REGIONS. COMMANDS_AT_STOP_PAUSE.value) self._write_basic_commands(self._commands_at_pause_stop, spec) # End-of-Spec: spec.end_specification()
def _write_basic_commands(self, commands, spec): # number of commands spec.write_value(len(commands)) # write commands to region for command in commands: self._write_command(command, spec) def _write_timed_commands(self, timed_commands, spec): spec.write_value(len(timed_commands)) # write commands for command in timed_commands: spec.write_value(command.time) self._write_command(command, spec) @staticmethod def _write_command(command, spec): spec.write_value(command.key) spec.write_value(CommandSenderMachineVertex._HAS_PAYLOAD) spec.write_value(command.payload if command.is_payload else 0) spec.write_value(command.repeat) spec.write_value(command.delay_between_repeats) @staticmethod def _reserve_memory_regions( spec, time_command_size, start_command_size, end_command_size, vertex): """ Reserve SDRAM space for memory areas: 1) Area for information on what data to record 2) area for start commands 3) area for end commands """ spec.comment("\nReserving memory space for data regions:\n\n") # Reserve memory: spec.reserve_memory_region( region=CommandSenderMachineVertex.DATA_REGIONS.SYSTEM_REGION.value, size=SYSTEM_BYTES_REQUIREMENT, label='system') spec.reserve_memory_region( region=CommandSenderMachineVertex.DATA_REGIONS.SETUP.value, size=CommandSenderMachineVertex._SETUP_DATA_SIZE, label='setup') spec.reserve_memory_region( region=CommandSenderMachineVertex. DATA_REGIONS.COMMANDS_WITH_ARBITRARY_TIMES.value, size=time_command_size, label='commands with arbitrary times') spec.reserve_memory_region( region=CommandSenderMachineVertex. DATA_REGIONS.COMMANDS_AT_START_RESUME.value, size=start_command_size, label='commands with start resume times') spec.reserve_memory_region( region=CommandSenderMachineVertex. DATA_REGIONS.COMMANDS_AT_STOP_PAUSE.value, size=end_command_size, label='commands with stop pause times') vertex.reserve_provenance_data_region(spec)
[docs] @staticmethod def get_timed_commands_bytes(timed_commands): n_bytes = CommandSenderMachineVertex._N_COMMANDS_SIZE n_bytes += ( (CommandSenderMachineVertex._COMMAND_TIMESTAMP_SIZE + CommandSenderMachineVertex._COMMAND_WITH_PAYLOAD_SIZE) * len(timed_commands) ) return n_bytes
[docs] @staticmethod def get_n_command_bytes(commands): n_bytes = CommandSenderMachineVertex._N_COMMANDS_SIZE n_bytes += ( CommandSenderMachineVertex._COMMAND_WITH_PAYLOAD_SIZE * len(commands) ) return n_bytes
[docs] @overrides(AbstractHasAssociatedBinary.get_binary_file_name) def get_binary_file_name(self): """ Return a string representation of the models binary """ return self.BINARY_FILE_NAME
[docs] @overrides(AbstractHasAssociatedBinary.get_binary_start_type) def get_binary_start_type(self): return ExecutableStartType.USES_SIMULATION_INTERFACE
[docs] @staticmethod def get_number_of_mallocs_used_by_dsg(): return CommandSenderMachineVertex.TOTAL_REQUIRED_MALLOCS