Skip to content

Commit

Permalink
Disallow repeated keys and masks
Browse files Browse the repository at this point in the history
`build_routing_tables` raises an exception if multiple nets with the
exact same key and mask would cause packets to become duplicated at any
node; this is generally an indication that the underlying net should be
being treated as a multisource net.
  • Loading branch information
mundya committed Oct 27, 2015
1 parent 0bd5432 commit e7965a9
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 57 deletions.
24 changes: 22 additions & 2 deletions rig/place_and_route/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,14 @@ def build_routing_tables(routes, net_keys, omit_default_routes=True):

# Add a routing entry when the direction changes
if (key, mask) in route_sets[(x, y)]:
# Update the existing route set if possible
# If there is an existing route set raise an error if the out
# directions are not equivalent.
if route_sets[(x, y)][(key, mask)].outs != out_directions:
raise MultisourceRouteError(key, mask, (x, y))

# Otherwise, add the input directions as this represents a
# merge of the routes.
route_sets[(x, y)][(key, mask)].ins.add(direction)
route_sets[(x, y)][(key, mask)].outs.update(out_directions)
else:
# Otherwise create a new route set
route_sets[(x, y)][(key, mask)] = _InOutPair(
Expand All @@ -136,3 +141,18 @@ def build_routing_tables(routes, net_keys, omit_default_routes=True):
)

return routing_tables


class MultisourceRouteError(Exception):
"""Indicates that two nets with the same key and mask would cause packets
to become duplicated.
"""
def __init__(self, key, mask, coordinate):
self.key = key
self.mask = mask
self.x, self.y = coordinate

def __str__(self):
return ("Two different nets with the same key ({0.key:#010x}) and "
"mask ({0.mask:#010x}) fork differently at ({0.x}, {0.y})".
format(self))
158 changes: 103 additions & 55 deletions tests/place_and_route/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pytest

from rig.place_and_route.utils import build_application_map, \
build_routing_tables

Expand Down Expand Up @@ -197,70 +199,116 @@ def test_build_routing_tables():
assert entries == [e0, e1] or entries == [e1, e0]


def test_build_routing_tables_repeated_key_mask():
# Multiple nets with the same key should be merged together
n0 = Net(object(), object())
r0 = RoutingTree((0, 0), set([(Routes.core_6, n0.sinks[0])]))
n1 = Net(object(), object())
r1 = RoutingTree((0, 0), set([(Routes.core_5, n1.sinks[0])]))
routes = {n0: r0, n1: r1}
net_keys = {n0: (0xCAFE, 0xFFFF), n1: (0xCAFE, 0xFFFF)}
assert build_routing_tables(routes, net_keys) == {
(0, 0): [RoutingTableEntry(set([Routes.core_5, Routes.core_6]),
0xCAFE, 0xFFFF)]
}
def test_build_routing_tables_repeated_key_mask_merge_allowed():
"""Nets with the same key and mask are allowed to MERGE into a SpiNNaker
node provided that they have the same outgoing route.
e.g.,
(0, 1) ----> (1, 1) ----> (2, 1)
PLUS:
(1, 1) ----> (2, 1)
^
|
|
(1, 0)
def test_build_routing_tables_repeated_key_mask_not_default():
"""The routes illustrated below have the same key and mask but should NOT
BE marked as default routes, despite the fact that each alone could be.
EQUALS:
(1, 2)
^
|
|
(0, 1) ---> (1, 1) ---> (2, 1)
^
|
|
(1, 0)
(0, 1) ----> (1, 1) ----> (2, 1)
^
|
|
(1, 0)
"""
n0 = Net(object(), object())
r0 = \
RoutingTree((0, 1), set([
(Routes.east, RoutingTree((1, 1), set([
(Routes.east, RoutingTree((2, 1), set([
(Routes.core_1, n0.sinks[0])
])))
])))
]))

n1 = Net(object(), object())
r1 = \
RoutingTree((1, 0), set([
(Routes.north, RoutingTree((1, 1), set([
(Routes.north, RoutingTree((1, 2), set([
(Routes.core_2, n1.sinks[0])
])))
])))
]))

routes = {n0: r0, n1: r1}
net_keys = {n0: (0xCAFE, 0xFFFF), n1: (0xCAFE, 0xFFFF)}
# Create the nets
sink = object()
net0 = Net(object(), sink)
net1 = Net(object(), sink)

# Create the routing trees
r0 = RoutingTree((2, 1), {(Routes.core(1), sink)})
r1 = RoutingTree((1, 1), {(Routes.west, r0)})
routes = {
net0: RoutingTree((0, 1), {(Routes.west, r1)}),
net1: RoutingTree((1, 0), {(Routes.north, r1)}),
}

# Create the keys
net_keys = {net: (0x0, 0xf) for net in (net0, net1)}

# Build the routing tables
routing_tables = build_routing_tables(routes, net_keys)

# Check that the routing tables are correct
assert routing_tables[(0, 1)] == [
RoutingTableEntry(set([Routes.east]), 0xCAFE, 0xFFFF)]
RoutingTableEntry({Routes.west}, 0x0, 0xf),
]
assert routing_tables[(1, 1)] == [
RoutingTableEntry({Routes.west}, 0x0, 0xf),
]
assert routing_tables[(2, 1)] == [
RoutingTableEntry({Routes.core(1)}, 0x0, 0xf),
]
assert routing_tables[(1, 0)] == [
RoutingTableEntry(set([Routes.north]), 0xCAFE, 0xFFFF)]
RoutingTableEntry({Routes.north}, 0x0, 0xf),
]

assert routing_tables[(2, 1)] == [
RoutingTableEntry(set([Routes.core_1]), 0xCAFE, 0xFFFF)]
assert routing_tables[(1, 2)] == [
RoutingTableEntry(set([Routes.core_2]), 0xCAFE, 0xFFFF)]

# (1, 1) SHOULD contain 1 entry
assert routing_tables[(1, 1)] == [
RoutingTableEntry(set([Routes.east, Routes.north]), 0xCAFE, 0xFFFF)]
def test_build_routing_tables_repeated_key_mask_fork_not_allowed():
"""Two nets with the same key and mask are NEVER allowed to FORK at a
SpiNNaker node.
e.g.,
(0, 1) ----> (1, 1) ----> (2, 1)
PLUS:
(1, 1) ----> (2, 1)
|
|
v
(1, 0)
IS NOT ALLOWED!
"""
# Create the nets
sink0 = object()
sink1 = object()

net0 = Net(object(), sink0)
net1 = Net(object(), [sink0, sink1])

# Create the routing trees
r_west = RoutingTree((2, 1), {(Routes.core(1), sink0)})
routes = {
net0: RoutingTree((0, 1), {
(Routes.west, RoutingTree((1, 1), {(Routes.west, r_west)})),
}),
net1: RoutingTree((1, 1), {
(Routes.west, r_west),
(Routes.south, RoutingTree((1, 0), {(Routes.core(1), sink1)})),
}),
}

# Create the keys
net_keys = {net: (0x0, 0xf) for net in (net0, net1)}

# Build the routing tables
with pytest.raises(Exception) as err:
build_routing_tables(routes, net_keys)

assert "(1, 1)" in str(err) # Co-ordinate of the fork
assert "0x00000000" in str(err) # Key that causes the problem
assert "0x0000000f" in str(err) # Mask that causes the problem

0 comments on commit e7965a9

Please sign in to comment.