sPyNNaker neural_modelling  7.4.2
local_only.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 The University of Manchester
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
20 
21 #include "local_only.h"
22 #include "local_only/local_only_impl.h"
23 #include <debug.h>
24 #include <circular_buffer.h>
25 #include <recording.h>
26 #include <spin1_api.h>
27 
28 //: The configuration of the local only model
31  uint32_t log_n_neurons;
35  uint32_t log_max_delay;
40 };
41 
43 static struct local_only_config config;
44 
46 static circular_buffer input_buffer;
47 
49 static uint16_t *ring_buffers;
50 
53 static volatile bool process_loop_running = false;
54 
56 static uint32_t n_spikes_received = 0;
57 
59 static uint32_t max_spikes_received = 0;
60 
62 static uint32_t n_spikes_dropped = 0;
63 
65 static uint32_t max_input_buffer_size = 0;
66 
68 static uint32_t local_time;
69 
72 
75 
78 
80 uint32_t p_per_ts_region;
81 
82 
84 static struct {
85  uint32_t time;
86  uint32_t packets_this_time_step;
88 
90 static inline void run_next_process_loop(void) {
91  if (spin1_trigger_user_event(local_time, 0)) {
92  process_loop_running = true;
93  }
94 }
95 
97 static inline void update_max_input_buffer(void) {
98  uint32_t sz = circular_buffer_size(input_buffer);
99  if (sz > max_input_buffer_size) {
101  }
102 }
103 
107 void mc_rcv_callback(uint key, UNUSED uint unused) {
108  n_spikes_received += 1;
109 
110  // If there is space in the buffer, add the packet, update the counters
111  if (circular_buffer_add(input_buffer, key)) {
113 
114  // Start the loop running if not already
115  if (!process_loop_running) {
117  }
118  }
119 }
120 
125  n_spikes_received += 1;
126 
127  // Check of any one spike can be added to the circular buffer
128  bool added = false;
129  for (uint32_t i = n_spikes; i > 0; i--) {
130  added |= circular_buffer_add(input_buffer, key);
131  }
132 
133  // If any spikes were added, update the buffer maximum
134  if (added) {
136 
137  // Start the loop running if not already
138  if (!process_loop_running) {
140  }
141  }
142 }
143 
145 void process_callback(uint time, UNUSED uint unused1) {
146  uint32_t spike;
147  uint32_t cspr = spin1_int_disable();
148 
149  // While there is a spike to process, pull it out of the buffer
150  while (process_loop_running && circular_buffer_get_next(input_buffer, &spike)) {
151  spin1_mode_restore(cspr);
152 
153  // Process the spike using the specific local-only implementation
154  local_only_impl_process_spike(time, spike, ring_buffers);
155  cspr = spin1_int_disable();
156  }
157  process_loop_running = false;
158  spin1_mode_restore(cspr);
159 }
160 
161 // -----------------------------------------
162 // Implementations of interface (see local_only.h file for details)
163 
164 bool local_only_initialise(void *local_only_addr, void *local_only_params_addr,
165  uint32_t n_rec_regions_used, uint16_t **ring_buffers_ptr) {
166 
167  // Set up the implementation
168  if (!local_only_impl_initialise(local_only_params_addr)) {
169  return false;
170  }
171 
172  // Copy the config
173  struct local_only_config *sdram_config = local_only_addr;
174  config = *sdram_config;
175 
176  input_buffer = circular_buffer_initialize(config.input_buffer_size);
177  if (input_buffer == NULL) {
178  log_error("Error setting up input buffer of size %u",
180  return false;
181  }
182  log_info("Created input buffer with %u entries", config.input_buffer_size);
183 
184  // Make some buffers
189  log_info("synapse_index_bits = %u, synapse_type_index_bits = %u, "
190  "synapse_delay_bits = %u", synapse_index_bits, synapse_type_index_bits,
192 
193  uint32_t n_ring_buffer_bits = synapse_type_index_bits + synapse_delay_bits;
194  uint32_t ring_buffer_size = 1 << (n_ring_buffer_bits);
195 
196  ring_buffers = spin1_malloc(ring_buffer_size * sizeof(uint16_t));
197  if (ring_buffers == NULL) {
198  log_error("Could not allocate %u entries for ring buffers",
200  return false;
201  }
202  log_info("Created ring buffer with %u entries at 0x%08x",
204  for (uint32_t i = 0; i < ring_buffer_size; i++) {
205  ring_buffers[i] = 0;
206  }
207  *ring_buffers_ptr = ring_buffers;
208 
209  p_per_ts_region = n_rec_regions_used;
210 
211  spin1_callback_on(MC_PACKET_RECEIVED, mc_rcv_callback, -1);
212  spin1_callback_on(MCPL_PACKET_RECEIVED, mc_rcv_payload_callback, -1);
213  spin1_callback_on(USER_EVENT, process_callback, 0);
214 
215  return true;
216 }
217 
218 void local_only_clear_input(uint32_t time) {
219  local_time = time;
222  }
223  p_per_ts_struct.packets_this_time_step = n_spikes_received;
224  p_per_ts_struct.time = time;
225  recording_record(p_per_ts_region, &p_per_ts_struct, sizeof(p_per_ts_struct));
226  n_spikes_received = 0;
227  uint32_t n_spikes_left = circular_buffer_size(input_buffer);
228  n_spikes_dropped += n_spikes_left;
230  circular_buffer_clear(input_buffer);
231  }
232 }
233 
237  prov->n_spikes_lost_from_input = circular_buffer_get_n_buffer_overflows(input_buffer);
239 }
static uint32_t key
Base multicast key for sending messages.
static uint32_t time
Simulation time.
uint32_t n_spikes[2]
Spike buffer counters.
static volatile bool process_loop_running
Definition: local_only.c:53
uint32_t log_max_delay
Log_2 of the maximum delay supported.
Definition: local_only.c:35
static uint32_t n_spikes_dropped
The number of spikes discarded in total during the run.
Definition: local_only.c:62
uint32_t log_n_synapse_types
Log_2 of the number of synapse types.
Definition: local_only.c:33
uint32_t clear_input_buffer
Whether to clear the input buffer.
Definition: local_only.c:39
uint32_t synapse_delay_mask
The mask to get the synaptic delay from a "synapse".
Definition: local_only.c:71
void local_only_clear_input(uint32_t time)
Clear the spikes for the last time step.
Definition: local_only.c:218
void mc_rcv_payload_callback(uint key, uint n_spikes)
Multicast packet with payload received callback.
Definition: local_only.c:124
static uint32_t max_spikes_received
The maximum number of spikes received in any time step.
Definition: local_only.c:59
static uint16_t * ring_buffers
Ring buffers to add weights to on spike processing.
Definition: local_only.c:49
uint32_t synapse_type_index_bits
The number of bits used by the synapse type and post-neuron index.
Definition: local_only.c:74
static uint32_t max_input_buffer_size
The maximum size of the input buffer during the run.
Definition: local_only.c:65
uint32_t input_buffer_size
The size to reserve for the input buffer of spikes.
Definition: local_only.c:37
uint32_t synapse_index_bits
The number of bits used by just the post-neuron index.
Definition: local_only.c:77
static void run_next_process_loop(void)
Start the process loop.
Definition: local_only.c:90
static uint32_t local_time
The local time step counter.
Definition: local_only.c:68
uint32_t p_per_ts_region
The region where packets-per-timestep are stored.
Definition: local_only.c:80
void local_only_store_provenance(struct local_only_provenance *prov)
Store provenance gathered during run.
Definition: local_only.c:234
static uint32_t n_spikes_received
The number of spikes received in total in the last time step.
Definition: local_only.c:56
bool local_only_initialise(void *local_only_addr, void *local_only_params_addr, uint32_t n_rec_regions_used, uint16_t **ring_buffers_ptr)
Set up local-only processing of spikes.
Definition: local_only.c:164
static struct @8 p_per_ts_struct
The number of packets received this time step for recording.
void mc_rcv_callback(uint key, uint unused)
Multicast packet without payload received callback.
Definition: local_only.c:107
uint32_t log_n_neurons
Log_2 of the number of neurons.
Definition: local_only.c:31
static circular_buffer input_buffer
The input buffer for spikes received.
Definition: local_only.c:46
static void update_max_input_buffer(void)
Update the maximum size of the input buffer.
Definition: local_only.c:97
void process_callback(uint time, uint unused1)
User callback; performs spike processing loop.
Definition: local_only.c:145
static struct local_only_config config
A local copy of the configuration.
Definition: local_only.c:43
Defines the "local-only" processing of spikes, that is, the processing of spikes without using transf...
uint32_t max_input_buffer_size
The maximum size of the spike input queue at any time.
Definition: local_only.h:33
uint32_t n_spikes_lost_from_input
The number of spikes dropped due to the queue having no space.
Definition: local_only.h:31
uint32_t n_spikes_dropped
The number of spikes dropped due to running out of time in a time step.
Definition: local_only.h:29
uint32_t max_spikes_received_per_timestep
The maximum number of spikes received in a time step.
Definition: local_only.h:27
A region of SDRAM used to transfer synapses.
static uint32_t ring_buffer_size
Ring buffer size.
Definition: synapses.c:46
uint32_t synapse_delay_bits
Number of bits in the delay.
Definition: synapses.c:75