-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #245 from SpiNNakerManchester/gfe_live_fixes
Gfe live fixes
- Loading branch information
Showing
7 changed files
with
413 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright (c) 2023 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. | ||
|
||
# If SPINN_DIRS is not defined, this is an error! | ||
ifndef SPINN_DIRS | ||
$(error SPINN_DIRS is not set. Please define SPINN_DIRS (possibly by running "source setup" in the spinnaker package folder)) | ||
endif | ||
|
||
APP = live_io | ||
SOURCES = live_io.c | ||
|
||
APP_OUTPUT_DIR := $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))/ | ||
|
||
include $(SPINN_DIRS)/make/local.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Copyright (c) 2023 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# Copyright (c) 2023 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. | ||
|
||
import os | ||
from time import sleep | ||
from random import randint | ||
from pacman.model.graphs.machine.machine_edge import MachineEdge | ||
from spinn_front_end_common.data.fec_data_view import FecDataView | ||
from spinn_front_end_common.utilities.connections import LiveEventConnection | ||
from spinn_front_end_common.utility_models import ( | ||
LivePacketGatherMachineVertex, ReverseIPTagMulticastSourceMachineVertex) | ||
from spinn_front_end_common.utilities.utility_objs import ( | ||
LivePacketGatherParameters) | ||
import spinnaker_graph_front_end as front_end | ||
from gfe_examples.live_io.live_io_vertex import LiveIOVertex | ||
|
||
n_receivers = 20 | ||
receiver_label = "Receiver" | ||
sender_label = "Sender" | ||
sender_partition = "Send" | ||
n_sender_keys = 32 | ||
sends_per_cycle = 10 | ||
lpg_label = "LPGReceiver" | ||
running = True | ||
|
||
|
||
def start_sending(label, c): | ||
# pylint: disable=unused-argument | ||
sleep(0.5) | ||
while running: | ||
for _ in range(sends_per_cycle): | ||
key = randint(0, n_sender_keys - 1) | ||
print(f"Sending {key}") | ||
c.send_event(sender_label, key) | ||
sleep(0.1) | ||
|
||
|
||
def end_sim(label, c): | ||
# pylint: disable=unused-argument | ||
global running | ||
running = False | ||
|
||
|
||
def receive(label, time, keys): | ||
print(f"Received from {label} at time {time}: {keys}") | ||
|
||
|
||
# Make a connection to send and receive data | ||
conn = LiveEventConnection( | ||
live_packet_gather_label=lpg_label, | ||
receive_labels=[receiver_label + f" {x}" for x in range(n_receivers)], | ||
send_labels=[sender_label], local_port=None) | ||
conn.add_start_resume_callback(sender_label, start_sending) | ||
conn.add_pause_stop_callback(sender_label, end_sim) | ||
for x in range(n_receivers): | ||
conn.add_receive_callback(receiver_label + f" {x}", receive) | ||
|
||
front_end.setup( | ||
n_chips_required=1, model_binary_folder=os.path.dirname(__file__)) | ||
front_end.add_socket_address(None, None, conn.local_port) | ||
|
||
# Add a sender | ||
sender = ReverseIPTagMulticastSourceMachineVertex( | ||
n_keys=n_sender_keys, label="Sender", | ||
injection_partition_id=sender_partition) | ||
front_end.add_machine_vertex_instance(sender) | ||
|
||
live_out = LivePacketGatherMachineVertex( | ||
LivePacketGatherParameters(tag=1, port=10000, hostname="localhost"), | ||
label=lpg_label) | ||
front_end.add_machine_vertex_instance(live_out) | ||
|
||
|
||
# Put LiveIOVertex on some cores | ||
for x in range(n_receivers): | ||
vertex = LiveIOVertex( | ||
n_keys=n_sender_keys, send_partition=sender_partition, | ||
label=receiver_label + f" {x}") | ||
front_end.add_machine_vertex_instance(vertex) | ||
front_end.add_machine_edge_instance( | ||
MachineEdge(sender, vertex), sender_partition) | ||
front_end.add_machine_edge_instance( | ||
MachineEdge(vertex, live_out), sender_partition) | ||
live_out.add_incoming_source(vertex, sender_partition) | ||
FecDataView.add_live_output_vertex(vertex, sender_partition) | ||
|
||
front_end.run(10000) | ||
|
||
front_end.stop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# Copyright (c) 2023 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 enum import IntEnum | ||
import logging | ||
from spinn_utilities.log import FormatAdapter | ||
from spinn_utilities.overrides import overrides | ||
from pacman.model.graphs.common import Slice | ||
from pacman.model.graphs.machine import MachineVertex | ||
from pacman.model.resources import ConstantSDRAM | ||
from spinn_front_end_common.utilities.constants import ( | ||
SYSTEM_BYTES_REQUIREMENT, BYTES_PER_WORD) | ||
from spinn_front_end_common.abstract_models.impl import ( | ||
MachineDataSpecableVertex) | ||
from spinn_front_end_common.data.fec_data_view import FecDataView | ||
from spinnaker_graph_front_end.utilities import SimulatorVertex | ||
|
||
logger = FormatAdapter(logging.getLogger(__name__)) | ||
N_KEY_DATA_BYTES = 3 * BYTES_PER_WORD | ||
|
||
|
||
class DataRegions(IntEnum): | ||
SYSTEM = 0 | ||
KEY_DATA = 1 | ||
|
||
|
||
class LiveIOVertex( | ||
SimulatorVertex, MachineDataSpecableVertex): | ||
|
||
def __init__(self, n_keys, send_partition="LiveOut", label=None): | ||
super().__init__(label, "live_io.aplx") | ||
self.__n_keys = n_keys | ||
self.__send_partition = send_partition | ||
self._vertex_slice = Slice(0, n_keys - 1) | ||
|
||
@property | ||
@overrides(MachineVertex.sdram_required) | ||
def sdram_required(self): | ||
return ConstantSDRAM( | ||
SYSTEM_BYTES_REQUIREMENT + N_KEY_DATA_BYTES) | ||
|
||
def get_n_keys_for_partition(self, partition_id): | ||
return self.__n_keys | ||
|
||
@overrides(MachineDataSpecableVertex.generate_machine_data_specification) | ||
def generate_machine_data_specification( | ||
self, spec, placement, iptags, reverse_iptags): | ||
# Generate the system data region for simulation .c requirements | ||
self.generate_system_region(spec) | ||
|
||
spec.reserve_memory_region(DataRegions.KEY_DATA, N_KEY_DATA_BYTES) | ||
spec.switch_write_focus(DataRegions.KEY_DATA) | ||
|
||
routing_infos = FecDataView().get_routing_infos() | ||
r_info = routing_infos.get_routing_info_from_pre_vertex( | ||
placement.vertex, self.__send_partition) | ||
if r_info is None: | ||
spec.write_value(0) | ||
spec.write_value(0) | ||
spec.write_value(0) | ||
else: | ||
spec.write_value(1) | ||
spec.write_value(r_info.key) | ||
spec.write_value((~r_info.mask) & 0xFFFFFFFF) | ||
|
||
# End-of-Spec: | ||
spec.end_specification() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/* | ||
* Copyright (c) 2023 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. | ||
*/ | ||
|
||
//! imports | ||
#include <spin1_api.h> | ||
#include "common-typedefs.h" | ||
#include <data_specification.h> | ||
#include <recording.h> | ||
#include <simulation.h> | ||
#include <debug.h> | ||
|
||
//! control value, which says how many timer ticks to run for before exiting | ||
static uint32_t simulation_ticks = 0; | ||
static uint32_t infinite_run = 0; | ||
static uint32_t time = 0; | ||
|
||
//! int as a bool to represent if this simulation should run forever | ||
static uint32_t infinite_run; | ||
|
||
//! The key to send data with | ||
static uint32_t send_key; | ||
|
||
//! Whether the data should be sent | ||
static uint32_t do_send; | ||
|
||
//! The mask to apply to the key to extract any data before sending | ||
static uint32_t key_mask; | ||
|
||
//! human readable definitions of each region in SDRAM | ||
typedef enum regions_e { | ||
SYSTEM_REGION, | ||
KEY_DATA_REGION, | ||
} regions_e; | ||
|
||
//! values for the priority for each callback | ||
typedef enum callback_priorities { | ||
MC_PACKET = -1, | ||
SDP = 0, | ||
DMA = 1, | ||
TIMER = 2, | ||
USER = 3 | ||
} callback_priorities; | ||
|
||
// ------------------------------------------------------------------- | ||
|
||
static void receive_data_pl(uint key, uint payload) { | ||
log_info("Key=%u Payload=%u", key, payload); | ||
if (do_send) { | ||
uint key_to_send = send_key | (key & key_mask); | ||
spin1_send_mc_packet(key_to_send, payload, 1); | ||
} | ||
} | ||
|
||
static void receive_data(uint key, UNUSED uint unused) { | ||
log_info("Key=%u", key); | ||
if (do_send) { | ||
uint key_to_send = send_key | (key & key_mask); | ||
spin1_send_mc_packet(key_to_send, 0, 0); | ||
} | ||
} | ||
|
||
static void update(uint ticks, uint b) { | ||
use(b); | ||
use(ticks); | ||
|
||
time++; | ||
|
||
// check that the run time hasn't already elapsed and thus needs to be | ||
// killed | ||
if ((infinite_run != TRUE) && (time >= simulation_ticks)) { | ||
|
||
// fall into the pause resume mode of operating | ||
simulation_handle_pause_resume(NULL); | ||
|
||
// switch to state where host is ready to read | ||
simulation_ready_to_read(); | ||
|
||
return; | ||
} | ||
} | ||
|
||
static bool initialize(uint32_t *timer_period) { | ||
log_info("Initialise: started\n"); | ||
|
||
// Get the address this core's DTCM data starts at from SRAM | ||
data_specification_metadata_t *data = data_specification_get_data_address(); | ||
|
||
// Read the header | ||
if (!data_specification_read_header(data)) { | ||
log_error("failed to read the data spec header"); | ||
return false; | ||
} | ||
|
||
// Get the timing details and set up the simulation interface | ||
if (!simulation_initialise( | ||
data_specification_get_region(SYSTEM_REGION, data), | ||
APPLICATION_NAME_HASH, timer_period, &simulation_ticks, | ||
&infinite_run, &time, SDP, DMA)) { | ||
return false; | ||
} | ||
|
||
// Get key data | ||
uint *key_data = data_specification_get_region(KEY_DATA_REGION, data); | ||
do_send = key_data[0]; | ||
send_key = key_data[1]; | ||
key_mask = key_data[2]; | ||
|
||
if (do_send) { | ||
log_info("Re-sending received keys with key 0x%08x and mask 0x%08x", | ||
send_key, key_mask); | ||
} else { | ||
log_info("Not re-sending received keys"); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/****f* | ||
* | ||
* SUMMARY | ||
* This function is called at application start-up. | ||
* It is used to register event callbacks and begin the simulation. | ||
* | ||
* SYNOPSIS | ||
* int c_main() | ||
* | ||
* SOURCE | ||
*/ | ||
void c_main(void) { | ||
|
||
// Load DTCM data | ||
uint32_t timer_period; | ||
|
||
// initialise the model | ||
if (!initialize(&timer_period)) { | ||
rt_error(RTE_SWERR); | ||
} | ||
|
||
// set timer tick value to configured value | ||
spin1_set_timer_tick(timer_period); | ||
|
||
// register callbacks | ||
spin1_callback_on(MCPL_PACKET_RECEIVED, receive_data_pl, MC_PACKET); | ||
spin1_callback_on(MC_PACKET_RECEIVED, receive_data, MC_PACKET); | ||
spin1_callback_on(TIMER_TICK, update, TIMER); | ||
|
||
// Start the time at "-1" so that the first tick will be 0 | ||
time = UINT32_MAX; | ||
|
||
simulation_run(); | ||
} |
Oops, something went wrong.