Source code for spinn_front_end_common.interface.buffer_management.recording_utilities

from spinn_front_end_common.interface.buffer_management.storage_objects\
    import ChannelBufferState
from spinn_front_end_common.utilities.constants \
    import SARK_PER_MALLOC_SDRAM_USAGE, SDP_PORTS

from pacman.model.resources \
    import ResourceContainer, IPtagResource, SDRAMResource

import struct
import sys
import math

# The offset of the last sequence number field in bytes
_LAST_SEQUENCE_NUMBER_OFFSET = 4 * 6

# The offset of the memory addresses in bytes
_FIRST_REGION_ADDRESS_OFFSET = 4 * 7

# the number of data elements inside the recording region before
# recording regions sizes are stored.
_RECORDING_ELEMENTS_BEFORE_REGION_SIZES = 7

# The Buffer traffic type
TRAFFIC_IDENTIFIER = "BufferTraffic"


[docs]def get_recording_header_size(n_recorded_regions): """ Get the size of the data to be written for the recording header :param n_recorded_regions: The number of regions to be recorded """ # See recording.h/recording_initialise for data included in the header return (_RECORDING_ELEMENTS_BEFORE_REGION_SIZES + (2 * n_recorded_regions)) * 4
[docs]def get_recording_data_size(recorded_region_sizes): """ Get the size of the recorded data to be reserved :param recorded_region_sizes:\ A list of sizes of each region to be recorded.\ A size of 0 is acceptable. :rtype: int """ return ( # The total recording data size sum(recorded_region_sizes) + # The storage of the recording state (len(recorded_region_sizes) * ChannelBufferState.size_of_channel_state()) + # The SARK allocation of SDRAM overhead (len(recorded_region_sizes) * SARK_PER_MALLOC_SDRAM_USAGE))
[docs]def get_minimum_buffer_sdram( buffered_sdram_per_timestep, n_machine_time_steps=None, minimum_sdram_for_buffering=(1024 * 1024)): """ Get the minimum buffer SDRAM :param buffered_sdram_per_timestep:\ The maximum number of bytes to use per timestep of recording,\ per recorded region. Disabled regions can specify 0. :type buffered_sdram_per_timestep: list of int :param n_machine_time_steps:\ The number of machine time steps for the simulation. Can be None if\ use_auto_pause_and_resume is True :type n_machine_time_steps: int :param minimum_sdram_for_buffering:\ The minimum SDRAM to reserve per recorded region for buffering :type minimum_sdram_for_buffering: int :rtype: list of int """ # The minimum SDRAM for each region is: # - If the buffered_sdram_per_timestep for the region is > 0 and # n_machine_time_steps is defined then the minimum of the actual region # size and the minimum_sdram_for_buffering # - If the sdram is 0 then 0 # - If n_machine_time_steps is None then minimum_sdram_for_buffering return [ min(sdram * n_machine_time_steps, minimum_sdram_for_buffering) if sdram > 0 and n_machine_time_steps is not None else 0 if sdram == 0 else minimum_sdram_for_buffering for sdram in buffered_sdram_per_timestep ]
[docs]def get_recording_region_sizes( buffered_sdram_per_timestep, n_machine_time_steps=None, minimum_sdram_for_buffering=(1024 * 1024), maximum_sdram_for_buffering=None, use_auto_pause_and_resume=True): """ Get the size of each recording region to be passed in to\ get_recording_resources, based on the details of the simulation :param buffered_sdram_per_timestep:\ The maximum number of bytes to use per timestep of recording,\ per recorded region. Disabled regions can specify 0. :type buffered_sdram_per_timestep: list of int :param n_machine_time_steps:\ The number of machine time steps for the simulation. Can be None if\ use_auto_pause_and_resume is True :type n_machine_time_steps: int :param minimum_sdram_for_buffering:\ The minimum SDRAM to reserve per recorded region for buffering :type minimum_sdram_for_buffering: int :param maximum_sdram_for_buffering:\ The maximum size of each buffer, or None if no maximum :type maximum_sdram_for_buffering: None or list of int :param use_auto_pause_and_resume:\ True if automatic pause and resume is to be used for buffering :type use_auto_pause_and_resume: bool :rtype: list of int """ if use_auto_pause_and_resume: # If auto pause and resume is enabled, find the minimum sizes return get_minimum_buffer_sdram( buffered_sdram_per_timestep, n_machine_time_steps, minimum_sdram_for_buffering) else: # If auto pause and resume is disabled, use the actual region size return get_recorded_region_sizes( n_machine_time_steps, buffered_sdram_per_timestep, maximum_sdram_for_buffering)
[docs]def get_recording_resources( region_sizes, buffering_ip_address=None, buffering_port=None, notification_tag=None): """ Get the resources for recording :param region_sizes:\ A list of the sizes of each region. A size of 0 is acceptable to\ indicate an empty region :type region_sizes: list of int :param buffering_ip_address:\ The ip address to receive buffering messages on, or None if buffering\ is not in use :type buffering_ip_address: str :param buffering_port:\ The port to receive buffering messages on, or None if a port is to be\ assigned :type buffering_port: int :param notification_tag:\ The tag to send buffering messages with, or None to use a default tag :type notification_tag: int :rtype:\ :py:class:`pacman.model.resources.ResourceContainer` """ ip_tags = list() if buffering_ip_address is not None: ip_tags.append(IPtagResource( buffering_ip_address, buffering_port, True, notification_tag, TRAFFIC_IDENTIFIER )) # return the resources including the SDRAM requirements return ResourceContainer( iptags=ip_tags, sdram=SDRAMResource( get_recording_header_size(len(region_sizes)) + get_recording_data_size(region_sizes)))
[docs]def get_recorded_region_sizes( n_machine_time_steps, buffered_sdram_per_timestep, maximum_sdram_for_buffering=None): """ Get the size of each recording region to be passed in to\ get_recording_header_array :param n_machine_time_steps:\ The duration of the simulation segment in time steps :type n_machine_time_steps: int :param buffered_sdram_per_timestep:\ The maximum SDRAM used per timestep in bytes per region :type buffered_sdram_per_timestep: list of int :param maximum_sdram_for_buffering:\ The maximum size of each buffer, or None if no maximum :type maximum_sdram_for_buffering: None or list of int :rtype: list of int """ # The size of each buffer is the actual size needed for the number of # timesteps, or the maximum for buffering if a maximum is specified if n_machine_time_steps is None: data = [0 for _ in buffered_sdram_per_timestep] return data return [ n_machine_time_steps * sdram if (maximum_sdram_for_buffering is None or maximum_sdram_for_buffering[i] == 0 or (n_machine_time_steps * sdram) < maximum_sdram_for_buffering[i]) else maximum_sdram_for_buffering[i] for i, sdram in enumerate(buffered_sdram_per_timestep) ]
[docs]def get_recording_header_array( recorded_region_sizes, time_between_triggers=0, buffer_size_before_request=None, ip_tags=None, buffering_tag=None): """ Get data to be written for the recording header :param recorded_region_sizes:\ A list of sizes of each region to be recorded.\ A size of 0 is acceptable. :param time_between_triggers:\ The minimum time between requesting reads of any region :param buffer_size_before_request:\ The amount of buffer to fill before a read request is sent :param ip_tags: A list of ip tags to extract the buffer tag from :param buffering_tag: The tag to use for buffering requests :return: An array of values to be written as the header :rtype: list of int """ # Find the tag if required buffering_output_tag = 0 buffering_output_dest_x = 0 buffering_output_dest_y = 0 if buffering_tag is not None: buffering_output_tag = buffering_tag elif ip_tags is not None and len(ip_tags) > 0: buffering_output_tag = None for tag in ip_tags: if tag.traffic_identifier == TRAFFIC_IDENTIFIER: buffering_output_tag = tag.tag buffering_output_dest_x = tag.destination_x buffering_output_dest_y = tag.destination_y break if buffering_output_tag is None: raise Exception("Buffering tag not found") # See recording.h/recording_initialise for data included in the header data = list() # The parameters data.append(len(recorded_region_sizes)) data.append(buffering_output_tag) data.append(struct.unpack("<I", struct.pack( "<HH", buffering_output_dest_y, buffering_output_dest_x))[0]) data.append(SDP_PORTS.OUTPUT_BUFFERING_SDP_PORT.value) if buffer_size_before_request is not None: data.append(buffer_size_before_request) else: # If no buffer size before request, assume not buffering, so ensure # that the buffering will not be activated data.append(max(recorded_region_sizes) + 256) data.append(time_between_triggers) # The last sequence number (to be filled in by C code) data.append(0) # The pointers for each region (to be filled in by C code) data.extend([0 for _ in recorded_region_sizes]) # The size of the regions data.extend(recorded_region_sizes) return data
[docs]def get_last_sequence_number(placement, transceiver, recording_data_address): """ Read the last sequence number from the data :param placement: The placement from which to read the sequence number :param transceiver: The transceiver to use to read the sequence number :param recording_data_address:\ The address of the recording data from which to read the number :rtype: int """ data = transceiver.read_memory( placement.x, placement.y, recording_data_address + _LAST_SEQUENCE_NUMBER_OFFSET, 4) return struct.unpack_from("<I", data)[0]
[docs]def get_region_pointer(placement, transceiver, recording_data_address, region): """ Get a pointer to a recording region :param placement: The placement from which to read the pointer :param transceiver: The transceiver to use to read the pointer :param recording_data_address:\ The address of the recording data from which to read the pointer :param region: The index of the region to get the pointer of :rtype: int """ data = transceiver.read_memory( placement.x, placement.y, recording_data_address + _FIRST_REGION_ADDRESS_OFFSET + (region * 4), 4) return struct.unpack_from("<I", data)[0]
[docs]def get_n_timesteps_in_buffer_space(buffer_space, buffered_sdram_per_timestep): """ Get the number of time steps of data that can be stored in a given\ buffers space :param buffer_space: The space that will hold the data :type buffer_space: int :param buffered_sdram_per_timestep:\ The maximum SDRAM used by each region per timestep :type buffered_sdram_per_timestep: list of int :rtype: int """ total_per_timestep = sum(buffered_sdram_per_timestep) if total_per_timestep == 0: return sys.maxint return int(math.floor(buffer_space / total_per_timestep))
[docs]def get_recorded_region_ids(buffered_sdram_per_timestep): """ Get the ids of regions where recording is enabled :param buffered_sdram_per_timestep:\ The maximum SDRAM used by each region per timestep, where 0 indicates\ a disabled region :type buffered_sdram_per_timestep: list of int :rtype: list of int """ return [ i for i in range(len(buffered_sdram_per_timestep)) if buffered_sdram_per_timestep[i] > 0 ]