sPyNNaker neural_modelling  7.4.2
population_table_binary_search_impl.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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 #include "population_table.h"
20 #include <neuron/synapse_row.h>
21 #include <debug.h>
22 #include <stdbool.h>
23 
24 
27 
30 
33 
36 
38 static spike_t last_spike = 0;
39 
41 static uint32_t last_colour = 0;
42 
44 static uint32_t last_colour_mask = 0;
45 
47 static uint32_t last_neuron_id = 0;
48 
50 static uint16_t next_item = 0;
51 
54 uint16_t items_to_go = 0;
55 
57 static bit_field_t *connectivity_bit_field = NULL;
58 
61 
64 
68 
72 
75 static inline void print_master_population_table(void) {
76 #if LOG_LEVEL >= LOG_DEBUG
77  log_info("Master_population\n");
78  for (uint32_t i = 0; i < master_population_table_length; i++) {
80  log_info("key: 0x%08x, mask: 0x%08x", entry.key, entry.mask);
81  int count = entry.count;
82  int start = entry.start;
83  log_info(" core_mask: 0x%08x, core_shift: %u, n_neurons: %u, n_words: %u, n_colour_bits: %u",
84  entry.core_mask, entry.mask_shift, entry.n_neurons, entry.n_words, entry.n_colour_bits);
85  for (uint16_t j = start; j < (start + count); j++) {
87  if (addr.address == INVALID_ADDRESS) {
88  log_info(" index %d: INVALID", j);
89  } else {
90  log_info(" index %d: offset: %u, address: 0x%08x, row_length: %u",
92  get_row_length(addr));
93  }
94  }
95  }
96  log_info("Population table has %u entries", master_population_table_length);
97 #endif
98 }
99 
103 static inline void print_bitfields(uint32_t mp_i, filter_info_t *filters) {
104 #if LOG_LEVEL >= LOG_DEBUG
105  // print out the bit field for debug purposes
106  uint32_t n_words = get_bit_field_size(filters[mp_i].n_atoms);
107  log_info("Bit field(s) for key 0x%08x, %u words for %u atoms:",
108  master_population_table[mp_i].key, n_words, filters[mp_i].n_atoms);
109  for (uint32_t i = 0; i < n_words; i++) {
110  log_info("0x%08x", connectivity_bit_field[mp_i][i]);
111  }
112 #else
113  use(mp_i);
114  use(filters);
115 #endif
116 }
117 
118 bool population_table_load_bitfields(filter_region_t *filter_region) {
119 
121  return true;
122  }
123  // No filters = nothing to load
124  if (filter_region->n_filters == 0) {
125  return true;
126  }
127  // try allocating DTCM for starting array for bitfields
129  spin1_malloc(sizeof(bit_field_t) * master_population_table_length);
130  if (connectivity_bit_field == NULL) {
131  log_warning(
132  "Couldn't initialise basic bit field holder. Will end up doing"
133  " possibly more DMA's during the execution than required."
134  " We required %d bytes where %d are available",
135  sizeof(bit_field_t) * master_population_table_length,
136  sark_heap_max(sark.heap, 0));
137  failed_bit_field_reads += filter_region->n_filters;
138  return true;
139  }
140 
141  // Go through the population table, and the relevant bitfield list, both
142  // of which are ordered by key...
143  if (filter_region->n_filters != master_population_table_length) {
144  log_error("The number of filters doesn't match the population table");
145  return false;
146  }
147  filter_info_t* filters = filter_region->filters;
148  for (uint32_t mp_i = 0; mp_i < master_population_table_length; mp_i++) {
149  connectivity_bit_field[mp_i] = NULL;
150 
151  // Fail if the key doesn't match
152  if (master_population_table[mp_i].key != filters[mp_i].key) {
153  log_error("Bitfield for %u keys do not match: bf=0x%08x vs mp=0x%08x",
154  mp_i, filters[mp_i].key, master_population_table[mp_i].key);
155  return false;
156  }
157  uint32_t useful = !(filters[mp_i].merged || filters[mp_i].all_ones);
158 
159  if (useful) {
160  // Try to allocate all the bitfields for this entry
161  uint32_t n_words = get_bit_field_size(filters[mp_i].n_atoms);
162  uint32_t size = sizeof(bit_field_t) * n_words;
163  connectivity_bit_field[mp_i] = spin1_malloc(size);
164  if (connectivity_bit_field[mp_i] == NULL) {
165  // There might be more than one that has failed
167  } else {
168  spin1_memcpy(connectivity_bit_field[mp_i], filters[mp_i].data, size);
169  print_bitfields(mp_i, filters);
170  }
171  }
172  }
173  return true;
174 }
175 
181  spike_t spike, uint32_t *position) {
182  uint32_t imin = 0;
183  uint32_t imax = master_population_table_length;
184 
185  while (imin < imax) {
186  uint32_t imid = (imax + imin) >> 1;
188  if ((spike & entry.mask) == entry.key) {
189  *position = imid;
190  return true;
191  } else if (entry.key < spike) {
192 
193  // Entry must be in upper part of the table
194  imin = imid + 1;
195  } else {
196  // Entry must be in lower part of the table
197  imax = imid;
198  }
199  }
200  return false;
201 }
202 
203 bool population_table_setup(address_t table_address, uint32_t *row_max_n_words,
204  uint32_t *master_pop_table_length,
205  master_population_table_entry **master_pop_table,
207  pop_table_config_t *config = (pop_table_config_t *) table_address;
208  *row_max_n_words = 0xFF + N_SYNAPSE_ROW_HEADER_WORDS;
209 
210  *master_pop_table_length = config->table_length;
211 
212  if (*master_pop_table_length == 0) {
213  return true;
214  }
215 
216  uint32_t n_master_pop_bytes =
217  *master_pop_table_length * sizeof(master_population_table_entry);
218 
219  // only try to malloc if there's stuff to malloc.
220  *master_pop_table = spin1_malloc(n_master_pop_bytes);
221  if (*master_pop_table == NULL) {
222  log_error("Could not allocate master population table of %u bytes",
223  n_master_pop_bytes);
224  return false;
225  }
226 
227  uint32_t address_list_length = config->addr_list_length;
228  uint32_t n_address_list_bytes =
229  address_list_length * sizeof(address_list_entry);
230 
231  *address_list = spin1_malloc(n_address_list_bytes);
232  if (*address_list == NULL) {
233  log_error("Could not allocate master population address list of %u bytes",
234  n_address_list_bytes);
235  return false;
236  }
237 
238  // Copy the master population table
239  spin1_memcpy(*master_pop_table, config->data, n_master_pop_bytes);
240  spin1_memcpy(*address_list, &config->data[*master_pop_table_length],
241  n_address_list_bytes);
242  return true;
243 }
245 
248 
250  address_t table_address, address_t synapse_rows_address,
251  uint32_t *row_max_n_words) {
252  population_table_setup(table_address, row_max_n_words,
255 
256  // Store the base address
257  synaptic_rows_base_address = (uint32_t) synapse_rows_address;
258 
260  return true;
261 }
262 
264 
265  // check we don't have a complete miss
266  uint32_t position;
267  if (!population_table_position_in_the_master_pop_array(spike, &position)) {
269  return false;
270  }
271 
273 
274  last_spike = spike;
275  next_item = entry.start;
276  items_to_go = entry.count;
277  uint32_t local_neuron_id = get_local_neuron_id(entry, spike);
278  if (entry.n_colour_bits) {
279  last_colour_mask = (1 << entry.n_colour_bits) - 1;
280  last_colour = local_neuron_id & last_colour_mask;
281  last_neuron_id = (local_neuron_id >> entry.n_colour_bits) + get_core_sum(entry, spike);
282  } else {
283  last_colour = 0;
284  last_colour_mask = 0;
285  last_neuron_id = local_neuron_id + get_core_sum(entry, spike);
286  }
287 
288  // check we have a entry in the bit field for this (possible not to due to
289  // DTCM limitations or router table compression). If not, go to DMA check.
290  if (connectivity_bit_field != NULL &&
291  connectivity_bit_field[position] != NULL) {
292  // check that the bit flagged for this neuron id does hit a
293  // neuron here. If not return false and avoid the DMA check.
294  if (!bit_field_test(
297  items_to_go = 0;
298  return false;
299  }
300  }
301 
302  // A local address is used here as the interface requires something
303  // to be passed in but using the address of an argument is odd!
304  uint32_t local_spike_id;
305  bool get_next = population_table_get_next_address(&local_spike_id, result);
306 
307  // tracks surplus DMAs
308  if (!get_next) {
310  }
311  return get_next;
312 }
313 
315  // If there are no more items in the list, return false
316  if (items_to_go == 0) {
317  return false;
318  }
319 
320  bool is_valid = false;
321  do {
323  if (item.address != INVALID_ADDRESS) {
324 
326  last_neuron_id, result);
327  *spike = last_spike;
328  result->colour = last_colour;
329  result->colour_mask = last_colour_mask;
330  is_valid = true;
331  }
332 
333  next_item++;
334  items_to_go--;
335  } while (!is_valid && (items_to_go > 0));
336 
337  return is_valid;
338 }
339 
static uint32_t key
Base multicast key for sending messages.
static struct local_only_config config
A local copy of the configuration.
Definition: local_only.c:43
uint32_t spike_t
The type of a spike.
Master pop(ulation) table API.
static uint32_t get_offset(address_list_entry entry)
Get the standard address offset out of an entry.
uint32_t key
The key to match against the incoming message.
uint32_t count
The number of entries in address_list for this entry.
uint32_t n_neurons
The number of neurons per core.
static uint32_t get_address(address_list_entry entry, uint32_t addr)
Get the standard address out of an entry.
uint32_t address
the address
static uint32_t get_row_length(address_list_entry entry)
Get the length of the row from the entry.
static void get_row_addr_and_size(address_list_entry item, uint32_t synaptic_rows_base_address, uint32_t neuron_id, pop_table_lookup_result_t *result)
Get the row address and size for a given neuron.
static uint32_t get_local_neuron_id(master_population_table_entry entry, spike_t spike)
Get the neuron id of the neuron on the source core, for a spike with extra info.
uint32_t mask
The mask to select the relevant bits of key for matching.
uint32_t n_colour_bits
The number of bits of key used for colour (0 if no colour)
uint32_t n_words
The number of words for n_neurons.
#define INVALID_ADDRESS
An Invalid address and row length.
static uint32_t get_core_sum(master_population_table_entry entry, spike_t spike)
Get the total number of neurons on cores which come before this core.
uint32_t core_mask
The mask to apply to the key once shifted to get the core index.
uint32_t mask_shift
The shift to apply to the key to get the core part.
uint32_t start
The index into address_list for this entry.
A packed address and row length (note: same size as extra info)
An entry in the master population table.
The memory layout in SDRAM of the first part of the population table configuration....
A structure to hold a response to a population table lookup.
bool population_table_setup(address_t table_address, uint32_t *row_max_n_words, uint32_t *master_pop_table_length, master_population_table_entry **master_pop_table, address_list_entry **address_list)
Set up and return the table for outside use.
static uint16_t next_item
the index for the next item in the address_list
bool population_table_get_next_address(spike_t *spike, pop_table_lookup_result_t *result)
Get the next row data for a previously given spike. If no spike has been given, return False.
static master_population_table_entry * master_population_table
The master population table. This is sorted.
static void print_bitfields(uint32_t mp_i, filter_info_t *filters)
Print bitfields for debugging.
static uint32_t last_colour
The last colour received.
static uint32_t synaptic_rows_base_address
Base address for the synaptic matrix's indirect rows.
static void print_master_population_table(void)
Prints the master pop table.
uint32_t failed_bit_field_reads
The number of bit fields which were not able to be read in due to DTCM limits.
uint32_t invalid_master_pop_hits
the number of times packet isnt in the master pop table at all!
uint32_t bit_field_filtered_packets
The number of packets dropped because the bitfield filter says they don't hit anything.
bool population_table_load_bitfields(filter_region_t *filter_region)
Initialise the bitfield filtering system.
static address_list_entry * address_list
The array of information that points into the synaptic matrix.
static uint32_t last_colour_mask
The last colour mask used.
bool population_table_get_first_address(spike_t spike, pop_table_lookup_result_t *result)
Get the first row data for the given input spike.
static bool population_table_position_in_the_master_pop_array(spike_t spike, uint32_t *position)
Get the position in the master population table.
static uint32_t last_neuron_id
The last neuron id for the key.
uint32_t ghost_pop_table_searches
the number of times a DMA resulted in 0 entries
static uint32_t master_population_table_length
The length of master_population_table.
bool population_table_initialise(address_t table_address, address_t synapse_rows_address, uint32_t *row_max_n_words)
Set up the table.
uint16_t items_to_go
The number of addresses from the same spike left to process.
static bit_field_t * connectivity_bit_field
The bitfield map.
static spike_t last_spike
The last spike received.
implementation for handling the processing of synapse rows.
#define N_SYNAPSE_ROW_HEADER_WORDS
Number of header words per synaptic row.
Definition: synapse_row.h:109