Example #1
0
	def test_fully_connect_chips_pair_of_chips_no_wrap_around(self):
		"""
		Test that a model.fully_connect_chips connects (and leaves disconnected)
		the correct links when a pair of touching chips are created.
		"""
		# Test with the neighbouring chip being on every possible edge.
		for direction in [ topology.EAST
		                 , topology.NORTH_EAST
		                 , topology.NORTH
		                 , topology.WEST
		                 , topology.SOUTH_WEST
		                 , topology.SOUTH
		                 ]:
			other_chip_position = topology.to_xy(topology.add_direction((0,0,0), direction))
			chips = { (0,0)               : model.make_chip((0,0))
			        , other_chip_position : model.make_chip(other_chip_position)
			        }
			model.fully_connect_chips(chips)
			
			# Only the touching ports are connected
			for port in model.Router.EXTERNAL_PORTS:
				if port == direction:
					# Touching port
					self.assertEqual( chips[(0,0)].router.connections[port]
					                , chips[other_chip_position].router
					                )
					self.assertEqual( chips[other_chip_position].router.connections[topology.opposite(port)]
					                , chips[(0,0)].router
					                )
				else:
					# Non-touching port
					self.assertIsNone(chips[(0,0)].router.connections[port])
					self.assertIsNone(chips[other_chip_position].router.connections[topology.opposite(port)])
Example #2
0
	def test_connections(self):
		# Try with several sizes
		for torus_size in SpiNNakerTorusTests.TORUS_SIZES:
			self.generate_torus(*torus_size)
			
			# Get a dictionary of chips to their locations
			chips = {}
			for board in self.torus.boards.itervalues():
				for chip in board.chips.itervalues():
					chips[chip.get_mesh_position()] = chip
			
			# Check each chip is connected with their neighbours N, NE, W
			for pos, chip in chips.iteritems():
				for direction in [topology.NORTH, topology.NORTH_EAST, topology.WEST]:
					other_pos = topology.to_xy(
						topology.add_direction(topology.zero_pad(pos), direction))
					other_chip = chips[( other_pos[0]%(self.torus.width*12)
					                   , other_pos[1]%(self.torus.height*12)
					                   , )]
					
					other_direction = topology.opposite(direction)
					
					# Make sure we share links
					self.assertEqual(chip.get_in_link(direction),
					                 other_chip.get_out_link(other_direction))
					self.assertEqual(chip.get_out_link(direction),
					                 other_chip.get_in_link(other_direction))
Example #3
0
	def test_fully_connect_chips_pair_of_chips_no_wrap_around(self):
		"""
		Test that a model.fully_connect_chips connects (and leaves disconnected)
		the correct links when a pair of touching chips are created.
		"""
		# Test with the neighbouring chip being on every possible edge.
		for direction in [ topology.EAST
		                 , topology.NORTH_EAST
		                 , topology.NORTH
		                 , topology.WEST
		                 , topology.SOUTH_WEST
		                 , topology.SOUTH
		                 ]:
			other_chip_position = topology.to_xy(topology.add_direction((0,0,0), direction))
			chips = { (0,0)               : model.make_chip((0,0))
			        , other_chip_position : model.make_chip(other_chip_position)
			        }
			model.fully_connect_chips(chips)
			
			# Only the touching ports are connected
			for port in model.Router.EXTERNAL_PORTS:
				if port == direction:
					# Touching port
					self.assertEqual( chips[(0,0)][0].connections[port]
					                , chips[other_chip_position][0]
					                )
					self.assertEqual( chips[other_chip_position][0].connections[topology.opposite(port)]
					                , chips[(0,0)][0]
					                )
				else:
					# Non-touching port
					self.assertIsNone(chips[(0,0)][0].connections[port])
					self.assertIsNone(chips[other_chip_position][0].connections[topology.opposite(port)])
Example #4
0
	def test_hexagon_edge_link(self):
		# Get the set of edge nodes for a 4-layer hexagon
		all_nodes   = set(topology.hexagon(4))
		inner_nodes = set(topology.hexagon(3))
		outer_nodes = all_nodes - inner_nodes
		
		directions = [
			topology.EAST,
			topology.NORTH_EAST,
			topology.NORTH,
			topology.WEST,
			topology.SOUTH_WEST,
			topology.SOUTH
		]
		
		edges = [
			topology.EDGE_TOP_LEFT,
			topology.EDGE_TOP,
			topology.EDGE_TOP_RIGHT,
			topology.EDGE_BOTTOM_RIGHT,
			topology.EDGE_BOTTOM,
		  topology.EDGE_BOTTOM_LEFT,
		]
		
		# Get the set of outward-facing links as (node_xy,direction) pairs
		outward_facing_links = []
		for node in all_nodes:
			for direction in directions:
				# Get the node that this link would connect to
				facing_node = topology.to_xy(
					topology.add_direction(topology.zero_pad(node), direction))
				# If that node isn't part of our set, it is an edge link
				if facing_node not in all_nodes:
					outward_facing_links.append((node, direction))
		
		# Get the set of outward facing links according to the function under test
		all_links = []
		for edge in edges:
			for num in range(8):
				all_links.append(topology.hexagon_edge_link(edge, num, 4))
		
		# No duplicates
		self.assertEqual(len(all_links), len(set(all_links)))
		
		# The algorithm gets every outward facing edge
		self.assertEqual(set(all_links), set(outward_facing_links))
