def _create_message_to_send(self, size, vertex, region): """ Creates a single message to send with the given boundaries. :param size: The number of bytes available for the whole packet :type size: int :param vertex: The vertex to get the keys from :type vertex:\ :py:class:`spynnaker.pyNN.models.abstract_models.buffer_models.abstract_sends_buffers_from_host.AbstractSendsBuffersFromHost` :param region: The region of the vertex to get keys from :type region: int :return: A new message, or None if no keys can be added :rtype: None or\ :py:class:`spinnman.messages.eieio.data_messages.eieio_32bit.eieio_32bit_timed_payload_prefix_data_message.EIEIO32BitTimedPayloadPrefixDataMessage` """ # If there are no more messages to send, return None if not vertex.is_next_timestamp(region): return None # Create a new message next_timestamp = vertex.get_next_timestamp(region) message = EIEIO32BitTimedPayloadPrefixDataMessage(next_timestamp) # If there is no room for the message, return None if message.size + _N_BYTES_PER_KEY > size: return None # Add keys up to the limit bytes_to_go = size - message.size while (bytes_to_go >= _N_BYTES_PER_KEY and vertex.is_next_key(region, next_timestamp)): key = vertex.get_next_key(region) message.add_key(key) bytes_to_go -= _N_BYTES_PER_KEY if self._write_reload_files: self._reload_buffer_file[(vertex, region)].write( "{}:{}\n".format(next_timestamp, key)) return message
def _read_32_bit_message(prefix, payload_base, prefix_type, is_time, data, offset, eieio_header): """ Return a packet containing 32 bit elements """ if payload_base is None: if prefix is None: return EIEIO32BitDataMessage(eieio_header.count, data, offset) elif prefix_type == EIEIOPrefix.LOWER_HALF_WORD: return EIEIO32BitLowerKeyPrefixDataMessage(prefix, eieio_header.count, data, offset) elif prefix_type == EIEIOPrefix.UPPER_HALF_WORD: return EIEIO32BitUpperKeyPrefixDataMessage(prefix, eieio_header.count, data, offset) elif payload_base is not None and not is_time: if prefix is None: return EIEIO32BitPayloadPrefixDataMessage(payload_base, eieio_header.count, data, offset) elif prefix_type == EIEIOPrefix.LOWER_HALF_WORD: return EIEIO32BitPayloadPrefixLowerKeyPrefixDataMessage( prefix, payload_base, eieio_header.count, data, offset) elif prefix_type == EIEIOPrefix.UPPER_HALF_WORD: return EIEIO32BitPayloadPrefixUpperKeyPrefixDataMessage( prefix, payload_base, eieio_header.count, data, offset) elif payload_base is not None and is_time: if prefix is None: return EIEIO32BitTimedPayloadPrefixDataMessage( payload_base, eieio_header.count, data, offset) elif prefix_type == EIEIOPrefix.LOWER_HALF_WORD: return EIEIO32BitTimedPayloadPrefixLowerKeyPrefixDataMessage( prefix, payload_base, eieio_header.count, data, offset) elif prefix_type == EIEIOPrefix.UPPER_HALF_WORD: return EIEIO32BitTimedPayloadPrefixUpperKeyPrefixDataMessage( prefix, payload_base, eieio_header.count, data, offset) return EIEIOWithoutPayloadDataMessage(eieio_header, data, offset)
def _send_initial_messages(self, vertex, region, progress_bar): """ Send the initial set of messages :param vertex: The vertex to get the keys from :type vertex:\ :py:class:`spynnaker.pyNN.models.abstract_models.buffer_models.abstract_sends_buffers_from_host.AbstractSendsBuffersFromHost` :param region: The region to get the keys from :type region: int :return: A list of messages :rtype: list of\ :py:class:`spinnman.messages.eieio.data_messages.eieio_32bit.eieio_32bit_timed_payload_prefix_data_message.EIEIO32BitTimedPayloadPrefixDataMessage` """ # Get the vertex load details # region_base_address = self._locate_region_address(region, vertex) region_base_address = \ helpful_functions.locate_memory_region_for_placement( self._placements.get_placement_of_subvertex(vertex), region, self._transceiver) placement = self._placements.get_placement_of_subvertex(vertex) # Add packets until out of space sent_message = False bytes_to_go = vertex.get_region_buffer_size(region) if bytes_to_go % 2 != 0: raise exceptions.SpinnFrontEndException( "The buffer region of {} must be divisible by 2".format( vertex)) all_data = "" if vertex.is_empty(region): sent_message = True else: min_size_of_packet = \ EIEIO32BitTimedPayloadPrefixDataMessage.get_min_packet_length() while (vertex.is_next_timestamp(region) and bytes_to_go > min_size_of_packet): space_available = min(bytes_to_go, 280) next_message = self._create_message_to_send( space_available, vertex, region) if next_message is None: break # Write the message to the memory data = next_message.bytestring all_data += data sent_message = True # Update the positions bytes_to_go -= len(data) progress_bar.update(len(data)) if not sent_message: raise exceptions.BufferableRegionTooSmall( "The buffer size {} is too small for any data to be added for" " region {} of vertex {}".format(bytes_to_go, region, vertex)) # If there are no more messages and there is space, add a stop request if (not vertex.is_next_timestamp(region) and bytes_to_go >= EventStopRequest.get_min_packet_length()): data = EventStopRequest().bytestring # logger.debug( # "Writing stop message of {} bytes to {} on {}, {}, {}".format( # len(data), hex(region_base_address), # placement.x, placement.y, placement.p)) all_data += data bytes_to_go -= len(data) progress_bar.update(len(data)) self._sent_messages[vertex] = BuffersSentDeque( region, sent_stop_message=True) # If there is any space left, add padding if bytes_to_go > 0: padding_packet = PaddingRequest() n_packets = bytes_to_go / padding_packet.get_min_packet_length() data = padding_packet.bytestring data *= n_packets all_data += data # Do the writing all at once for efficiency self._transceiver.write_memory(placement.x, placement.y, region_base_address, all_data)
from spinn_front_end_common.interface.buffer_management.storage_objects.\ end_buffering_state import EndBufferingState # general imports import struct import threading import logging import traceback import os import re logger = logging.getLogger(__name__) # The minimum size of any message - this is the headers plus one entry _MIN_MESSAGE_SIZE = ( EIEIO32BitTimedPayloadPrefixDataMessage.get_min_packet_length()) # The number of bytes in each key to be sent _N_BYTES_PER_KEY = EIEIOType.KEY_32_BIT.key_bytes # @UndefinedVariable class BufferManager(object): """ Manager of send buffers """ def __init__(self, placements, tags, transceiver, write_reload_files, application_folder_path): """ :param placements: The placements of the vertices :type placements:\ :py:class:`pacman.model.placements.placements.Placements`
def _send_initial_messages(self, vertex, region, progress_bar): """ Send the initial set of messages :param vertex: The vertex to get the keys from :type vertex:\ :py:class:`spynnaker.pyNN.models.abstract_models.buffer_models.abstract_sends_buffers_from_host_partitioned_vertex.AbstractSendsBuffersFromHostPartitionedVertex` :param region: The region to get the keys from :type region: int :return: A list of messages :rtype: list of\ :py:class:`spinnman.messages.eieio.data_messages.eieio_32bit.eieio_32bit_timed_payload_prefix_data_message.EIEIO32BitTimedPayloadPrefixDataMessage` """ # Get the vertex load details region_base_address = self._locate_region_address(region, vertex) placement = self._placements.get_placement_of_subvertex(vertex) # Add packets until out of space sent_message = False bytes_to_go = vertex.get_region_buffer_size(region) if bytes_to_go % 2 != 0: raise exceptions.SpinnFrontEndException( "The buffer region of {} must be divisible by 2".format( vertex)) all_data = "" if vertex.is_empty(region): sent_message = True else: min_size_of_packet = \ EIEIO32BitTimedPayloadPrefixDataMessage.get_min_packet_length() while (vertex.is_next_timestamp(region) and bytes_to_go > min_size_of_packet): space_available = min(bytes_to_go, 280) next_message = self._create_message_to_send( space_available, vertex, region) if next_message is None: break # Write the message to the memory data = next_message.bytestring all_data += data sent_message = True # Update the positions bytes_to_go -= len(data) progress_bar.update(len(data)) if not sent_message: raise exceptions.BufferableRegionTooSmall( "The buffer size {} is too small for any data to be added for" " region {} of vertex {}".format(bytes_to_go, region, vertex)) # If there are no more messages and there is space, add a stop request if (not vertex.is_next_timestamp(region) and bytes_to_go >= EventStopRequest.get_min_packet_length()): data = EventStopRequest().bytestring # logger.debug( # "Writing stop message of {} bytes to {} on {}, {}, {}".format( # len(data), hex(region_base_address), # placement.x, placement.y, placement.p)) all_data += data bytes_to_go -= len(data) progress_bar.update(len(data)) self._sent_messages[vertex] = BuffersSentDeque( region, sent_stop_message=True) # If there is any space left, add padding if bytes_to_go > 0: padding_packet = PaddingRequest() n_packets = bytes_to_go / padding_packet.get_min_packet_length() data = padding_packet.bytestring data *= n_packets all_data += data # Do the writing all at once for efficiency self._transceiver.write_memory( placement.x, placement.y, region_base_address, all_data)