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_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_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
]