SpiNNFrontEndCommon 7.3.1
Common support code for user-facing front end systems.
Loading...
Searching...
No Matches
pair_minimize.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 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
30#include <stdbool.h>
31#include <debug.h>
32#include "../common/routing_table.h"
33#include "common/minimise.h"
34
36#define MAX_NUM_ROUTES 1023
37
39static uint32_t write_index;
40
42static int remaining_index;
43
45static uint32_t routes[MAX_NUM_ROUTES];
46
48static uint32_t routes_frequency[MAX_NUM_ROUTES] = {0};
49
51static uint32_t routes_count;
52
55
60static inline entry_t merge(const entry_t* entry1, const entry_t* entry2) {
61 entry_t result = {
62 .key_mask = key_mask_merge(entry1->key_mask, entry2->key_mask),
63 .route = entry1->route,
64 .source = (entry1->source == entry2->source ? entry1->source : 0)
65 };
66 return result;
67}
68
72static inline void _entry(const entry_t* entry, int index) {
73 entry_t* e_ptr = routing_table_get_entry(index);
74 e_ptr->key_mask = entry->key_mask;
75 e_ptr->route = entry->route;
76 e_ptr->source = entry->source;
77}
78
79static inline int transfer_next(int start_index, int n_items, uint32_t cache) {
80 if (n_items == 0) {
81 return 0;
82 }
83 uint32_t next_items = n_items;
84 if (n_items > MAX_NUM_ROUTES) {
85 next_items = MAX_NUM_ROUTES;
86 }
87 routing_table_get_entries(start_index, next_items, route_cache[cache]);
88 return next_items;
89}
90
92static inline void cancel_dmas(void) {
93 dma[DMA_CTRL] = 0x3F;
94 while (dma[DMA_STAT] & 0x1) {
95 continue;
96 }
97 dma[DMA_CTRL] = 0xD;
98 while (dma[DMA_CTRL] & 0xD) {
99 continue;
100 }
101}
102
109static inline bool find_merge_optimised(int left, int index) {
110 log_debug("find merge %d %d", left, index);
111 cancel_dmas();
112 const entry_t *entry1 = routing_table_get_entry(left);
113 const entry_t *entry2 = routing_table_get_entry(index);
114 const entry_t merged = merge(entry1, entry2);
115
116 #if LOG_LEVEL >= LOG_DEBUG
118 const entry_t *check_entry = routing_table_get_entry(check);
119 log_debug("%d %08x %08x %d", check, check_entry->key_mask.key,
120 check_entry->key_mask.mask, check_entry->route);
121 }
122 #endif // LOG_LEVEL >= LOG_DEBUG
123
124 uint32_t size = routing_table_get_n_entries();
125 uint32_t items_to_go = size - remaining_index;
126 log_debug("size %d remaining_index %d items_to_go %d", size, remaining_index, items_to_go);
127 uint32_t next_n_items = transfer_next(remaining_index, items_to_go, 0);
128 uint32_t next_items_to_go = items_to_go - next_n_items;
129 uint32_t next_start = remaining_index + next_n_items;
130 bool dma_in_progress = true;
131 uint32_t read_cache = 0;
132 uint32_t write_cache = 1;
133 while (items_to_go > 0) {
134
135 // Finish any outstanding transfer
136 if (dma_in_progress) {
138 dma_in_progress = false;
139 }
140
141 // Get the details of the last transfer done
142 uint32_t n_items = next_n_items;
143 uint32_t cache = read_cache;
144
145 // Start the next transfer if needed
146 if (next_items_to_go > 0) {
147 next_n_items = transfer_next(next_start, next_items_to_go, write_cache);
148 next_items_to_go -= next_n_items;
149 next_start += next_n_items;
150 dma_in_progress = true;
151 write_cache = (write_cache + 1) & 0x1;
152 read_cache = (read_cache + 1) & 0x1;
153 }
154
155 // Check the items now available
156 entry_t *entries = route_cache[cache];
157 log_debug("to check %d", n_items);
158 for (uint32_t i = 0; i < n_items; i++) {
159 log_debug("%d %08x %08x %d", i + remaining_index, entries[i].key_mask.key,
160 entries[i].key_mask.mask, entries[i].route);
161 if (key_mask_intersect(entries[i].key_mask, merged.key_mask)) {
162 if (dma_in_progress) {
164 }
165 log_debug("intersect");
166 return false;
167 }
168 }
169
170 items_to_go = next_items_to_go;
171 }
172 routing_table_put_entry(&merged, left);
173 return true;
174}
175
182static inline bool find_merge(int left, int index) {
183 log_debug("find merge %d %d", left, index);
184 cancel_dmas();
185 const entry_t *entry1 = routing_table_get_entry(left);
186 const entry_t *entry2 = routing_table_get_entry(index);
187 const entry_t merged = merge(entry1, entry2);
188
189 for (int check = remaining_index;
191 check++) {
192 const entry_t *check_entry =
194 if (key_mask_intersect(check_entry->key_mask, merged.key_mask)) {
195 return false;
196 }
197 }
198
199 routing_table_put_entry(&merged, left);
200 return true;
201}
202
206static inline void compress_by_route(int left, int right) {
207 log_debug("merge left %d right %d", left, right);
208 while (left < right) {
209 bool merged = false;
210
211 for (int index = left + 1; index <= right; index++) {
212 merged = find_merge(left, index);
213 if (merged) {
214 routing_table_copy_entry(index, right--);
215 break;
216 }
217 }
218 if (!merged) {
220 }
221 }
222 if (left == right) {
224 }
225}
226
229static void sort_routes(void) {
230 uint32_t i, j;
231
232 for (i = 1; i < routes_count; i++) {
233 // The entry we're going to move is "taken out"
234 uint32_t r_tmp = routes[i];
235 uint32_t rf_tmp = routes_frequency[i];
236
237 // The entries below it that are larger are shuffled up
238 for (j = i; j > 0 && routes_frequency[j - 1] > rf_tmp; j--) {
239 routes[j] = routes[j - 1];
241 }
242
243 // The entry is dropped back into place
244 routes[j] = r_tmp;
245 routes_frequency[j] = rf_tmp;
246 }
247}
248
252static inline bool update_frequency(int index) {
253 uint32_t route = routing_table_get_entry(index)->route;
254 log_debug("index %d routes %d", index, route);
255 for (uint i = 0; i < routes_count; i++) {
256 if (routes[i] == route) {
257 routes_frequency[i]++;
258 return true;
259 }
260 }
261 routes[routes_count] = route;
263 routes_count++;
265 if (standalone()) {
266 log_error("Too many different routes to compress found %d "
267 "compared to max legal of %d",
269 }
270 return false;
271 }
272 return true;
273}
274
275static inline uint32_t find_route_index(uint32_t route) {
276 for (uint32_t i = 0; i < routes_count; i++) {
277 if (route == routes[i]) {
278 return i;
279 }
280 }
281 log_error("Route 0x%08x not found!", route);
282 for (uint32_t i = 0; i < routes_count; i++) {
283 log_error("Route %u = 0x%08x", i, routes[i]);
284 }
285 rt_error(RTE_SWERR);
286 return 0xFFFFFFFF;
287}
288
292void sort_table(void) {
293 if (routes_count == 0) {
294 return;
295 }
296
297 // Set up a pointer for each of the routes
298 uint16_t route_offset[routes_count];
299 uint16_t route_end[routes_count];
300 uint32_t offset = 0;
301 for (uint32_t i = 0; i < routes_count; i++) {
302 route_offset[i] = offset;
303 offset += routes_frequency[i];
304 route_end[i] = offset - 1;
305 }
306
307 // Go through and move things into position
308 uint32_t pos = 0;
309 uint32_t pos_index = 0;
310 uint32_t next_index_offset = routes_frequency[0];
311 uint32_t n_entries = routing_table_get_n_entries();
312 while (pos < n_entries) {
313 // Get the entry
314 entry_t entry = *routing_table_get_entry(pos);
315
316 // Where does the route need to go
317 uint32_t route_index = find_route_index(entry.route);
318
319 // Where are we reading from?
320 uint32_t read_index = pos_index;
321
322 // If we are in the right region
323 bool skip = false;
324 if (route_index == read_index) {
325 // If we already put this item here, don't move it
326 if (pos < route_offset[route_index]) {
327 skip = true;
328 }
329 }
330
331 // Keep swapping things until they are in the right place
332 while (!skip) {
333
334 // Find the place to put the route in its group
335 uint32_t new_pos = route_offset[route_index];
336 if (new_pos >= n_entries) {
337 log_error("New table position %u out of range!", new_pos);
339 }
340
341 if (new_pos > route_end[route_index]) {
342 log_error("New table position %u of region %u is out of range!",
343 new_pos, route_index);
345 }
346 route_offset[route_index] += 1;
347
348 // Swap out the existing entry with the new one
349 entry_t old_entry = *routing_table_get_entry(new_pos);
350 routing_table_put_entry(&entry, new_pos);
351
352 // We can quit because we should have moved this one
353 if (new_pos <= pos) {
354 break;
355 }
356 entry = old_entry;
357 read_index = route_index;
358
359 // Find the index of the item we swapped out so it can be swapped next
360 route_index = find_route_index(entry.route);
361 }
362
363 // Where are we next
364 pos++;
365 if (pos == next_index_offset) {
366 pos_index += 1;
367 next_index_offset += routes_frequency[pos_index];
368 }
369 }
370}
371
378bool minimise_run(int target_length, bool *failed_by_malloc,
379 volatile bool *stop_compressing) {
380 use(failed_by_malloc);
381 use(target_length);
382
383 // Verify constant used to build arrays is correct
385 log_error("MAX_NUM_ROUTES %d != rtr_alloc_max() %d",
387 return false;
388 }
389 int table_size = routing_table_get_n_entries();
390
391 routes_count = 0;
392
393 for (int index = 0; index < table_size; index++) {
394 if (!update_frequency(index)) {
395 return false;
396 }
397 }
398
399 log_debug("before sort %u", routes_count);
400 for (uint i = 0; i < routes_count; i++) {
401 log_debug("%u", routes[i]);
402 }
403
404 sort_routes();
405 if (*stop_compressing) {
406 log_info("Stopping as asked to stop");
407 return false;
408 }
409
410 log_debug("after sort %u", routes_count);
411 for (uint i = 0; i < routes_count; i++) {
412 log_debug("%u", routes[i]);
413 }
414
415 log_debug("do sort_table by route %u", table_size);
416 tc[T2_LOAD] = 0xFFFFFFFF;
417 tc[T2_CONTROL] = 0x83;
418 sort_table();
419 uint32_t duration = 0xFFFFFFFF - tc[T2_COUNT];
420 tc[T2_CONTROL] = 0;
421 log_info("Sorting table took %u clock cycles", duration);
422 if (*stop_compressing) {
423 log_info("Stopping before compression as asked to stop");
424 return false;
425 }
426
427 write_index = 0;
428 int max_index = table_size - 1;
429 int left = 0;
430
431 while (left <= max_index) {
432 int right = left;
433 uint32_t left_route = routing_table_get_entry(left)->route;
434 log_debug("A %u %u %u %u", left, max_index, right, left_route);
435 while ((right < table_size - 1) &&
436 routing_table_get_entry(right+1)->route ==
437 left_route) {
438 right++;
439 }
440 remaining_index = right + 1;
441 log_debug("compress %u %u", left, right);
442 tc[T2_LOAD] = 0xFFFFFFFF;
443 tc[T2_CONTROL] = 0x83;
444 compress_by_route(left, right);
445 duration = 0xFFFFFFFF - tc[T2_COUNT];
446 tc[T2_CONTROL] = 0;
447 log_info("Compressing %u routes took %u", right - left + 1, duration);
448 if (write_index > rtr_alloc_max()){
449 if (standalone()) {
450 log_error("Compression not possible as already found %d "
451 "entries where max allowed is %d",
453 }
454 return false;
455 }
456 if (*stop_compressing) {
457 log_info("Stopping during compression as asked to stop");
458 return false;
459 }
460 left = right + 1;
461 }
462
463 log_debug("done %u %u", table_size, write_index);
464
465 //for (uint i = 0; i < write_index; i++) {
466 // entry_t *entry1 = routing_table_get_entry(i);
467 // log_info("%u route:%u source:%u key:%u mask:%u",i, entry1->route,
468 // entry1->source, entry1->key_mask.key, entry1->key_mask.mask);
469 //}
472 return true;
473}
#define check(condition, message,...)
#define use(x)
This can be used to silence gcc's "-Wall -Wextra" warnings about failure to use function arguments.
SpiNNaker debug header file.
void log_error(const char *message,...)
This function logs errors. Errors usually indicate a serious fault in the program,...
void log_debug(const char *message,...)
This function logs debugging messages. This level of message is normally not printed except when the ...
void log_info(const char *message,...)
This function logs informational messages. This is the lowest level of message normally printed.
API for routing table minimisation.
bool standalone(void)
Whether this is a standalone compressor.
static bool find_merge(int left, int index)
Finds if two routes can be merged.
static void sort_routes(void)
Implementation of insertion sort for routes based on frequency.
static entry_t merge(const entry_t *entry1, const entry_t *entry2)
Merges a single pair of route entries.
static uint32_t routes[MAX_NUM_ROUTES]
Table of routes being produced.
static uint32_t write_index
The index of the next place in the compressed table to write a route.
static int remaining_index
The index of the first route after the ones being compressed in this step.
#define MAX_NUM_ROUTES
Absolute maximum number of routes that we may produce.
bool minimise_run(int target_length, bool *failed_by_malloc, volatile bool *stop_compressing)
Implementation of minimise()
static bool find_merge_optimised(int left, int index)
Finds if two routes can be merged.
static bool update_frequency(int index)
Computes route histogram.
static void compress_by_route(int left, int right)
Does the actual routing compression.
static void cancel_dmas(void)
Cancel any outstanding DMA transfers.
static entry_t route_cache[2][MAX_NUM_ROUTES]
Space for caching routes while going through them.
static uint32_t routes_count
Count of unique routes (as opposed to routes with just different key_masks).
static uint32_t routes_frequency[MAX_NUM_ROUTES]
Route frequency histogram.
void sort_table(void)
Implementation of insertion sort for routes based on route information.
key_mask_t key_mask
Key and mask.
uint32_t mask
Mask for the key_mask.
bool routing_table_get_entries(uint32_t start_entry, uint32_t n_entries, entry_t *output)
Gets a pointer to several entries.
Definition rt_single.h:176
static key_mask_t key_mask_merge(key_mask_t a, key_mask_t b)
Generate a new key-mask which is a combination of two other key_masks.
static void routing_table_copy_entry(int new_index, int old_index)
Copy an entry from one index to another.
uint32_t route
Routing direction.
int routing_table_get_n_entries(void)
Get the number of entries in the routing table.
Definition rt_single.h:102
static bool key_mask_intersect(key_mask_t a, key_mask_t b)
Determine if two key_masks would match any of the same keys.
entry_t * routing_table_get_entry(uint32_t entry_id_to_find)
Gets a pointer to where this entry is stored.
Definition rt_single.h:110
static void routing_table_put_entry(const entry_t *entry, int index)
Write an entry to a specific index.
uint32_t key
Key for the key_mask.
void routing_table_wait_for_last_transfer(void)
Waits for the last transfer from routing_table_get_entries to complete.
Definition rt_single.h:195
void routing_table_remove_from_size(int size_to_remove)
updates table stores accordingly.
Definition rt_single.h:106
uint32_t source
Source of packets arriving at this entry.
Holds data for a routing table entry.
RTE_SWERR
void rt_error(uint code,...)
uint rtr_alloc_max(void)
#define T2_COUNT
#define T2_CONTROL
#define DMA_CTRL
unsigned int uint
#define DMA_STAT
#define T2_LOAD