Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
578 changes: 110 additions & 468 deletions c_common/models/system_models/src/data_speed_up_packet_gatherer.c

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions c_common/models/system_models/src/extra_monitor_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,9 @@ static inline void data_in_process_address(uint data) {
data_in_first_write_address = data_in_write_address = (address_t) data;
}

static const uint SDRAM_TOP_UNBUF = SDRAM_BASE_UNBUF + SDRAM_SIZE;
static const uint SDRAM_TOP_BUF = SDRAM_TOP_UNBUF + SDRAM_SIZE;

//! \brief Writes a word in a stream and advances the write pointer.
//! \param[in] data: The word to write
static inline void data_in_process_data(uint data) {
Expand All @@ -1194,6 +1197,12 @@ static inline void data_in_process_data(uint data) {
io_printf(IO_BUF, "[ERROR] Write address not set when write data received!\n");
rt_error(RTE_SWERR);
}
uint data_addr = (uint) data_in_write_address;
if (((data_addr < SDRAM_BASE_BUF) || (data_addr >= SDRAM_TOP_BUF))
&& ((data_addr < SDRAM_BASE_UNBUF) || (data_addr >= SDRAM_TOP_UNBUF))) {
io_printf(IO_BUF, "[ERROR] Write address 0x%08x is outside SDRAM\n", data_addr);
rt_error(RTE_SWERR);
}
*data_in_write_address = data;
data_in_write_address++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
# limitations under the License.

import logging
from functools import partial
from typing import Any, Callable

import numpy
from typing_extensions import TypeAlias
import numpy

from spinn_utilities.config_holder import get_config_bool
from spinn_utilities.progress_bar import ProgressBar
Expand All @@ -32,6 +32,9 @@
from spinn_front_end_common.utilities.emergency_recovery import (
emergency_recover_states_from_failure)
from spinn_front_end_common.interface.ds import DsSqlliteDatabase
from spinn_front_end_common.utilities.iobuf_extractor import IOBufExtractor
from spinn_front_end_common.utilities.scp import (
WriteMemoryUsingMulticastProcess)

logger = FormatAdapter(logging.getLogger(__name__))
_Writer: TypeAlias = Callable[[int, int, int, bytes], Any]
Expand Down Expand Up @@ -118,6 +121,12 @@ def load_data_specs(self, is_system: bool, uses_advanced_monitors: bool):
self.__java_app(uses_advanced_monitors)
else:
self.__python_load(is_system, uses_advanced_monitors)
if uses_advanced_monitors and get_config_bool(
"Reports", "write_advanced_monitor_iobuf"):
extractor = IOBufExtractor(
None, recovery_mode=True,
filename_template="system_iobuf_{}_{}_{}.txt")
extractor.extract_iobuf()
except: # noqa: E722
if uses_advanced_monitors:
emergency_recover_states_from_failure()
Expand All @@ -140,6 +149,8 @@ def __python_load(self, is_system: bool, uses_advanced_monitors: bool):
"""
if uses_advanced_monitors:
self.__set_router_timeouts()
write_memory_process = WriteMemoryUsingMulticastProcess(
FecDataView.get_scamp_connection_selector())

# create a progress bar for end users
with DsSqlliteDatabase() as ds_database:
Expand All @@ -165,7 +176,11 @@ def __python_load(self, is_system: bool, uses_advanced_monitors: bool):
for x, y, p, eth_x, eth_y in progress.over(core_infos):
if uses_advanced_monitors:
gatherer = FecDataView.get_gatherer_by_xy(eth_x, eth_y)
writer = gatherer.send_data_into_spinnaker
placement = FecDataView.get_placement_of_vertex(gatherer)
writer = partial(
write_memory_process.write_memory_from_bytearray,
placement.x, placement.y, placement.p)

written = self.__python_load_core(ds_database, x, y, p, writer)
to_write = ds_database.get_memory_to_write(x, y, p)
if written != to_write:
Expand Down
2 changes: 1 addition & 1 deletion spinn_front_end_common/interface/java_caller.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ def load_app_data_specification(self, use_monitors: bool) -> None:
"""
if use_monitors:
result = self._run_java(
'dse_app_mon', self._placement_json, self._machine_json(),
'dse_app_mon_mc', self._placement_json, self._machine_json(),
FecDataView.get_ds_database_path(),
FecDataView.get_run_dir_path())
else:
Expand Down
1 change: 1 addition & 0 deletions spinn_front_end_common/interface/spinnaker.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ write_bit_field_compressor_report = False
write_drift_report_start = False
write_drift_report_end = False
write_text_specs = False
write_advanced_monitor_iobuf = False

max_reports_kept = 10
remove_errored_folders = False
Expand Down
5 changes: 4 additions & 1 deletion spinn_front_end_common/utilities/scp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
from .load_mc_routes_process import LoadMCRoutesProcess
from .reinjector_control_process import ReinjectorControlProcess
from .update_runtime_process import UpdateRuntimeProcess
from .write_memory_using_multicast_process import (
WriteMemoryUsingMulticastProcess)

__all__ = (
"ClearIOBUFProcess",
"LoadMCRoutesProcess",
"ReinjectorControlProcess",
"UpdateRuntimeProcess")
"UpdateRuntimeProcess",
"WriteMemoryUsingMulticastProcess")
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright (c) 2017 The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Optional, Tuple
import numpy
from numpy import uint8, uint32
from spinnman.constants import UDP_MESSAGE_MAX_SIZE
from spinnman.processes import AbstractMultiConnectionProcess
from spinnman.messages.scp.impl import CheckOKResponse
from spinn_front_end_common.utilities.utility_objs.\
extra_monitor_scp_messages import SendMCDataMessage