Example #5
0
def fully_connect_chips(chips, wrap_around = False):
	"""
	Given a set of chips (i.e. (router, cores) tuples), fully interconnects the
	chips optionally including wrap-around links.
	"""
	# Calculate the bounds of the system's size (in case wrap_around is used)
	width  = max(x for (x,y) in chips.iterkeys()) + 1
	height = max(y for (x,y) in chips.iterkeys()) + 1
	
	# Connect up the nodes to their neighbours
	for position, (router, cores) in chips.iteritems():
		for direction in [topology.EAST, topology.NORTH_EAST, topology.NORTH]:
			next_x, next_y = topology.to_xy(
				topology.add_direction(topology.to_xyz(position), direction))
			
			if wrap_around:
				next_x %= width
				next_y %= height
			
			# Only connect up to nodes which actually exist...
			if (next_x, next_y) in chips:
				router.connect(direction, chips[(next_x, next_y)][0], topology.opposite(direction))
Example #6
0
	def test_chips(self):
		# A board should have chips in the correct locations and no repeats
		self.assertEqual(len(self.board.chips), 48)
		self.assertEqual(set(self.board.chips.iterkeys()),
		                 set(topology.hexagon(4)))
		
		# For all inputs & outputs, if there is a chip in that direction it must be
		# connected via a SilistixLink and if not it should be attached to a
		# DeadLink.
		for src_pos, src_chip in self.board.chips.iteritems():
			for direction in ( topology.EAST
			                 , topology.NORTH_EAST
			                 , topology.NORTH
			                 , topology.WEST
			                 , topology.SOUTH_WEST
			                 , topology.SOUTH
			                 ):
				in_link  = src_chip.get_in_link(direction)
				out_link = src_chip.get_out_link(direction)
				
				dst_pos = topology.to_xy(topology.add_direction(topology.zero_pad(src_pos),
				                                                direction))
				if dst_pos in self.board.chips:
					# There is a chip opposite this connection
					dst_chip = self.board.chips[dst_pos]
					direction = topology.opposite(direction)
					
					# Check that they have the same link (connected to opposite ports)
					self.assertEqual(out_link, dst_chip.get_in_link(direction))
					self.assertEqual(in_link,  dst_chip.get_out_link(direction))
					
					# And that they're SilistixLinks
					self.assertEqual(type(in_link), SilistixLink)
					self.assertEqual(type(out_link), SilistixLink)
				else:
					# No adjacent chip so should be DeadLinks
					self.assertEqual(type(in_link), DeadLink)
					self.assertEqual(type(out_link), DeadLink)
Example #7
0
	def test_threeboards(self):
		# Creating no threeboards makes no boards...
		self.assertEqual(list(topology.threeboards(0)), [])
		
		# Creating 2x2 threeboards (throw away the boards...)
		boards = [topology.to_xy(c) for c in topology.threeboards(2)]
		self.assertEqual(len(boards), 3*2*2)
		# Threeboard (0,0)
		self.assertTrue((0,0) in boards)
		self.assertTrue((0,1) in boards)
		self.assertTrue((1,1) in boards)
		# Threeboard (1,0)
		self.assertTrue((2,1) in boards)
		self.assertTrue((2,2) in boards)
		self.assertTrue((3,2) in boards)
		# Threeboard (0,1)
		self.assertTrue((-1,1) in boards)
		self.assertTrue((-1,2) in boards)
		self.assertTrue((0,2) in boards)
		# Threeboard (1,1)
		self.assertTrue((1,2) in boards)
		self.assertTrue((1,3) in boards)
		self.assertTrue((2,3) in boards)
Example #8
0
def fully_connect_chips(chips, wrap_around=False):
    """
	Given a set of chips (i.e. (router, cores) tuples), fully interconnects the
	chips optionally including wrap-around links.
	"""
    # Calculate the bounds of the system's size (in case wrap_around is used)
    width = max(x for (x, y) in chips.iterkeys()) + 1
    height = max(y for (x, y) in chips.iterkeys()) + 1

    # Connect up the nodes to their neighbours
    for position, (router, cores) in chips.iteritems():
        for direction in [topology.EAST, topology.NORTH_EAST, topology.NORTH]:
            next_x, next_y = topology.to_xy(
                topology.add_direction(topology.to_xyz(position), direction))

            if wrap_around:
                next_x %= width
                next_y %= height

            # Only connect up to nodes which actually exist...
            if (next_x, next_y) in chips:
                router.connect(direction, chips[(next_x, next_y)][0],
                               topology.opposite(direction))
