def test_get_all_routes_empty(self): """ Test that model.get_all_routes finds some in a system containing some """ chips = model.make_rectangular_board(2,2) # A set of test routes ref_routes = { # Unicast self loop model.Route(0): (chips[(0,0)].cores[0], set([chips[(0,0)].cores[0]])), # Broadcast to all cores on a chip model.Route(1): (chips[(0,0)].cores[0], set(chips[(0,0)].cores.itervalues())), # Multicast messages from everyone from them to two other chips model.Route(2): (chips[(0,0)].cores[0], set([chips[(1,0)].cores[0], chips[(1,1)].cores[1]])), model.Route(3): (chips[(1,0)].cores[0], set([chips[(0,0)].cores[0], chips[(0,1)].cores[1]])), model.Route(4): (chips[(0,1)].cores[0], set([chips[(1,1)].cores[0], chips[(1,0)].cores[1]])), model.Route(5): (chips[(1,1)].cores[0], set([chips[(0,1)].cores[0], chips[(0,0)].cores[1]])), } # Add the reference routes to the network for route, (source, sinks) in ref_routes.iteritems(): source.sources.add(route) for sink in sinks: sink.sinks.add(route) # Check that the routes found match the routes added found_routes = model.get_all_routes(chips) self.assertEqual(len(found_routes), len(ref_routes)) for route, (source, sinks) in found_routes.iteritems(): self.assertEqual(ref_routes[route][0], source) self.assertEqual(ref_routes[route][1], sinks)
def test_get_all_routes_empty(self): """ Test that model.get_all_routes finds some in a system containing some """ chips = model.make_rectangular_board(2,2) # A set of test routes ref_routes = { # Unicast self loop model.Route(0): (chips[(0,0)][1][0], set([chips[(0,0)][1][0]])), # Broadcast to all cores on a chip model.Route(1): (chips[(0,0)][1][0], set(chips[(0,0)][1])), # Multicast messages from everyone from them to two other chips model.Route(2): (chips[(0,0)][1][0], set([chips[(1,0)][1][0], chips[(1,1)][1][1]])), model.Route(3): (chips[(1,0)][1][0], set([chips[(0,0)][1][0], chips[(0,1)][1][1]])), model.Route(4): (chips[(0,1)][1][0], set([chips[(1,1)][1][0], chips[(1,0)][1][1]])), model.Route(5): (chips[(1,1)][1][0], set([chips[(0,1)][1][0], chips[(0,0)][1][1]])), } # Add the reference routes to the network for route, (source, sinks) in ref_routes.iteritems(): source.sources.add(route) for sink in sinks: sink.sinks.add(route) # Check that the routes found match the routes added found_routes = model.get_all_routes(chips) self.assertEqual(len(found_routes), len(ref_routes)) for route, (source, sinks) in found_routes.iteritems(): self.assertEqual(ref_routes[route][0], source) self.assertEqual(ref_routes[route][1], sinks)
def test_is_path_connected(self): """ Test that the is_path_connected function works on a set of example cases. """ chips = model.make_rectangular_board(4,1) for is_connected, path in [ # Self-loop (True, [chips[(0,0)].cores[0], chips[(0,0)].router, chips[(0,0)].cores[0]]), # From one end to another (True, [ chips[(0,0)].cores[10], chips[(0,0)].router, chips[(1,0)].router , chips[(2,0)].router, chips[(3,0)].router, chips[(3,0)].cores[11] ]), # Reverse direction... (True, [ chips[(3,0)].cores[10], chips[(3,0)].router, chips[(2,0)].router , chips[(1,0)].router, chips[(0,0)].router, chips[(0,0)].cores[11] ]), # Self loop without router (False, [chips[(0,0)].cores[0], chips[(0,0)].cores[0]]), # From one chip to another non-adjacent chip (False, [ chips[(0,0)].cores[10], chips[(0,0)].router , chips[(2,0)].router, chips[(2,0)].cores[11] ]), ]: self.assertEqual(is_connected, model.is_path_connected(path))
def test_is_path_connected(self): """ Test that the is_path_connected function works on a set of example cases. """ chips = model.make_rectangular_board(4,1) for is_connected, path in [ # Self-loop (True, [chips[(0,0)][1][0], chips[(0,0)][0], chips[(0,0)][1][0]]), # From one end to another (True, [ chips[(0,0)][1][10], chips[(0,0)][0], chips[(1,0)][0] , chips[(2,0)][0], chips[(3,0)][0], chips[(3,0)][1][11] ]), # Reverse direction... (True, [ chips[(3,0)][1][10], chips[(3,0)][0], chips[(2,0)][0] , chips[(1,0)][0], chips[(0,0)][0], chips[(0,0)][1][11] ]), # Self loop without router (False, [chips[(0,0)][1][0], chips[(0,0)][1][0]]), # From one chip to another non-adjacent chip (False, [ chips[(0,0)][1][10], chips[(0,0)][0] , chips[(2,0)][0], chips[(2,0)][1][11] ]), ]: self.assertEqual(is_connected, model.is_path_connected(path))
def test_make_rectangular_board(self): """ Test that a model.make_rectangular_board creates the appropriate formation of chips. """ for (w,h) in [(1,1), (1,2), (2,1), (2,2)]: chips = model.make_rectangular_board(w,h) # Ensure correct number of nodes self.assertEqual(len(chips), w*h) # Ensure nodes exist in correct places for y in range(h): for x in range(w): self.assertIn((x,y), chips.keys())
def setUp(self): """ Create a small network with a few routes within it. """ self.chips = model.make_rectangular_board(3,3) # A self-loop on 0,1,0 model.add_route(model.Route(0), [ self.chips[(0,1)].cores[0] , self.chips[(0,1)].router , self.chips[(0,1)].cores[0] ]) # A straight route from 0,0,0 to 2,0,0 model.add_route(model.Route(1), [ self.chips[(0,0)].cores[0] , self.chips[(0,0)].router , self.chips[(1,0)].router , self.chips[(2,0)].router , self.chips[(2,0)].cores[0] ]) # A multicast from from 0,2,0 to 1,2,0, 2,2,0 and 1,1,0 r = model.Route(2) model.add_route(r, [ self.chips[(0,2)].cores[0] , self.chips[(0,2)].router , self.chips[(1,2)].router , self.chips[(1,2)].cores[0] ]) model.add_route(r, [ self.chips[(0,2)].cores[0] , self.chips[(0,2)].router , self.chips[(1,2)].router , self.chips[(2,2)].router , self.chips[(2,2)].cores[0] ]) model.add_route(r, [ self.chips[(0,2)].cores[0] , self.chips[(0,2)].router , self.chips[(1,2)].router , self.chips[(1,1)].router , self.chips[(1,1)].cores[0] ]) # A self-loop on 1,1,1 to result in 1,1 having multiple routing entries model.add_route(model.Route(3), [ self.chips[(1,1)].cores[1] , self.chips[(1,1)].router , self.chips[(1,1)].cores[1] ])
def setUp(self): """ Create a small network with a few routes within it. """ self.chips = model.make_rectangular_board(3,3) # A self-loop on 0,1,0 model.add_route(model.Route(0), [ self.chips[(0,1)][1][0] , self.chips[(0,1)][0] , self.chips[(0,1)][1][0] ]) # A straight route from 0,0,0 to 2,0,0 model.add_route(model.Route(1), [ self.chips[(0,0)][1][0] , self.chips[(0,0)][0] , self.chips[(1,0)][0] , self.chips[(2,0)][0] , self.chips[(2,0)][1][0] ]) # A multicast from from 0,2,0 to 1,2,0, 2,2,0 and 1,1,0 r = model.Route(2) model.add_route(r, [ self.chips[(0,2)][1][0] , self.chips[(0,2)][0] , self.chips[(1,2)][0] , self.chips[(1,2)][1][0] ]) model.add_route(r, [ self.chips[(0,2)][1][0] , self.chips[(0,2)][0] , self.chips[(1,2)][0] , self.chips[(2,2)][0] , self.chips[(2,2)][1][0] ]) model.add_route(r, [ self.chips[(0,2)][1][0] , self.chips[(0,2)][0] , self.chips[(1,2)][0] , self.chips[(1,1)][0] , self.chips[(1,1)][1][0] ]) # A self-loop on 1,1,1 to result in 1,1 having multiple routing entries model.add_route(model.Route(3), [ self.chips[(1,1)][1][1] , self.chips[(1,1)][0] , self.chips[(1,1)][1][1] ])
def test_dor_dead_links(self): """ Test dimension-order-routing in the case where routing is not possible. """ # Create a square system with a hole in the x-axis for the 0th row of chips. chips = model.make_rectangular_board(3, 1) chips[(1,0)].router.connections[topology.EAST] = None # Should not be able to route along the x axis of the system. node_sequences, unrouted_sinks = \ routers.dimension_order_route( chips[(0,0)].cores[0] , [chips[(2,0)].cores[0]] , chips , use_wrap_around = False , dimension_order = (0,1,2) ) self.assertFalse(node_sequences) self.assertEqual(len(unrouted_sinks), 1)
def test_dor_dead_links(self): """ Test dimension-order-routing in the case where routing is not possible. """ # Create a square system with a hole in the x-axis for the 0th row of chips. chips = model.make_rectangular_board(3, 1) chips[(1,0)][0].connections[topology.EAST] = None # Should not be able to route along the x axis of the system. node_sequences, unrouted_sinks = \ routers.dimension_order_route( chips[(0,0)][1][0] , [chips[(2,0)][1][0]] , chips , use_wrap_around = False , dimension_order = (0,1,2) ) self.assertFalse(node_sequences) self.assertEqual(len(unrouted_sinks), 1)
def test_dor_perfect_case(self): """ Test dimension-order-routing in the case where routing should be possible. """ width = 5 height = 5 port_to_dimension = { topology.EAST: 0, topology.WEST: 0, topology.NORTH: 1, topology.SOUTH: 1, topology.NORTH_EAST: 2, topology.SOUTH_WEST: 2, } for wrap_around in (True, False): chips = model.make_rectangular_board(width, height, wrap_around = wrap_around) for dimension_order in ( (0,1,2), (2,1,0) ): for route, source, sinks in ( # Self-loop (model.Route(0), chips[(0,0)].cores[0], ( chips[(0,0)].cores[0], )), # One-to-one (same row) (model.Route(1), chips[(0,0)].cores[0], ( chips[(4,0)].cores[0], )), # One-to-one (different row) (model.Route(2), chips[(0,0)].cores[0], ( chips[(2,1)].cores[0], )), # One-to-one (may use wrap-around) (model.Route(3), chips[(0,0)].cores[0], ( chips[(4,4)].cores[0], )), # One-to-N (model.Route(4), chips[(0,0)].cores[0], ( chips[(0,0)].cores[0] , chips[(4,0)].cores[0] , chips[(0,4)].cores[0] , chips[(4,4)].cores[0] )), ): node_sequences, unrouted_sinks = \ routers.dimension_order_route(source, sinks, chips , use_wrap_around = wrap_around , dimension_order = dimension_order ) # Nothing should be unroutable self.assertFalse(unrouted_sinks) # Should be one route per sink self.assertEqual(len(sinks), len(node_sequences)) # All node sequences should start from the source for node_sequence in node_sequences: self.assertEqual(node_sequence[0], source) sinks_routed = set() for node_sequence in node_sequences: sequence_sink = node_sequence[-1] # Each sink must not have multiple node sequences leading to it self.assertNotIn(sequence_sink, sinks_routed) sinks_routed.add(sequence_sink) # Every sink must have node sequence leading to it self.assertEqual(set(sinks), sinks_routed) # Test that the route follows the order of dimensions required for node_sequence in node_sequences: dimensions = list(dimension_order) for step in xrange(1, len(node_sequence) - 2): router = node_sequence[step] next_router = node_sequence[step+1] # Find the port to the next router for port, next_router_ in router.connections.iteritems(): if next_router_ == next_router: break port = None # Whenever the direction changes, it must change to a direction # next in the ordering while dimensions[0] != port_to_dimension[port]: dimensions.pop(0) self.assertTrue(dimensions)
def test_add_route(self): """ Test that model.add_route successfully works for a simple multicast route (and that defining the route twice has no ill-effects). """ chips = model.make_rectangular_board(2,2) # Make a path travelling round the system (do it twice to make sure nothing # gets duplicated) route = model.Route(0) for _ in range(2): model.add_route( route , [ chips[(0,0)].cores[0] , chips[(0,0)].router , chips[(0,1)].router , chips[(1,1)].router , chips[(1,0)].router , chips[(1,0)].cores[17] ] ) model.add_route( route , [ chips[(0,0)].cores[0] , chips[(0,0)].router , chips[(0,1)].router , chips[(1,1)].router , chips[(1,1)].cores[17] ] ) # Check that the route was added in the appropriate sink/source and nowhere # else for (position, core) in sum(( list((router.position, core) for core in cores.itervalues()) for (router,cores) in chips.itervalues() ), []): # Source should be in chip (0,0)'s 0th core if position == (0,0) and core.core_id == 0: self.assertEqual(core.sources, set([route])) else: self.assertEqual(core.sources, set()) # Sink should be in chips (1,0)'s and (1,1)'s 17th core if position in ((1,0), (1,1)) and core.core_id == 17: self.assertEqual(core.sinks, set([route])) else: self.assertEqual(core.sinks, set()) # Check that all connecting edges between routers are valid (i.e. face in # opposite directions and make sense) for router, cores in chips.itervalues(): for route, (input_port, output_ports) in router.routes.iteritems(): # Test the input has a corresponding output in the router/core if input_port in model.Router.INTERNAL_PORTS: # If a route is from a core, make sure the core knows about it core = router.connections[input_port] self.assertIn(route, core.sources) else: # Check the corresponding router has an output for this route pointing # at this router. other_router = router.connections[input_port] self.assertIn( topology.opposite(input_port) , other_router.routes[route][1] ) # Test all outputs have a coresponding input in another router/core for output_port in output_ports: if output_port in model.Router.INTERNAL_PORTS: # If a route is to a core, make sure the core knows about it core = router.connections[output_port] self.assertIn(route, core.sinks) else: # Check the corresponding router has an input for this route pointing # from this router. other_router = router.connections[output_port] self.assertEqual( topology.opposite(output_port) , other_router.routes[route][0] )
def test_get_all_routes_empty(self): """ Test that model.get_all_routes finds none in a system without any... """ chips = model.make_rectangular_board() self.assertEqual(model.get_all_routes(chips), {})
def test_dor_perfect_case(self): """ Test dimension-order-routing in the case where routing should be possible. """ width = 5 height = 5 port_to_dimension = { topology.EAST: 0, topology.WEST: 0, topology.NORTH: 1, topology.SOUTH: 1, topology.NORTH_EAST: 2, topology.SOUTH_WEST: 2, } for wrap_around in (True, False): chips = model.make_rectangular_board(width, height, wrap_around = wrap_around) for dimension_order in ( (0,1,2), (2,1,0) ): for route, source, sinks in ( # Self-loop (model.Route(0), chips[(0,0)][1][0], ( chips[(0,0)][1][0], )), # One-to-one (same row) (model.Route(1), chips[(0,0)][1][0], ( chips[(4,0)][1][0], )), # One-to-one (different row) (model.Route(2), chips[(0,0)][1][0], ( chips[(2,1)][1][0], )), # One-to-one (may use wrap-around) (model.Route(3), chips[(0,0)][1][0], ( chips[(4,4)][1][0], )), # One-to-N (model.Route(4), chips[(0,0)][1][0], ( chips[(0,0)][1][0] , chips[(4,0)][1][0] , chips[(0,4)][1][0] , chips[(4,4)][1][0] )), ): node_sequences, unrouted_sinks = \ routers.dimension_order_route(source, sinks, chips , use_wrap_around = wrap_around , dimension_order = dimension_order ) # Nothing should be unroutable self.assertFalse(unrouted_sinks) # Should be one route per sink self.assertEqual(len(sinks), len(node_sequences)) # All node sequences should start from the source for node_sequence in node_sequences: self.assertEqual(node_sequence[0], source) sinks_routed = set() for node_sequence in node_sequences: sequence_sink = node_sequence[-1] # Each sink must not have multiple node sequences leading to it self.assertNotIn(sequence_sink, sinks_routed) sinks_routed.add(sequence_sink) # Every sink must have node sequence leading to it self.assertEqual(set(sinks), sinks_routed) # Test that the route follows the order of dimensions required for node_sequence in node_sequences: dimensions = list(dimension_order) for step in xrange(1, len(node_sequence) - 2): router = node_sequence[step] next_router = node_sequence[step+1] # Find the port to the next router for port, next_router_ in router.connections.iteritems(): if next_router_ == next_router: break port = None # Whenever the direction changes, it must change to a direction # next in the ordering while dimensions[0] != port_to_dimension[port]: dimensions.pop(0) self.assertTrue(dimensions)
def test_add_route(self): """ Test that model.add_route successfully works for a simple multicast route (and that defining the route twice has no ill-effects). """ chips = model.make_rectangular_board(2,2) # Make a path travelling round the system (do it twice to make sure nothing # gets duplicated) route = model.Route(0) for _ in range(2): model.add_route( route , [ chips[(0,0)][1][0] , chips[(0,0)][0] , chips[(0,1)][0] , chips[(1,1)][0] , chips[(1,0)][0] , chips[(1,0)][1][17] ] ) model.add_route( route , [ chips[(0,0)][1][0] , chips[(0,0)][0] , chips[(0,1)][0] , chips[(1,1)][0] , chips[(1,1)][1][17] ] ) # Check that the route was added in the appropriate sink/source and nowhere # else for (position, core) in sum(( list((router.position, core) for core in cores) for (router,cores) in chips.itervalues() ), []): # Source should be in chip (0,0)'s 0th core if position == (0,0) and core.core_id == 0: self.assertEqual(core.sources, set([route])) else: self.assertEqual(core.sources, set()) # Sink should be in chips (1,0)'s and (1,1)'s 17th core if position in ((1,0), (1,1)) and core.core_id == 17: self.assertEqual(core.sinks, set([route])) else: self.assertEqual(core.sinks, set()) # Check that all connecting edges between routers are valid (i.e. face in # opposite directions and make sense) for router, cores in chips.itervalues(): for route, (input_port, output_ports) in router.routes.iteritems(): # Test the input has a corresponding output in the router/core if input_port in model.Router.INTERNAL_PORTS: # If a route is from a core, make sure the core knows about it core = router.connections[input_port] self.assertIn(route, core.sources) else: # Check the corresponding router has an output for this route pointing # at this router. other_router = router.connections[input_port] self.assertIn( topology.opposite(input_port) , other_router.routes[route][1] ) # Test all outputs have a coresponding input in another router/core for output_port in output_ports: if output_port in model.Router.INTERNAL_PORTS: # If a route is to a core, make sure the core knows about it core = router.connections[output_port] self.assertIn(route, core.sinks) else: # Check the corresponding router has an input for this route pointing # from this router. other_router = router.connections[output_port] self.assertEqual( topology.opposite(output_port) , other_router.routes[route][0] )