_UNSIGNED_WORD = 0xFFFFFFFF


class WriteMemoryUsingMulticastProcess(
AbstractMultiConnectionProcess[CheckOKResponse]):
"""
How to send messages to write data using multicast
"""
__slots__ = ()

def write_memory_from_bytearray(
self, x: int, y: int, p: int, target_x: int, target_y: int,
base_address: int, data: bytes, data_offset: int = 0,
n_bytes: Optional[int] = None,
get_sum: bool = False) -> Tuple[int, int]:
"""
Write memory using multicast over the advanced monitor connection.

:param int x:
The x-coordinate of the chip where the advanced monitor is
:param int y:
The y-coordinate of the chip where the advanced monitor is
:param int p:
The processor ID of the chip where the advanced monitor is
:param int target_x:
The x-coordinate of the chip where the memory is to be written to
:param int target_y:
The y-coordinate of the chip where the memory is to be written to
:param int base_address:
The address in SDRAM where the region of memory is to be written
:param bytes data: The data to write.
:param int n_bytes:
The amount of data to be written in bytes. If not specified,
length of data is used.
:param int data_offset: The offset from which the valid data begins
:param bool get_sum: whether to return a checksum or 0
:return: The number of bytes written, the checksum (0 if get_sum=False)
:rtype: int, int
"""
offset = 0
if n_bytes is None:
n_bytes_to_write = len(data)
else:
n_bytes_to_write = n_bytes
n_bytes_written = n_bytes_to_write
with self._collect_responses():
while n_bytes_to_write > 0:
bytes_to_send = min(n_bytes_to_write, UDP_MESSAGE_MAX_SIZE)
data_array = data[data_offset:data_offset + bytes_to_send]

self._send_request(
SendMCDataMessage(x, y, p, target_x, target_y,
base_address + offset, data_array))

n_bytes_to_write -= bytes_to_send
offset += bytes_to_send
data_offset += bytes_to_send
if not get_sum:
return n_bytes_written, 0
np_data = numpy.array(data, dtype=uint8)
np_sum = int(numpy.sum(np_data.view(uint32), dtype=uint32))
return n_bytes_written, np_sum & _UNSIGNED_WORD
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .set_reinjection_packet_types_message import (
SetReinjectionPacketTypesMessage)
from .set_router_timeout_message import SetRouterTimeoutMessage
from .send_mc_data_message import SendMCDataMessage

__all__ = (
"ClearReinjectionQueueMessage",
Expand All @@ -30,4 +31,5 @@
"LoadSystemMCRoutesMessage",
"ResetCountersMessage",
"SetReinjectionPacketTypesMessage",
"SetRouterTimeoutMessage")
"SetRouterTimeoutMessage",
"SendMCDataMessage")
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright (c) 2017 The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from spinn_utilities.overrides import overrides
from spinnman.messages.scp import SCPRequestHeader
from spinnman.messages.scp.abstract_messages import AbstractSCPRequest
from spinnman.messages.sdp import SDPFlag, SDPHeader
from spinnman.messages.scp.impl.check_ok_response import CheckOKResponse
from spinnman.messages.scp.enums import SCPCommand
from spinnman.model.enums import SDP_PORTS
from spinn_front_end_common.utilities.constants import BYTES_PER_WORD

X_SHIFT = 16


class SendMCDataMessage(AbstractSCPRequest[CheckOKResponse]):
"""
An SCP Request to write data using multicast.
"""

__slots__ = ()

def __init__(self, x: int, y: int, p: int, target_x: int, target_y: int,
target_address: int, data: bytes):
"""
:param int x: The x-coordinate of a chip, between 0 and 255
:param int y: The y-coordinate of a chip, between 0 and 255
:param int p:
The processor running the extra monitor vertex, between 0 and 17
"""
super().__init__(
SDPHeader(
flags=SDPFlag.REPLY_EXPECTED,
destination_port=(
SDP_PORTS.EXTRA_MONITOR_CORE_COPY_DATA_IN.value),
destination_cpu=p, destination_chip_x=x,
destination_chip_y=y),
SCPRequestHeader(
command=SCPCommand.CMD_WRITE),
argument_1=target_address,
argument_2=target_x << X_SHIFT | target_y,
argument_3=len(data) // BYTES_PER_WORD,
data=data)

@overrides(AbstractSCPRequest.get_scp_response)
def get_scp_response(self) -> CheckOKResponse:
return CheckOKResponse(
"write_over_multicast",
SCPCommand.CMD_WRITE)
Loading