Example #9
0
	def test_to_xy(self):
		self.assertEqual(topology.to_xy((0,0,0)), (0,0))
		self.assertEqual(topology.to_xy((1,1,1)), (0,0))
		self.assertEqual(topology.to_xy((0,1,2)), (-2,-1))
		self.assertEqual(topology.to_xy((-2,0,2)), (-4,-2))
Example #10
0
def dimension_order_route(source, sinks, chips, use_wrap_around = False, dimension_order=(0,1,2)):
	"""
	Simple, naive dimension order routing optionally supporting wrap-around links.
	Note that when two DOR routes exist of equivalent length, one will be chosen
	at random.
	
	This routing algorithm does not attempt to route around dead links/cores and
	so some routes may fail in the presence of network errors.
	"""
	
	# Calculate the bounds of the system's size (in case wrap_around is used)
	width  = max(x for (x,y) in chips.iterkeys()) + 1
	height = max(y for (x,y) in chips.iterkeys()) + 1
	
	node_sequences = []
	unrouted_sinks = []
	
	for sink in sinks:
		source_pos = model.core_to_router(source).position
		sink_pos   = model.core_to_router(sink).position
		
		# Find the shortest vector from the source to the sink
		if use_wrap_around:
			vector = list(topology.to_torus_shortest_path(source_pos, sink_pos, (width,height)))
		else:
			vector = list(topology.to_shortest_path(topology.to_xyz(map( operator.sub
			                                                           , sink_pos
			                                                           , source_pos
			                                                           ))))
		
		node_sequence = [source, model.core_to_router(source)]
		
		# Route down each dimension in the given order
		for dimension in dimension_order:
			while vector[dimension] != 0:
				vx,vy = topology.to_xy((int(dimension == 0), int(dimension == 1), int(dimension == 2)))
				x, y  = node_sequence[-1].position
				
				if vector[dimension] > 0:
					x += vx
					y += vy
					vector[dimension] -= 1
				else:
					x -= vx
					y -= vy
					vector[dimension] += 1
				
				x %= width
				y %= height
				
				node_sequence.append(chips[(x,y)][0])
		
		# Add the sink
		node_sequence.append(sink)
		
		# Add the route
		if model.is_path_connected(node_sequence):
			node_sequences.append(node_sequence)
		else:
			unrouted_sinks.append(sink)
	
	return node_sequences, unrouted_sinks
Example #11
0
	def __init__( self
	            , scheduler
	            , system
	            
	            , link_send_cycles        # SilistixLink
	            , link_ack_cycles         # SilistixLink
	            
	            , injection_buffer_length # SpiNNaker101
	            
	            , router_period           # SpiNNakerRouter
	            , wait_before_emergency   # SpiNNakerRouter
	            , wait_before_drop        # SpiNNakerRouter
	            
	            , core_period             # SpiNNakerTrafficGenerator
	            , packet_prob             # SpiNNakerTrafficGenerator
	            , distance_std = None     # SpiNNakerTrafficGenerator
	            ):
		"""
		link_send_cycles see SilistixLink
		link_ack_cycles see SilistixLink
		
		injection_buffer_length see SpiNNaker101
		
		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
		
		# A dictionary { (x,y): SpiNNaker101, ... } of all contained chips. The
		# coordinates are relative to the central chip (created first in the
		# hexagon).
		self.chips = { }
		
		# Utility function to add a new chip to the chips dict.
		def add_chip(position):
			"Add a chip at the specified position"
			self.chips[position] = SpiNNaker101( self.scheduler
			                                   , self.system
			                                   , injection_buffer_length
			                                   , router_period
			                                   , wait_before_emergency
			                                   , wait_before_drop
			                                   , core_period
			                                   , packet_prob
			                                   , distance_std
			                                   )
		# Create the chips in a hexagonal pattern
		for position in topology.hexagon(4):
			add_chip(position)
		
		# Put SilistixLinks between them
		for src_pos, src_chip in self.chips.iteritems():
			# Try and link this chip to all other neighbours which are towards the
			# top/right of the chip
			for direction in (topology.NORTH, topology.NORTH_EAST, topology.EAST):
				dst_pos = topology.to_xy(
					topology.add_direction(topology.zero_pad(src_pos), direction))
				
				# If the chip exists, put links in this direction
				if dst_pos in self.chips:
					dst_chip = self.chips[dst_pos]
					
					in_link  = SilistixLink(self.scheduler, link_send_cycles, link_ack_cycles)
					out_link = SilistixLink(self.scheduler, link_send_cycles, link_ack_cycles)
					
					src_chip.set_out_link(direction, out_link)
					src_chip.set_in_link(direction, in_link)
					
					dst_chip.set_in_link(topology.opposite(direction), out_link)
					dst_chip.set_out_link(topology.opposite(direction), in_link)