SpiNNFrontEndCommon 7.3.1
Common support code for user-facing front end systems.
Loading...
Searching...
No Matches
ordered_covering.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#ifndef __ORDERED_COVERING_H__
20#define __ORDERED_COVERING_H__
21
22#include <malloc_extras.h>
23#include <debug.h>
24#include "aliases.h"
25#include "bit_set.h"
26#include "merge.h"
27#include "../common/routing_table.h"
28
30typedef struct _sets_t {
31 bit_set_t *best;
32 bit_set_t *working;
33} __sets_t;
34
39static unsigned int oc_get_insertion_point(
40 const unsigned int generality) {
41 // Perform a binary search of the table to find entries of generality - 1
42 const unsigned int g_m_1 = generality - 1;
43 int bottom = 0;
45 int pos = top / 2;
46
47 // get first entry
48 entry_t* entry = routing_table_get_entry(pos);
49 unsigned int count_xs = key_mask_count_xs(entry->key_mask);
50
51 // iterate till found something
52 while ((bottom < pos) && (pos < top) && (count_xs != g_m_1)) {
53 if (count_xs < g_m_1) {
54 bottom = pos;
55 } else {
56 top = pos;
57 }
58
59 // Update the position
60 pos = bottom + (top - bottom) / 2;
61
62 // update entry and count
63 entry = routing_table_get_entry(pos);
64 count_xs = key_mask_count_xs(entry->key_mask);
65 }
66
67 // Iterate through the table until either the next generality or the end of
68 // the table is found.
69 while (pos < routing_table_get_n_entries() &&
70 (count_xs < generality)) {
71 pos++;
72 if (pos < routing_table_get_n_entries()) {
73 entry = routing_table_get_entry(pos);
74 count_xs = key_mask_count_xs(entry->key_mask);
75 } else {
76 // FIX MUNDY LOOKING PAST END OF TABLE!
77 count_xs = 0;
78 }
79 }
80
81 return pos;
82}
83
84
94static inline bool oc_up_check(
95 merge_t *merge, int min_goodness,
96 volatile bool *stop_compressing, bool *changed) {
97 min_goodness = (min_goodness > 0) ? min_goodness : 0;
98
99 // Get the point where the merge will be inserted into the table.
100 unsigned int generality = key_mask_count_xs(merge->key_mask);
101 unsigned int insertion_index = oc_get_insertion_point(generality);
102
103 // For every entry in the merge check that the entry would not be covered by
104 // any existing entries if it were to be merged.
105
106 for (unsigned int _i = routing_table_get_n_entries(),
108 (_i > 0) && (merge_goodness(merge) > min_goodness);
109 _i--, i--) {
110 // safety check for timing limits
111 if (*stop_compressing) {
112 return false;
113 }
114
115 if (!merge_contains(merge, i)) {
116 // If this entry is not contained within the merge skip it
117 continue;
118 }
119
120 // Get the key_mask for this entry
122
123 // Otherwise look through the table from the insertion point to the
124 // current entry position to ensure that nothing covers the merge.
125 for (unsigned int j = i + 1; j < insertion_index; j++) {
127
128 // If the key masks intersect then remove this entry from the merge
129 // and recalculate the insertion index.
130 if (key_mask_intersect(km, other_km)) {
131 // Indicate the the merge has changed
132 *changed = true;
133
134 // Remove from the merge
136 generality = key_mask_count_xs(merge->key_mask);
137 insertion_index = oc_get_insertion_point(generality);
138 }
139 }
140 }
141
142 // Completely empty the merge if its goodness drops below the minimum
143 // specified
144 if (merge_goodness(merge) <= min_goodness) {
145 *changed = true;
147 }
148
149 return true;
150}
151
158static void _get_settable(
159 key_mask_t merge_km, key_mask_t covered_km, unsigned int *stringency,
160 uint32_t *set_to_zero, uint32_t *set_to_one) {
161 // We can "set" any bit where the merge contains an X and the covered
162 // entry doesn't.
163 uint32_t setable = ~key_mask_get_xs(covered_km) & key_mask_get_xs(merge_km);
164 unsigned int new_stringency = __builtin_popcount(setable);
165
166 uint32_t this_set_to_zero = setable & covered_km.key;
167 uint32_t this_set_to_one = setable & ~covered_km.key;
168
169 // The stringency indicates how many bits *could* be set to avoid the cover.
170 // If this new stringency is lower than the existing stringency then we
171 // reset which bits may be set.
172 if (new_stringency < *stringency) {
173 // Update the stringency count
174 *stringency = new_stringency;
175 *set_to_zero = this_set_to_zero;
176 *set_to_one = this_set_to_one;
177 } else if (new_stringency == *stringency) {
178 *set_to_zero |= this_set_to_zero;
179 *set_to_one |= this_set_to_one;
180 }
181}
182
189static inline __sets_t _get_removables(
190 merge_t *m, uint32_t settable, bool to_one, __sets_t sets) {
191 // For each bit which we are trying to set while the best set doesn't
192 // contain only one entry.
193 for (uint32_t bit = (1 << 31); bit > 0 && sets.best->count != 1;
194 bit >>= 1) {
195
196 // If this bit cannot be set we ignore it
197 if (!(bit & settable)) {
198 continue;
199 }
200
201 // Loop through the table adding to the working set any entries with
202 // either a X or a 0 or 1 (as specified by `to_one`) to the working set
203 // of entries to remove.
204 int entry = 0;
205 for (int i = 0; i < routing_table_get_n_entries(); i++) {
206
207 // Skip if this isn't an entry
208 if (!merge_contains(m, i)) {
209 continue;
210 }
211
212 // See if this entry should be removed
214
215 // check entry has x or 1 or 0 in this position.
216 if ((bit & ~km.mask) || (!to_one && (bit & km.key)) ||
217 (to_one && (bit & ~km.key))) {
218
219 // NOTE: Indexing by position in merge!
220 bit_set_add(sets.working, entry);
221 }
222
223 // Increment the index into the merge set
224 entry++;
225 }
226
227 // If `working` contains fewer entries than `best` or `best` is empty
228 // swap `working and best`. Otherwise just empty the working set.
229 if (sets.best->count == 0 || sets.working->count < sets.best->count) {
230 // Perform the swap
231 bit_set_t *c = sets.best;
232 sets.best = sets.working;
233 sets.working = c;
234 }
235
236 // Clear the working merge
237 bit_set_clear(sets.working);
238 }
239
240 return sets;
241}
242
243
255static bool oc_down_check(
256 merge_t *merge, int min_goodness, aliases_t *aliases,
257 bool *failed_by_malloc,
258 volatile bool *stop_compressing) {
259 min_goodness = (min_goodness > 0) ? min_goodness : 0;
260
261 while (merge_goodness(merge) > min_goodness) {
262 // safety check for timing limits
263 if (*stop_compressing) {
264 log_error("failed due to timing");
265 return false;
266 }
267
268 // Record if there were any covered entries
269 bool covered_entries = false;
270 // Not at all stringent
271 unsigned int stringency = 33;
272 // Mask of which bits could be set to zero
273 uint32_t set_to_zero = 0x0;
274 // Mask of which bits could be set to one
275 uint32_t set_to_one = 0x0;
276
277 // Look at every entry between the insertion index and the end of the
278 // table to see if there are any entries which could be covered by the
279 // entry resulting from the merge.
280 int insertion_point =
282
283 for (int i = insertion_point;
284 i < routing_table_get_n_entries() && stringency > 0;
285 i++) {
286 // safety check for timing limits
287 if (*stop_compressing) {
288 log_error("failed due to timing");
289 return false;
290 }
291
294 if (!aliases_contains(aliases, km)) {
295 // The entry doesn't contain any aliases so we need to
296 // avoid hitting the key that has just been identified.
297 covered_entries = true;
298 _get_settable(
299 merge->key_mask, km, &stringency, &set_to_zero,
300 &set_to_one);
301 } else {
302 // We need to avoid any key_masks contained within the
303 // alias table.
304 alias_list_t *the_alias_list = aliases_find(aliases, km);
305 while (the_alias_list != NULL) {
306 // safety check for timing limits
307 if (*stop_compressing) {
308 log_error("failed due to timing");
309 return false;
310 }
311 for (unsigned int j = 0; j < the_alias_list->n_elements;
312 j++) {
313
314 // safety check for timing limits
315 if (*stop_compressing) {
316 log_error("failed due to timing");
317 return false;
318 }
319
320 km = alias_list_get(the_alias_list, j).key_mask;
321
323 covered_entries = true;
324 _get_settable(
325 merge->key_mask, km, &stringency,
326 &set_to_zero, &set_to_one);
327 }
328 }
329
330 // Progress through the alias list
331 the_alias_list = the_alias_list->next;
332 }
333 }
334 }
335 }
336
337 if (!covered_entries) {
338 // If there were no covered entries then we needn't do anything
339 return true;
340 }
341
342 if (stringency == 0) {
343 // We can't avoid a covered entry at all so we need to empty the
344 // merge entirely.
346 return true;
347 }
348
349 // Determine which entries could be removed from the merge and then
350 // pick the smallest number of entries to remove.
351 __sets_t sets;
352
353 // allocate and free accordingly
354 sets.best = MALLOC(sizeof(bit_set_t));
355 if (sets.best == NULL) {
356 log_error("failed to alloc sets.best");
357 *failed_by_malloc = true;
358 return false;
359 }
360
361 sets.working = MALLOC(sizeof(bit_set_t));
362 if (sets.working == NULL) {
363 log_error("failed to alloc sets.working");
364 *failed_by_malloc = true;
365
366 // free stuff already malloc
367 bit_set_delete(sets.best);
368 FREE(sets.best);
369 return false;
370 }
371
372 bool success = bit_set_init(sets.best, merge->entries.count);
373 if (!success) {
374 log_error("failed to init the bitfield best");
375 *failed_by_malloc = true;
376
377 // free stuff already malloc
378 bit_set_delete(sets.best);
379 bit_set_delete(sets.working);
380 FREE(sets.best);
381 FREE(sets.working);
382 return false;
383 }
384
385 success = bit_set_init(sets.working, merge->entries.count);
386 if (!success) {
387 log_error("failed to init the bitfield working.");
388 *failed_by_malloc = true;
389
390 // free stuff already malloc
391 bit_set_delete(sets.best);
392 bit_set_delete(sets.working);
393 FREE(sets.best);
394 FREE(sets.working);
395 return false;
396 }
397
398 // Get the entries that can be removed because of the filtering we have
399 // computed above
400 sets = _get_removables(merge, set_to_zero, false, sets);
401 sets = _get_removables(merge, set_to_one, true, sets);
402
403 // Remove the specified entries
404 int entry = 0;
405 for (int i = 0; i <routing_table_get_n_entries(); i++) {
406 // safety check for timing limits
407 if (*stop_compressing) {
408 log_error("failed due to timing");
409 bit_set_delete(sets.best);
410 bit_set_delete(sets.working);
411 FREE(sets.best);
412 FREE(sets.working);
413 return false;
414 }
415
416 if (merge_contains(merge, i)) {
417 if (bit_set_contains(sets.best, entry)) {
418 // Remove this entry from the merge
420 }
421 entry++;
422 }
423 }
424
425 // Tidy up
426 bit_set_delete(sets.best);
427 FREE(sets.best);
428 sets.best=NULL;
429 bit_set_delete(sets.working);
430 FREE(sets.working);
431 sets.working=NULL;
432
433 // If the merge only contains 1 entry empty it entirely
434 if (merge->entries.count == 1) {
435 log_debug("final merge clear");
437 }
438 }
439 log_debug("returning from down check");
440 return true;
441}
442
443
451static inline bool oc_get_best_merge(
452 aliases_t *aliases, merge_t *best, bool *failed_by_malloc,
453 volatile bool *stop_compressing) {
454 // Keep track of which entries have been considered as part of merges.
455 bit_set_t considered;
456 bool success = bit_set_init(
457 &considered, routing_table_get_n_entries());
458 if (!success) {
459 log_warning("failed to initialise the bit_set. throwing response malloc");
460 *failed_by_malloc = true;
461 return false;
462 }
463
464 // Keep track of the current best merge and also provide a working merge
465 merge_t working;
466
467 success = merge_init(best, routing_table_get_n_entries());
468 if (!success) {
469 log_warning("failed to init the merge best. throw response malloc");
470 *failed_by_malloc = true;
471
472 // free bits we already done
473 bit_set_delete(&considered);
474
475 // return false
476 return false;
477 }
478
479 success = merge_init(&working, routing_table_get_n_entries());
480 if (!success) {
481 log_warning("failed to init the merge working. throw response malloc");
482 *failed_by_malloc = true;
483
484 // free bits we already done
485 merge_delete(best);
486 bit_set_delete(&considered);
487
488 // return false
489 return false;
490 }
491
492 // For every entry in the table see with which other entries it could be
493 // merged.
494 log_debug("starting search for merge entry");
495 for (int i = 0; i < routing_table_get_n_entries(); i++) {
496 // safety check for timing limits
497 if (*stop_compressing) {
498 log_info("closed due to stop request");
499 // free bits we already done
500 merge_delete(best);
501 bit_set_delete(&considered);
502 return false;
503 }
504
505 // If this entry has already been considered then skip to the next
506 if (bit_set_contains(&considered, i)) {
507 continue;
508 }
509
510 // Otherwise try to build a merge
511 // Clear the working merge
512 merge_clear(&working);
513
514 // Add to the merge
515 merge_add(&working, i);
516
517 // Mark this entry as considered
518 bit_set_add(&considered, i);
519
520 // Get the entry
522
523 // Try to merge with other entries
524 log_debug("starting second search at index %d", i);
525 for (int j = i+1; j < routing_table_get_n_entries(); j++) {
526 // safety check for timing limits
527 if (*stop_compressing) {
528 log_info("closed due to stop request");
529 // free bits we already done
530 merge_delete(best);
531 bit_set_delete(&considered);
532 return false;
533 }
534
535 // Get the other entry
537
538 // check if merge-able
539 if (entry->route == other->route) {
540 // If the routes are the same then the entries may be merged
541 // Add to the merge
542 merge_add(&working, j);
543
544 // Mark the other entry as considered
545 bit_set_add(&considered, j);
546 }
547 }
548
549 if (merge_goodness(&working) <= merge_goodness(best)) {
550 continue;
551 }
552
553 // Perform the first down check
554 success = oc_down_check(
555 &working, merge_goodness(best), aliases, failed_by_malloc,
556 stop_compressing);
557 if (!success) {
558 log_error("failed to down check.");
559
560 // free bits we already done
561 merge_delete(best);
562 bit_set_delete(&considered);
563
564 return false;
565 }
566
567 if (merge_goodness(&working) <= merge_goodness(best)) {
568 continue;
569 }
570
571 // Perform the up check, seeing if this actually makes a change to the
572 // size of the merge.
573 bool changed = false;
574 success = oc_up_check(
575 &working, merge_goodness(best), stop_compressing, &changed);
576 if (!success) {
577 log_info("failed to upcheck");
578 // free bits we already done
579 merge_delete(best);
580 bit_set_delete(&considered);
581 return false;
582 }
583
584 // if changed the merge
585 if (changed) {
586 if (merge_goodness(&working) <= merge_goodness(best)) {
587 continue;
588 }
589
590 // If the up check did make a change then the down check needs to
591 // be run again.
592 log_debug("down check");
593 success = oc_down_check(
594 &working, merge_goodness(best), aliases, failed_by_malloc,
595 stop_compressing);
596 if (!success) {
597 log_error("failed to down check. ");
598
599 // free bits we already done
600 merge_delete(best);
601 bit_set_delete(&considered);
602
603 return false;
604 }
605 }
606
607 // If the merge is still better than the current best merge we swap the
608 // current and best merges to record the new best merge.
609 if (merge_goodness(best) < merge_goodness(&working)) {
610 merge_t other = working;
611 working = *best;
612 *best = other;
613 }
614 }
615
616 // Tidy up
617 merge_delete(&working);
618 bit_set_delete(&considered);
619 log_debug("n entries is %d", routing_table_get_n_entries());
620 // found the best merge. return true
621 return true;
622}
623
624
630static inline bool oc_merge_apply(
631 merge_t *merge, aliases_t *aliases, bool *failed_by_malloc) {
632 // Get the new entry
633 entry_t new_entry;
634 new_entry.key_mask = merge->key_mask;
635 new_entry.route = merge->route;
636 new_entry.source = merge->source;
637
638 log_debug("new entry k %x mask %x route %x source %x x mergable is %d",
639 new_entry.key_mask.key, new_entry.key_mask.mask, new_entry.route,
640 new_entry.source, merge->entries.count);
641
642 // Get the insertion point for the new entry
643 int insertion_point =
645 log_debug("the insertion point is %d", insertion_point);
646
647 // Keep track of the amount of reduction of the finished table
648 int reduced_size = 0;
649
650 // Create a new aliases list with sufficient space for the key_masks of all
651 // of the entries in the merge. NOTE: IS THIS REALLY REQUIRED!?
652 log_debug("new alias");
653 alias_list_t *new_aliases = alias_list_new(merge->entries.count);
654 if (new_aliases == NULL) {
655 log_error("failed to malloc new alias list");
656 *failed_by_malloc = true;
657 return false;
658 }
659
660 log_debug("alias insert");
661 bool malloc_success =
662 aliases_insert(aliases, new_entry.key_mask, new_aliases);
663 if (!malloc_success) {
664 log_error("failed to malloc new alias list during insert");
665 *failed_by_malloc = true;
666 return false;
667 }
668
669 // Use two iterators to move through the table copying entries from one
670 // position to the other as required.
671 int insert = 0;
672
673 log_debug("routing table entries = %d", routing_table_get_n_entries());
674
675 for (int remove = 0; remove < routing_table_get_n_entries(); remove++) {
676 // Grab the current entry before we possibly overwrite it
677 entry_t* current = routing_table_get_entry(remove);
678 log_debug("bacon");
679 log_debug("entry %d being processed has key %x or %d, mask %x "
680 "route %x source %x", remove, current->key_mask.key,
681 current->key_mask.key, current->key_mask.mask, current->route,
682 current->source);
683 // Insert the new entry if this is the correct position at which to do
684 // so
685 if (remove == insertion_point) {
686 log_debug("remove == insert at index %d and insert %d at "
687 "insert point", remove, insert);
688
689 entry_t *insert_entry = routing_table_get_entry(insert);
690
691 // move data between entries
692 insert_entry->key_mask.key = new_entry.key_mask.key;
693 insert_entry->key_mask.mask = new_entry.key_mask.mask;
694 insert_entry->route = new_entry.route;
695 insert_entry->source = new_entry.source;
696 insert++;
697 }
698
699 // If this entry is not contained within the merge then copy it from its
700 // current position to its new position.
701 if (!merge_contains(merge, remove)) {
702 log_debug("not contains at index %d and insert %d at insert point",
703 remove, insert);
704
705 entry_t *insert_entry = routing_table_get_entry(insert);
706
707 // move data between entries
708 insert_entry->key_mask.key = current->key_mask.key;
709 insert_entry->key_mask.mask = current->key_mask.mask;
710 insert_entry->route = current->route;
711 insert_entry->source = current->source;
712 insert++;
713
714 } else {
715 log_debug("merge contains at index %d and insert %d at "
716 "insert point", remove, insert);
717
718 // Otherwise update the aliases table to account for the entry
719 // which is being merged.
720 key_mask_t km = current->key_mask;
721 uint32_t source = current->source;
722
723 if (aliases_contains(aliases, km)) {
724 // Join the old list of aliases with the new
725 alias_list_join(new_aliases, aliases_find(aliases, km));
726
727 // Remove the old aliases entry
728 aliases_remove(aliases, km);
729 } else {
730 // Include the key_mask in the new list of aliases
731 alias_list_append(new_aliases, km, source);
732 }
733
734 // Decrement the final table size to account for this entry being
735 // removed.
736 reduced_size++;
737
738 log_debug("at index %d and insert %d not at merge point",
739 remove, insert);
740 }
741 }
742
743 log_debug("alias delete");
744 alias_list_delete(new_aliases);
745 log_debug("alias delete end");
746
747 // If inserting beyond the old end of the table then perform the insertion
748 // at the new end of the table.
749 if (insertion_point == routing_table_get_n_entries()) {
750 log_debug("insert point was at end of table, new insert point is %d",
751 insert);
752 entry_t *insert_entry = routing_table_get_entry(insert);
753 insert_entry->key_mask.key = new_entry.key_mask.key;
754 insert_entry->key_mask.mask = new_entry.key_mask.mask;
755 insert_entry->route = new_entry.route;
756 insert_entry->source = new_entry.source;
757 }
758
759 // Record the new size of the table
760 routing_table_remove_from_size(reduced_size - 1);
761 return true;
762}
763
764
774 int target_length, bool *failed_by_malloc,
775 volatile bool *stop_compressing) {
776 // check if any compression actually needed
777 log_debug("n entries before compression is %d",
779
780 if (routing_table_get_n_entries() < target_length) {
781 log_info("does not need compression.");
782 return true;
783 }
784
785 // Some Mundy black magic
786 aliases_t aliases = aliases_init();
787
788 // start the merger process
789 log_debug("n entries is %d", routing_table_get_n_entries());
790 int attempts = 0;
791
792 while ((routing_table_get_n_entries() > target_length) &&
793 !*stop_compressing) {
794 log_debug("n entries is %d", routing_table_get_n_entries());
795
796 // Get the best possible merge, if this merge is empty then break out
797 // of the loop.
799 bool success = oc_get_best_merge(
800 &aliases, &merge, failed_by_malloc, stop_compressing);
801 if (!success) {
802 log_debug("failed to do get best merge. "
803 "the number of merge cycles were %d", attempts);
804 aliases_clear(&aliases);
805 return false;
806 }
807
808 log_debug("best merge end");
809 unsigned int count = merge.entries.count;
810
811 if (count > 1) {
812 // Apply the merge to the table if it would result in merging
813 // actually occurring.
814 //routing_tables_print_out_table_sizes();
815 log_debug("merge apply");
816 bool malloc_success = oc_merge_apply(
817 &merge, &aliases, failed_by_malloc);
818
819 if (!malloc_success) {
820 log_error("failed to malloc");
821 aliases_clear(&aliases);
822 return false;
823 }
824 log_debug("merge apply end");
825 //routing_tables_print_out_table_sizes();
826 }
827
828 // Free any memory used by the merge
829 log_debug("merge delete");
831 log_debug("merge delete end");
832
833 // Break out of the loop if no merge could be performed (indicating
834 // that no more minimisation is possible).
835 if (count < 2) {
836 break;
837 }
838 attempts += 1;
839 }
840
841 // shut down timer. as passed the compression
842 spin1_pause();
843
844 // if it failed due to timing, report and then reset and fail.
845 if (*stop_compressing) {
846 log_info("Asked to stop. reached %d entries over %d attempts",
847 routing_table_get_n_entries(), attempts);
848 spin1_pause();
849 aliases_clear(&aliases);
850 return false;
851 }
852
853 log_info("entries after compressed = %d, target_length = %d, stop = %d, "
854 " the number of merge cycles were %d",
855 routing_table_get_n_entries(), target_length, *stop_compressing,
856 attempts);
857
858 log_debug("compressed!!!");
859 log_debug("produced table with %d entries", routing_table_get_n_entries());
860 aliases_clear(&aliases);
861 return true;
862}
863
864#endif // __ORDERED_COVERING_H__
Aliases in the routing tree.
static bool aliases_insert(aliases_t *a, key_mask_t key, alias_list_t *value)
Add/overwrite an element into an aliases tree.
Definition aliases.h:301
static bool alias_list_append(alias_list_t *as, key_mask_t val, uint32_t source)
Append an element to a list.
Definition aliases.h:77
unsigned int n_elements
Elements in this instance.
Definition aliases.h:43
struct _alias_list_t * next
Next element in list of lists.
Definition aliases.h:47
void alias_list_delete(alias_list_t *a)
Delete all elements in an alias list.
Definition aliases.h:112
static alias_list_t * alias_list_new(unsigned int max_size)
Create a new list on the stack.
Definition aliases.h:55
key_mask_t key_mask
key_mask of the element
Definition aliases.h:34
static void alias_list_join(alias_list_t *a, alias_list_t *b)
Append a list to an existing list.
Definition aliases.h:100
static alias_list_t * aliases_find(aliases_t *a, key_mask_t key)
Retrieve an element from an aliases container.
Definition aliases.h:193
static bool aliases_contains(aliases_t *a, key_mask_t key)
See if the aliases contain holds an element.
Definition aliases.h:206
static alias_element_t alias_list_get(alias_list_t *as, unsigned int i)
Get an element from the list.
Definition aliases.h:93
static void aliases_remove(aliases_t *a, key_mask_t key)
Remove an element from an aliases tree.
Definition aliases.h:312
static aliases_t aliases_init(void)
Create a new, empty, aliases container.
Definition aliases.h:162
static void aliases_clear(aliases_t *a)
Remove all elements from an aliases container and free all sub-containers.
Definition aliases.h:349
Linked list of arrays.
Definition aliases.h:41
top of tree
Definition aliases.h:155
Sets of bits.
bool bit_set_clear(bit_set_t *b)
Empty a bitset entirely.
Definition bit_set.h:50
static bool bit_set_add(bit_set_t *b, unsigned int i)
Add an element to a bitset.
Definition bit_set.h:100
static bool bit_set_contains(bit_set_t *b, unsigned int i)
Test if an element is in a bitset.
Definition bit_set.h:121
static bool bit_set_init(bit_set_t *b, unsigned int length)
Create a new bitset.
Definition bit_set.h:65
static void bit_set_delete(bit_set_t *b)
Destroy a bitset.
Definition bit_set.h:89
wrapper over bitfield
Definition bit_set.h:33
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_warning(const char *message,...)
This function logs warnings.
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.
Support for adding debugging information to dynamic allocation.
#define MALLOC
An easily-insertable name for the memory allocator.
#define FREE
An easily-insertable name for the memory free.
How to merge routing table entries.
static int merge_goodness(merge_t *merge)
Get the goodness for a merge.
Definition merge.h:55
static void merge_clear(merge_t *m)
Clear a merge.
Definition merge.h:61
static bool merge_contains(merge_t *m, unsigned int i)
See if an entry is contained within a merge.
Definition merge.h:121
static void merge_delete(merge_t *m)
Destroy a merge.
Definition merge.h:88
static void merge_remove(merge_t *m, unsigned int i)
Remove an entry from the merge.
Definition merge.h:129
static bool merge_init(merge_t *m, uint32_t n_entries_in_table)
Initialise a merge.
Definition merge.h:76
static void merge_add(merge_t *m, unsigned int i)
Add an entry to the merge.
Definition merge.h:96
merge struct. entries which can be merged
Definition merge.h:26
static bool oc_up_check(merge_t *merge, int min_goodness, volatile bool *stop_compressing, bool *changed)
Remove from a merge any entries which would be covered by being existing entries if they were include...
static bool oc_down_check(merge_t *merge, int min_goodness, aliases_t *aliases, bool *failed_by_malloc, volatile bool *stop_compressing)
Remove entries from a merge such that the merge would not cover existing entries positioned below the...
static bool oc_get_best_merge(aliases_t *aliases, merge_t *best, bool *failed_by_malloc, volatile bool *stop_compressing)
Get the best merge which can be applied to a routing table.
static unsigned int oc_get_insertion_point(const unsigned int generality)
Get the index where the routing table entry resulting from a merge should be inserted.
bool minimise_run(int target_length, bool *failed_by_malloc, volatile bool *stop_compressing)
Apply the ordered covering algorithm to a routing table.
static bool oc_merge_apply(merge_t *merge, aliases_t *aliases, bool *failed_by_malloc)
Apply a merge to the table against which it is defined.
static entry_t merge(const entry_t *entry1, const entry_t *entry2)
Merges a single pair of route entries.
key_mask_t key_mask
Key and mask.
uint32_t mask
Mask for the key_mask.
static uint32_t key_mask_get_xs(key_mask_t km)
Get a mask of the Xs in a key_mask.
static unsigned int key_mask_count_xs(key_mask_t km)
Get a count of the Xs in a key_mask.
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
uint32_t key
Key for the key_mask.
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.
Holds key and mask.
#define NULL
void spin1_pause(void)