sPyNNaker neural_modelling 7.1.1
Loading...
Searching...
No Matches
neuron_recording.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 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
19
20#ifndef _NEURON_RECORDING_H_
21#define _NEURON_RECORDING_H_
22
24#include <bit_field.h>
25#include <recording.h>
26#include <wfi.h>
27#include <stddef.h>
28
30// Note data is just bytes here but actual type is used on writing
31typedef struct recording_values_t {
32 uint32_t time;
33 uint8_t data[];
35
37typedef struct bitfield_values_t {
38 uint32_t time;
39 uint32_t bits[];
41
43typedef struct recording_info_t {
44 uint32_t element_size;
45 uint32_t rate;
46 uint32_t count;
47 uint32_t increment;
48 uint32_t size;
49 recording_values_t *values;
51
53typedef struct bitfield_info_t {
54 uint32_t rate;
55 uint32_t count;
56 uint32_t increment;
57 uint32_t size;
58 uint32_t n_words;
59 bitfield_values_t *values;
61
63static uint16_t **neuron_recording_indexes;
64
67
70
73
75static uint8_t **recording_values;
76
78static uint32_t **bitfield_values;
79
81static volatile uint32_t n_recordings_outstanding = 0;
82
84static void *reset_address;
85
87#define FLOOR_TO_2 0xFFFFFFFE
88
90#define CEIL_TO_2 1
91
98 uint32_t var_index, uint32_t neuron_index, void *value) {
99 uint32_t index = neuron_recording_indexes[var_index][neuron_index];
100 uint32_t size = recording_info[var_index].element_size;
101 uint32_t p = size * index;
102 spin1_memcpy(&recording_values[var_index][p], value, size);
103}
104
111 uint32_t var_index, uint32_t neuron_index, accum value) {
112 uint16_t index = neuron_recording_indexes[var_index][neuron_index];
113 accum *data = (accum *) recording_values[var_index];
114 data[index] = value;
115}
116
123 uint32_t var_index, uint32_t neuron_index, double value) {
124 uint16_t index = neuron_recording_indexes[var_index][neuron_index];
125 double *data = (double *) recording_values[var_index];
126 data[index] = value;
127}
128
135 uint32_t var_index, uint32_t neuron_index, float value) {
136 uint16_t index = neuron_recording_indexes[var_index][neuron_index];
137 float *data = (float *) recording_values[var_index];
138 data[index] = value;
139}
140
147 uint32_t var_index, uint32_t neuron_index, int32_t value) {
148 uint16_t index = neuron_recording_indexes[var_index][neuron_index];
149 int32_t *data = (int32_t *) recording_values[var_index];
150 data[index] = value;
151}
152
158 uint32_t var_index, uint32_t neuron_index) {
159 // Record the bit
160 uint32_t index = bitfield_recording_indexes[var_index][neuron_index];
161 bit_field_set(bitfield_values[var_index], index);
162}
163
166static inline void neuron_recording_record(uint32_t time) {
167 // go through all recordings
168
169 for (uint32_t i = N_RECORDED_VARS; i > 0; i--) {
170 recording_info_t *rec_info = &recording_info[i - 1];
171 // if the rate says record, record now
172 if (rec_info->count == rec_info->rate) {
173 // Reset the count
174 rec_info->count = 1;
175 // Set the time and record the data
176 rec_info->values->time = time;
177 recording_record(i - 1, rec_info->values, rec_info->size);
178 } else {
179
180 // Not recording this time, so increment by specified amount
181 rec_info->count += rec_info->increment;
182 }
183 }
184
185 for (uint32_t i = N_BITFIELD_VARS; i > 0; i--) {
186 bitfield_info_t *bf_info = &bitfield_info[i - 1];
187 // if the rate says record, record now
188 if (bf_info->count == bf_info->rate) {
189 // Reset the count
190 bf_info->count = 1;
191 // Skip empty bitfields
192 if (empty_bit_field(bf_info->values->bits, bf_info->n_words)) {
193 continue;
194 }
195 // Set the time and record the data (note index is after recorded_vars)
196 bf_info->values->time = time;
197 recording_record(i + N_RECORDED_VARS - 1, bf_info->values, bf_info->size);
198 } else {
199
200 // Not recording this time, so increment by specified amount
201 bf_info->count += bf_info->increment;
202 }
203 }
204}
205
208 // Reset the bitfields before starting if a beginning of recording
209 for (uint32_t i = N_BITFIELD_VARS; i > 0; i--) {
210 bitfield_info_t *b_info = &bitfield_info[i - 1];
211 if (b_info->count == 1) {
212 clear_bit_field(b_info->values->bits, b_info->n_words);
213 }
214 }
215}
216
218static void reset_record_counter(void) {
219 for (uint32_t i = 0; i < N_RECORDED_VARS; i++) {
220 if (recording_info[i].rate == 0) {
221 // Setting increment to zero means count will never equal rate
222 recording_info[i].increment = 0;
223
224 // Count is not rate so does not record, but not 1 so it does not reset!
225 recording_info[i].count = 2;
226 } else {
227 // Increase one each call so count gets to rate
228 recording_info[i].increment = 1;
229
230 // Using rate here so that the zero time is recorded
231 recording_info[i].count = recording_info[i].rate;
232 }
233 }
234
235 // clear the bitfields
236 for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) {
237 if (bitfield_info[i].rate == 0) {
238 // Setting increment to zero means count will never equal rate
239 bitfield_info[i].increment = 0;
240
241 // Count is not rate so does not record, but not 1 so it does not reset!
242 bitfield_info[i].count = 2;
243 } else {
244 // Increase one each call so count gets to rate
245 bitfield_info[i].increment = 1;
246
247 // Using rate here so that the zero time is recorded
248 bitfield_info[i].count = bitfield_info[i].rate;
249 clear_bit_field(bitfield_info[i].values->bits,
250 bitfield_info[i].n_words);
251 }
252 }
253}
254
258static inline uint32_t bitfield_data_size(uint32_t n_neurons) {
259 return sizeof(bitfield_values_t) + (get_bit_field_size(n_neurons) * sizeof(uint32_t));
260}
261
267 void *recording_address, uint32_t n_neurons) {
268 // Round up the number of bytes to align at a word boundary i.e. round to
269 // the next multiple of 2
270 uint32_t ceil_n_entries = (n_neurons + CEIL_TO_2) & FLOOR_TO_2;
271
272
273 // GCC lets you define a struct like this!
274 typedef struct neuron_recording_data {
275 uint32_t rate;
276 uint32_t n_neurons_recording;
277 uint32_t element_size;
278 uint16_t indices[ceil_n_entries];
279 } neuron_recording_data_t;
280
281 neuron_recording_data_t *data = recording_address;
282
283 for (uint32_t i = 0; i < N_RECORDED_VARS; i++) {
284 recording_info[i].rate = data[i].rate;
285 uint32_t n_neurons_rec = data[i].n_neurons_recording;
286 recording_info[i].element_size = data[i].element_size;
287 recording_info[i].size = sizeof(recording_values_t)
288 + (n_neurons_rec * recording_info[i].element_size);
289 // There is an extra "neuron" in the data used when one of the neurons
290 // is *not* recording, to avoid a check
291 uint32_t alloc_size = recording_info[i].size +
292 recording_info[i].element_size;
293
294 // allocate memory for the recording
295 if (recording_info[i].values == NULL) {
296 recording_info[i].values = spin1_malloc(alloc_size);
297 if (recording_info[i].values == NULL) {
298 log_error("couldn't allocate recording data space %u for %d",
299 alloc_size, i);
300 return false;
301 }
302 recording_values[i] = recording_info[i].values->data;
303 }
304
305 // copy over the indexes
306 spin1_memcpy(neuron_recording_indexes[i], data[i].indices,
307 n_neurons * sizeof(uint16_t));
308 }
309
310 typedef struct bitfield_recording_data {
311 uint32_t rate;
312 uint32_t n_neurons_recording;
313 uint16_t indices[ceil_n_entries];
314 } bitfield_recording_data_t;
315
316 bitfield_recording_data_t *bitfield_data =
317 (bitfield_recording_data_t *) &data[N_RECORDED_VARS];
318
319 for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) {
320 bitfield_info[i].rate = bitfield_data[i].rate;
321 uint32_t n_neurons_rec = bitfield_data[i].n_neurons_recording;
322 bitfield_info[i].size = bitfield_data_size(n_neurons_rec);
323 // There is an extra "neuron" in the data used when one of the neurons
324 // is *not* recording, to avoid a check
325 uint32_t alloc_size = bitfield_data_size(n_neurons_rec + 1);
326
327 // allocate memory for the recording
328 if (bitfield_info[i].values == NULL) {
329 bitfield_info[i].values = spin1_malloc(alloc_size);
330 if (bitfield_info[i].values == NULL) {
331 log_error("couldn't allocate bitfield recording data space for %d", i);
332 return false;
333 }
334 // There is an extra "neuron" in the data used when one of the
335 // neurons is *not* recording, to avoid a check
336 bitfield_info[i].n_words = get_bit_field_size(n_neurons_rec + 1);
337 bitfield_values[i] = bitfield_info[i].values->bits;
338 }
339
340 // copy over the indexes
341 spin1_memcpy(bitfield_recording_indexes[i], bitfield_data[i].indices,
342 n_neurons * sizeof(uint16_t));
343 }
344 return true;
345}
346
352 log_error("failed to reread in the new elements after reset");
353 return false;
354 }
355 return true;
356}
357
361static inline bool allocate_word_dtcm(uint32_t n_neurons) {
362 recording_info = spin1_malloc(N_RECORDED_VARS * sizeof(recording_info_t));
363 if (recording_info == NULL) {
364 log_error("Could not allocated space for recording_info");
365 return false;
366 }
367
368 // allocate dtcm for the overall holder for indexes
370 spin1_malloc(N_RECORDED_VARS * sizeof(uint16_t *));
372 log_error("Could not allocate space for var_recording_indexes");
373 return false;
374 }
375
376 recording_values = spin1_malloc(N_RECORDED_VARS * sizeof(uint8_t *));
377 if (recording_values == NULL) {
378 log_error("Could not allocate space for recording_values");
379 return false;
380 }
381
382 for (uint32_t i = 0; i < N_RECORDED_VARS; i++) {
383 // clear recorded values pointer
384 recording_info[i].values = NULL;
385
386 // allocate dtcm for indexes for each recording region
387 neuron_recording_indexes[i] = spin1_malloc(n_neurons * sizeof(uint16_t));
388 if (neuron_recording_indexes[i] == NULL) {
389 log_error("failed to allocate memory for recording index %d", i);
390 return false;
391 }
392 }
393
394 // successfully allocated all DTCM.
395 return true;
396}
397
401static inline bool allocate_bitfield_dtcm(uint32_t n_neurons) {
402 bitfield_info = spin1_malloc(N_BITFIELD_VARS * sizeof(bitfield_info_t));
403 if (bitfield_info == NULL) {
404 log_error("Failed to allocate space for bitfield_info");
405 return false;
406 }
407
408 // allocate dtcm for the overall holder for indexes
410 spin1_malloc(N_BITFIELD_VARS * sizeof(uint16_t *));
412 log_error("Could not allocate space for bitfield_recording_indexes");
413 return false;
414 }
415
416 bitfield_values = spin1_malloc(N_BITFIELD_VARS * sizeof(uint32_t *));
417 if (bitfield_values == NULL) {
418 log_error("Could not allocate space for bitfield_values");
419 return false;
420 }
421
422 for (uint32_t i = 0; i < N_BITFIELD_VARS; i++) {
423 // clear recorded values pointer
424 bitfield_info[i].values = NULL;
425
426 // allocate dtcm for indexes for each recording region
428 spin1_malloc(n_neurons * sizeof(uint16_t));
430 log_error("failed to allocate memory for bitfield index %d", i);
431 return false;
432 }
433 }
434
435 // successfully allocated all DTCM.
436 return true;
437}
438
440typedef struct neuron_recording_header {
446
454 void *recording_address, uint32_t n_neurons,
455 uint32_t *n_rec_regions_used) {
456 // boot up the basic recording
457 void *data_addr = recording_address;
458
459 // Verify the number of recording and bitfield elements
460 neuron_recording_header_t *header = data_addr;
461 if (header->n_recorded_vars != N_RECORDED_VARS) {
462 log_error("Data spec number of recording variables %d != "
463 "neuron implementation number of recorded variables %d",
464 header->n_recorded_vars, N_RECORDED_VARS);
465 return false;
466 }
467 if (header->n_bitfield_vars != N_BITFIELD_VARS) {
468 log_error("Data spec number of bitfield variables %d != "
469 "neuron implementation number of bitfield variables %d",
470 header->n_bitfield_vars, N_BITFIELD_VARS);
471 return false;
472 }
473 // Copy the number of regions used
474 *n_rec_regions_used = header->n_recorded_vars + header->n_bitfield_vars;
475 data_addr = &header[1];
476
478 log_error("failed to allocate DTCM for the neuron recording structs.");
479 return false;
480 }
482 log_error("failed to allocate DTCM for the bitfield recording structs");
483 return false;
484 }
485
486 // read in the sdram params into the allocated data objects
487 reset_address = data_addr;
489 log_error("failed to read in the elements");
490 return false;
491 }
492
493 // reset stuff
495
496 return true;
497}
498
499#endif //_NEURON_RECORDING_H_
uint32_t time
The current timer tick value.
Definition c_main.c:94
void log_error(const char *message,...)
Data type definitions for SpiNNaker Neuron-modelling.
static uint32_t n_neurons
The number of neurons on the core.
Definition neuron.c:45
static void neuron_recording_record_float(uint32_t var_index, uint32_t neuron_index, float value)
stores a recording of a float variable only; this is faster than neuron_recording_record_value for th...
static bitfield_info_t * bitfield_info
An array of bitfield information structures.
#define FLOOR_TO_2
When bitwise anded with a number will floor to the nearest multiple of 2.
static void neuron_recording_record_value(uint32_t var_index, uint32_t neuron_index, void *value)
stores a recording of a value of any type, except bitfield; use the functions below for common types ...
static void reset_record_counter(void)
resets all states back to start state.
static void neuron_recording_record_accum(uint32_t var_index, uint32_t neuron_index, accum value)
stores a recording of an accum variable only; this is faster than neuron_recording_record_value for t...
static volatile uint32_t n_recordings_outstanding
The number of recordings outstanding.
bool neuron_recording_reset(uint32_t n_neurons)
reads recording data from sdram on reset.
static void neuron_recording_setup_for_next_recording(void)
sets up state for next recording.
static uint16_t ** neuron_recording_indexes
The index to record each variable to for each neuron.
static bool allocate_word_dtcm(uint32_t n_neurons)
handles all the DTCM allocations for recording words
static uint16_t ** bitfield_recording_indexes
The index to record each bitfield variable to for each neuron.
static void neuron_recording_record(uint32_t time)
does the recording process of handing over to basic recording
static recording_info_t * recording_info
An array of recording information structures.
#define CEIL_TO_2
Add to a number before applying floor to 2 to turn it into a ceil operation.
static bool neuron_recording_read_in_elements(void *recording_address, uint32_t n_neurons)
reads recording data from SDRAM
static void neuron_recording_record_double(uint32_t var_index, uint32_t neuron_index, double value)
stores a recording of a double variable only; this is faster than neuron_recording_record_value for t...
static uint32_t ** bitfield_values
An array of spaces into which bitfields can be written.
uint32_t n_recorded_vars
The number of word-sized variables to record.
static uint8_t ** recording_values
An array of spaces into which recording values can be written.
static void * reset_address
The address of the recording region to read on reset.
uint32_t n_bitfield_vars
The number of bitfield variables to record.
bool neuron_recording_initialise(void *recording_address, uint32_t n_neurons, uint32_t *n_rec_regions_used)
sets up the recording stuff
static uint32_t bitfield_data_size(uint32_t n_neurons)
the number of bytes used in bitfield recording for n_neurons
static void neuron_recording_record_bit(uint32_t var_index, uint32_t neuron_index)
stores a recording of a set bit; this is the only way to set a bit in a bitfield; neuron_recording_re...
static bool allocate_bitfield_dtcm(uint32_t n_neurons)
handles all the DTCM allocations for recording bitfields
static void neuron_recording_record_int32(uint32_t var_index, uint32_t neuron_index, int32_t value)
stores a recording of an int32_t variable only; this is faster than neuron_recording_record_value for...
A struct for information on a bitfield recording.
A struct for bitfield data.
The heading of the neuron recording region.
A struct for information for a non-bitfield recording.
A struct of the different types of recorded data.
bool recording_record(channel_index_t channel, void *data, size_t size_bytes)
#define NULL
void spin1_memcpy(void *dst, void const *src, uint len)