SpiNNFrontEndCommon 7.4.2
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>
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
80static inline void cancel_dmas(void) {
81 dma[DMA_CTRL] = 0x3F;
82 while (dma[DMA_STAT] & 0x1) {
83 continue;
84 }
85 dma[DMA_CTRL] = 0xD;
86 while (dma[DMA_CTRL] & 0xD) {
87 continue;
88 }
89}
90
97static inline bool find_merge(int left, int index) {
98 log_debug("find merge %d %d", left, index);
100 const entry_t *entry1 = routing_table_get_entry(left);
101 const entry_t *entry2 = routing_table_get_entry(index);
102 const entry_t merged = merge(entry1, entry2);
103
104 for (int check = remaining_index;
106 check++) {
107 const entry_t *check_entry =
109 if (key_mask_intersect(check_entry->key_mask, merged.key_mask)) {
110 return false;
111 }
112 }
113
114 routing_table_put_entry(&merged, left);
115 return true;
116}
117
121static inline void compress_by_route(int left, int right) {
122 log_debug("merge left %d right %d", left, right);
123 while (left < right) {
124 bool merged = false;
125
126 for (int index = left + 1; index <= right; index++) {
127 merged = find_merge(left, index);
128 if (merged) {
129 routing_table_copy_entry(index, right--);
130 break;
131 }
132 }
133 if (!merged) {
135 }
136 }
137 if (left == right) {
139 }
140}
141
144static void sort_routes(void) {
145 uint32_t i, j;
146
147 for (i = 1; i < routes_count; i++) {
148 // The entry we're going to move is "taken out"
149 uint32_t r_tmp = routes[i];
150 uint32_t rf_tmp = routes_frequency[i];
151
152 // The entries below it that are larger are shuffled up
153 for (j = i; j > 0 && routes_frequency[j - 1] > rf_tmp; j--) {
154 routes[j] = routes[j - 1];
156 }
157
158 // The entry is dropped back into place
159 routes[j] = r_tmp;
160 routes_frequency[j] = rf_tmp;
161 }
162}
163
167static inline bool update_frequency(int index) {
168 uint32_t route = routing_table_get_entry(index)->route;
169 log_debug("index %d routes %d", index, route);
170 for (uint i = 0; i < routes_count; i++) {
171 if (routes[i] == route) {
172 routes_frequency[i]++;
173 return true;
174 }
175 }
176 routes[routes_count] = route;
178 routes_count++;
180 if (standalone()) {
181 log_error("Too many different routes to compress found %d "
182 "compared to max legal of %d",
184 }
185 return false;
186 }
187 return true;
188}
189
190static inline uint32_t find_route_index(uint32_t route) {
191 for (uint32_t i = 0; i < routes_count; i++) {
192 if (route == routes[i]) {
193 return i;
194 }
195 }
196 log_error("Route 0x%08x not found!", route);
197 for (uint32_t i = 0; i < routes_count; i++) {
198 log_error("Route %u = 0x%08x", i, routes[i]);
199 }
200 rt_error(RTE_SWERR);
201 return 0xFFFFFFFF;
202}
203
207void sort_table(void) {
208 if (routes_count == 0) {
209 return;
210 }
211
212 // Set up a pointer for each of the routes
213 uint16_t route_offset[routes_count];
214 uint16_t route_end[routes_count];
215 uint32_t offset = 0;
216 for (uint32_t i = 0; i < routes_count; i++) {
217 route_offset[i] = offset;
218 offset += routes_frequency[i];
219 route_end[i] = offset - 1;
220 }
221
222 // Go through and move things into position
223 uint32_t pos = 0;
224 uint32_t pos_index = 0;
225 uint32_t next_index_offset = routes_frequency[0];
226 uint32_t n_entries = routing_table_get_n_entries();
227 while (pos < n_entries) {
228 // Get the entry
229 entry_t entry = *routing_table_get_entry(pos);
230
231 // Where does the route need to go
232 uint32_t route_index = find_route_index(entry.route);
233
234 // Where are we reading from?
235 uint32_t read_index = pos_index;
236
237 // If we are in the right region
238 bool skip = false;
239 if (route_index == read_index) {
240 // If we already put this item here, don't move it
241 if (pos < route_offset[route_index]) {
242 skip = true;
243 }
244 }
245
246 // Keep swapping things until they are in the right place
247 while (!skip) {
248
249 // Find the place to put the route in its group
250 uint32_t new_pos = route_offset[route_index];
251 if (new_pos >= n_entries) {
252 log_error("New table position %u out of range!", new_pos);
254 }
255
256 if (new_pos > route_end[route_index]) {
257 log_error("New table position %u of region %u is out of range!",
258 new_pos, route_index);
260 }
261 route_offset[route_index] += 1;
262
263 // Swap out the existing entry with the new one
264 entry_t old_entry = *routing_table_get_entry(new_pos);
265 routing_table_put_entry(&entry, new_pos);
266
267 // We can quit because we should have moved this one
268 if (new_pos <= pos) {
269 break;
270 }
271 entry = old_entry;
272 read_index = route_index;
273
274 // Find the index of the item we swapped out so it can be swapped next
275 route_index = find_route_index(entry.route);
276 }
277
278 // Where are we next
279 pos++;
280 if (pos == next_index_offset) {
281 pos_index += 1;
282 next_index_offset += routes_frequency[pos_index];
283 }
284 }
285}
286
293bool minimise_run(int target_length, bool *failed_by_malloc,
294 volatile bool *stop_compressing) {
295 use(failed_by_malloc);
296 use(target_length);
297
298 // Verify constant used to build arrays is correct
300 log_error("MAX_NUM_ROUTES %d != rtr_alloc_max() %d",
302 return false;
303 }
304 int table_size = routing_table_get_n_entries();
305
306 routes_count = 0;
307
308 for (int index = 0; index < table_size; index++) {
309 if (!update_frequency(index)) {
310 return false;
311 }
312 }
313
314 log_debug("before sort %u", routes_count);
315 for (uint i = 0; i < routes_count; i++) {
316 log_debug("%u", routes[i]);
317 }
318
319 sort_routes();
320 if (*stop_compressing) {
321 log_info("Stopping as asked to stop");
322 return false;
323 }
324
325 log_debug("after sort %u", routes_count);
326 for (uint i = 0; i < routes_count; i++) {
327 log_debug("%u", routes[i]);
328 }
329
330 log_debug("do sort_table by route %u", table_size);
331 tc[T2_LOAD] = 0xFFFFFFFF;
332 tc[T2_CONTROL] = 0x83;
333 sort_table();
334 uint32_t duration = 0xFFFFFFFF - tc[T2_COUNT];
335 tc[T2_CONTROL] = 0;
336 log_info("Sorting table took %u clock cycles", duration);
337 if (*stop_compressing) {
338 log_info("Stopping before compression as asked to stop");
339 return false;
340 }
341
342 write_index = 0;
343 int max_index = table_size - 1;
344 int left = 0;
345
346 while (left <= max_index) {
347 int right = left;
348 uint32_t left_route = routing_table_get_entry(left)->route;
349 log_debug("A %u %u %u %u", left, max_index, right, left_route);
350 while ((right < table_size - 1) &&
351 routing_table_get_entry(right+1)->route ==
352 left_route) {
353 right++;
354 }
355 remaining_index = right + 1;
356 log_debug("compress %u %u", left, right);
357 tc[T2_LOAD] = 0xFFFFFFFF;
358 tc[T2_CONTROL] = 0x83;
359 compress_by_route(left, right);
360 duration = 0xFFFFFFFF - tc[T2_COUNT];
361 tc[T2_CONTROL] = 0;
362 log_info("Compressing %u routes took %u", right - left + 1, duration);
363 if (write_index > rtr_alloc_max()){
364 if (standalone()) {
365 log_error("Compression not possible as already found %d "
366 "entries where max allowed is %d",
368 }
369 return false;
370 }
371 if (*stop_compressing) {
372 log_info("Stopping during compression as asked to stop");
373 return false;
374 }
375 left = right + 1;
376 }
377
378 log_debug("done %u %u", table_size, write_index);
379
380 //for (uint i = 0; i < write_index; i++) {
381 // entry_t *entry1 = routing_table_get_entry(i);
382 // log_info("%u route:%u source:%u key:%u mask:%u",i, entry1->route,
383 // entry1->source, entry1->key_mask.key, entry1->key_mask.mask);
384 //}
387 return true;
388}
#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 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.
Utilities for a single routing table.
key_mask_t key_mask
Key and mask.
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.
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.
static void routing_table_put_entry(const entry_t *entry, int index)
Write an entry to a specific index.
void routing_table_remove_from_size(int size_to_remove)
updates table stores accordingly.
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