class RouterTests(unittest.TestCase): """ Tests the router """ TIME_PHASE_PERIOD = 200 ROUTER_PERIOD = 10 WAIT_BEFORE_EMERGENCY = 3 WAIT_BEFORE_DROP = 6 # We're right in the middle MESH_DIMENSIONS = (3,3) MESH_POSITION = (1,1) def setUp(self): # Before each test build a new scheduler, system and router self.scheduler = Scheduler() self.system = SpiNNakerSystem(self.scheduler, RouterTests.TIME_PHASE_PERIOD) self.injection_link = BufferLink(self.scheduler,1) self.exit_link = BufferLink(self.scheduler,1) self.in_links = [BufferLink(self.scheduler,1) for _ in range(6)] self.out_links = [BufferLink(self.scheduler,1) for _ in range(6)] # All links self.links = ( [self.injection_link, self.exit_link] + self.in_links + self.out_links) self.router = SpiNNakerRouter( self.scheduler , self.system , self.injection_link , self.exit_link , self.in_links , self.out_links , RouterTests.ROUTER_PERIOD , RouterTests.WAIT_BEFORE_EMERGENCY , RouterTests.WAIT_BEFORE_DROP ) self.router.set_mesh_dimensions(*RouterTests.MESH_DIMENSIONS) self.router.set_mesh_position(*RouterTests.MESH_POSITION) def test_nothing(self): # Test that the router does nothing if no packets are given... it = self.scheduler.run() while it.next() < 1000: pass # Nothing was sent/received for link in self.links: self.assertTrue(link.can_send()) self.assertFalse(link.can_receive()) # The router remained idle... self.assertEqual(self.router.counters["timestamp_packet_timeout"], 0) self.assertEqual(self.router.counters["router_packet_timeout"], 0) self.assertEqual(self.router.counters["packets_routed"], 0) self.assertEqual(self.router.counters["packet_emergency_routed"], 0) self.assertEqual(self.router.counters["router_blocked_cycles"], 0) # Some cycles occurred (i.e. it didn't stop after one) self.assertTrue(self.router.counters["router_cycles"] > 10) # Every cycle was idle self.assertEqual(self.router.counters["router_idle_cycles"], self.router.counters["router_cycles"]) def test_loopback(self): # Test that the router can forward packets to itself # A packet to ourselves packet = SpiNNakerP2PPacket( self.system , "Example Data" , RouterTests.MESH_POSITION , 32) self.assertTrue(self.injection_link.can_send()) self.injection_link.send(packet) # Run until the packet arrives it = self.scheduler.run() while it.next() < 1000 and not self.exit_link.can_receive(): pass # We got our packet back self.assertTrue(self.exit_link.can_receive()) rec_packet = self.exit_link.receive() self.assertEqual(packet, rec_packet) # Nothing else was sent/received for link in self.links: self.assertTrue(link.can_send()) self.assertFalse(link.can_receive()) # The router sent one packet... self.assertEqual(self.router.counters["timestamp_packet_timeout"], 0) self.assertEqual(self.router.counters["router_packet_timeout"], 0) self.assertEqual(self.router.counters["packets_routed"], 1) self.assertEqual(self.router.counters["packet_emergency_routed"], 0) self.assertEqual(self.router.counters["router_blocked_cycles"], 0) self.assertEqual(self.router.counters["router_idle_cycles"], 0) # This all happened in one cycle self.assertEqual(self.router.counters["router_cycles"], 1) # The packet took one hop self.assertEqual(packet.distance, 1) # Wait counter reset self.assertEqual(packet.wait, 0) # Not emergency routed self.assertFalse(packet.emergency) def test_normal_route(self): # Test that the router can forward packets to another router directions = [ ((2,1), topology.EAST), ((0,1), topology.WEST), ((1,2), topology.NORTH), ((1,0), topology.SOUTH), ((2,2), topology.NORTH_EAST), ((0,0), topology.SOUTH_WEST), ] for router_pos, direction in directions: # Reset everything... self.setUp() # A packet to ourselves packet = SpiNNakerP2PPacket( self.system , "Example Data" , router_pos , 32) # Send packet via an arbitrary input (east) self.assertTrue(self.in_links[0].can_send()) self.in_links[0].send(packet) # Run until the packet arrives it = self.scheduler.run() while it.next() < 1000 and not self.out_links[direction].can_receive(): pass # We got our packet back self.assertTrue(self.out_links[direction].can_receive()) rec_packet = self.out_links[direction].receive() self.assertEqual(packet, rec_packet) # Nothing else was sent/received for link in self.links: self.assertTrue(link.can_send()) self.assertFalse(link.can_receive()) # The router sent one packet... self.assertEqual(self.router.counters["timestamp_packet_timeout"], 0) self.assertEqual(self.router.counters["router_packet_timeout"], 0) self.assertEqual(self.router.counters["packets_routed"], 1) self.assertEqual(self.router.counters["packet_emergency_routed"], 0) self.assertEqual(self.router.counters["router_blocked_cycles"], 0) self.assertEqual(self.router.counters["router_idle_cycles"], 0) # This all happened in one cycle self.assertEqual(self.router.counters["router_cycles"], 1) # The packet took one hop self.assertEqual(packet.distance, 1) # Wait counter reset self.assertEqual(packet.wait, 0) # Not emergency routed self.assertFalse(packet.emergency) def test_emergency_on_block(self): # Test that the router uses emergency mode when the target link is blocked directions = [ ((2,1), topology.EAST, topology.NORTH_EAST), ((0,1), topology.WEST, topology.SOUTH_WEST), ((1,2), topology.NORTH, topology.WEST), ((1,0), topology.SOUTH, topology.EAST), ((2,2), topology.NORTH_EAST,topology.NORTH), ((0,0), topology.SOUTH_WEST,topology.SOUTH), ] for router_pos, direction, emergency in directions: # Reset everything... self.setUp() # A dud packet dud = SpiNNakerP2PPacket( self.system , "Dud" , None , 1) # A packet to ourselves packet = SpiNNakerP2PPacket( self.system , "Example Data" , router_pos , 32) # Send packet via an arbitrary input (east) self.assertTrue(self.in_links[0].can_send()) self.in_links[0].send(packet) # Block the target port with a dud packet self.assertTrue(self.out_links[direction].can_send()) self.out_links[direction].send(dud) # Run until the packet arrives it = self.scheduler.run() while it.next() < 1000 and not self.out_links[emergency].can_receive(): pass # We got our packet back self.assertTrue(self.out_links[emergency].can_receive()) rec_packet = self.out_links[emergency].receive() self.assertEqual(packet, rec_packet) # Remove the blockage and make sure it wasn't changed... self.assertTrue(self.out_links[direction].can_receive()) rec_dud = self.out_links[direction].receive() self.assertEqual(dud, rec_dud) # Nothing else was sent/received for link in self.links: self.assertTrue(link.can_send()) self.assertFalse(link.can_receive()) # The router sent one packet... self.assertEqual(self.router.counters["timestamp_packet_timeout"], 0) self.assertEqual(self.router.counters["router_packet_timeout"], 0) self.assertEqual(self.router.counters["packets_routed"], 0) self.assertEqual(self.router.counters["packet_emergency_routed"], 1) self.assertEqual(self.router.counters["router_idle_cycles"], 0) # We waited only until we could emergency route self.assertEqual(self.router.counters["router_blocked_cycles"], RouterTests.WAIT_BEFORE_EMERGENCY) # We executed until we waited long enough then sent the packet self.assertEqual(self.router.counters["router_cycles"], RouterTests.WAIT_BEFORE_EMERGENCY + 1) # The packet took one hop self.assertEqual(packet.distance, 1) # Wait counter reset self.assertEqual(packet.wait, 0) # Emergency routed self.assertTrue(packet.emergency) def test_emergency_forward(self): # Test that the router can forward packets received in emergency mode directions = [ (topology.EAST, topology.NORTH_EAST), (topology.WEST, topology.SOUTH_WEST), (topology.NORTH, topology.WEST), (topology.NORTH_EAST,topology.NORTH), (topology.SOUTH_WEST,topology.SOUTH), ] for in_link, out_link in directions: # Reset everything... self.setUp() # A packet to ourselves packet = SpiNNakerP2PPacket( self.system , "Example Data" , (0,0) # Doesn't/Shouldn't matter , 32) # The packet is in emergency mode packet.emergency = True # Send packet via an arbitrary input (east) self.assertTrue(self.in_links[in_link].can_send()) self.in_links[in_link].send(packet) # Run until the packet arrives it = self.scheduler.run() while it.next() < 1000 and not self.out_links[out_link].can_receive(): pass # We got our packet back self.assertTrue(self.out_links[out_link].can_receive()) rec_packet = self.out_links[out_link].receive() self.assertEqual(packet, rec_packet) # Nothing else was sent/received for link in self.links: self.assertTrue(link.can_send()) self.assertFalse(link.can_receive()) # The router sent one packet... self.assertEqual(self.router.counters["timestamp_packet_timeout"], 0) self.assertEqual(self.router.counters["router_packet_timeout"], 0) self.assertEqual(self.router.counters["packets_routed"], 1) self.assertEqual(self.router.counters["packet_emergency_routed"], 0) self.assertEqual(self.router.counters["router_idle_cycles"], 0) self.assertEqual(self.router.counters["router_blocked_cycles"], 0) # Routing took one cycle self.assertEqual(self.router.counters["router_cycles"], 1) # The packet took one hop self.assertEqual(packet.distance, 1) # Wait counter reset self.assertEqual(packet.wait, 0) # The packet is no-longer in emergency mode self.assertFalse(packet.emergency) def test_drop_on_block(self): # Test that the router drops packets which block directions = [ ((2,1), topology.EAST, topology.NORTH_EAST), ((0,1), topology.WEST, topology.SOUTH_WEST), ((1,2), topology.NORTH, topology.WEST), ((1,0), topology.SOUTH, topology.EAST), ((2,2), topology.NORTH_EAST,topology.NORTH), ((0,0), topology.SOUTH_WEST,topology.SOUTH), ] for router_pos, direction, emergency in directions: # Reset everything... self.setUp() # A dud packet dud = SpiNNakerP2PPacket( self.system , "Dud" , None , 1) # A packet to ourselves packet = SpiNNakerP2PPacket( self.system , "Example Data" , router_pos , 32) # Send packet via an arbitrary input (east) self.assertTrue(self.in_links[0].can_send()) self.in_links[0].send(packet) # Block the target port with a dud packet self.assertTrue(self.out_links[direction].can_send()) self.out_links[direction].send(dud) # Block the emergency port with a dud packet self.assertTrue(self.out_links[emergency].can_send()) self.out_links[emergency].send(dud) # Run until the packet is dropped (the input becomes free again) it = self.scheduler.run() while it.next() < 1000 and self.in_links[0].can_receive(): pass # Remove the blockages and make sure they weren't changed... self.assertTrue(self.out_links[direction].can_receive()) rec_dud = self.out_links[direction].receive() self.assertEqual(dud, rec_dud) self.assertTrue(self.out_links[emergency].can_receive()) rec_dud = self.out_links[emergency].receive() self.assertEqual(dud, rec_dud) # Nothing else was sent/received for link in self.links: self.assertTrue(link.can_send()) self.assertFalse(link.can_receive()) # The router dropped one packet... self.assertEqual(self.router.counters["timestamp_packet_timeout"], 0) self.assertEqual(self.router.counters["router_packet_timeout"], 1) self.assertEqual(self.router.counters["packets_routed"], 0) self.assertEqual(self.router.counters["packet_emergency_routed"], 0) # We blocked until the wait threshold was exhausted self.assertEqual(self.router.counters["router_blocked_cycles"], RouterTests.WAIT_BEFORE_DROP + 1) # One idle cycle where we actually drop the packet self.assertEqual(self.router.counters["router_idle_cycles"], 1) # We blocked until the wait threshold was exhausted plus one idle cycle # where we dropped the packet self.assertEqual(self.router.counters["router_cycles"], RouterTests.WAIT_BEFORE_DROP + 1 + 1) # The packet didn't hop self.assertEqual(packet.distance, 0) # The packet had to wait until the timeout expired self.assertEqual(packet.wait, RouterTests.WAIT_BEFORE_DROP + 1) # Not emergency routed self.assertFalse(packet.emergency)
class SpiNNaker101(object): """ A single SpiNNaker chip, a 101 machine in SpiNNaker parlance. Contains a traffic generator and router. The links from the router are initially dead. """ def __init__( self , scheduler , system , injection_buffer_length , router_period # SpiNNakerRouter , wait_before_emergency # SpiNNakerRouter , wait_before_drop # SpiNNakerRouter , core_period # SpiNNakerTrafficGenerator , packet_prob # SpiNNakerTrafficGenerator , distance_std = None # SpiNNakerTrafficGenerator ): """ injection_buffer_length is the number of packets that can be buffered internally before they're routed. router_period see SpiNNakerRouter wait_before_emergency see SpiNNakerRouter wait_before_drop see SpiNNakerRouter core_period see SpiNNakerTrafficGenerator packet_prob see SpiNNakerTrafficGenerator distance_std see SpiNNakerTrafficGenerator """ self.scheduler = scheduler self.system = system # Links between the router and traffic generator injection_link = BufferLink(self.scheduler, injection_buffer_length) exit_link = BufferLink(self.scheduler) # The external connections to the rest of the world self.in_links = [DeadLink(self.scheduler)]*6 self.out_links = [DeadLink(self.scheduler)]*6 self.traffic_generator = SpiNNakerTrafficGenerator( self.scheduler , self.system , core_period , packet_prob , injection_link , exit_link , distance_std ) self.router = SpiNNakerRouter( self.scheduler , self.system , injection_link , exit_link , self.in_links , self.out_links , router_period , wait_before_emergency , wait_before_drop ) def set_mesh_dimensions(self, w, h): """ Set the size of the mesh of chips this system is in. """ self.traffic_generator.set_mesh_dimensions(w,h) self.router.set_mesh_dimensions(w,h) def set_mesh_position(self, x, y): """ Set the size of the mesh of chips this system is in. """ self.traffic_generator.set_mesh_position(x,y) self.router.set_mesh_position(x,y) def get_mesh_position(self): """ Set the size of the mesh of chips this system is in. """ return self.router.get_mesh_position() def set_in_link(self, direction, link): """ Set the given link to the link specified. """ self.in_links[direction] = link def set_out_link(self, direction, link): """ Set the given link to the link specified. """ self.out_links[direction] = link def get_in_link(self, direction): """ Get the link specified. """ return self.in_links[direction] def get_out_link(self, direction): """ Get the link specified. """ return self.out_links[direction]