コード例 #1
0
    def test_redundant_paths_spinn7_via_router_require_turn():
        the_machine = machine.Machine('spinn-7', type="spinn4")
        src_vertex_constraints = lib_map.VertexConstraints(x=0, y=0)
        src_vrt = graph.Vertex(1,models.IF_curr_exp,
                               constraints=src_vertex_constraints)
        src_sub_vert = graph.Subvertex(src_vrt, 0,1)

        dest_vertex_constraints = lib_map.VertexConstraints(x=2, y=3)
        dest_vrt = graph.Vertex(1,models.IF_curr_exp,
                                constraints=dest_vertex_constraints)
        dest_sub_vert = graph.Subvertex(dest_vrt, 0,1)
        dest_sub_vert2 = graph.Subvertex(dest_vrt, 0,1)

        edge = graph.Edge(None, src_vrt, dest_vrt)
        sbedge = graph.Subedge(edge, src_sub_vert, dest_sub_vert)
        sbedge2 = graph.Subedge(edge, src_sub_vert, dest_sub_vert2)

        dao_object = dao
        #place vertexes in correct cores
        placements = Placer.place_raw(the_machine,
                                             [src_sub_vert, dest_sub_vert,
                                              dest_sub_vert2])
        dao.placements = placements
        routings = dijkstra_routing.DijkstraRouting.\
            route_raw(the_machine, [src_sub_vert, dest_sub_vert, dest_sub_vert2])
        inconsistant_routings, redundant_paths = \
            Router.check_for_inconsistant_routings(the_machine)
        assert(len(redundant_paths) > 0)
        assert(len(inconsistant_routings) == 0)
        Router.redundant_path_removal(redundant_paths, the_machine)
        inconsistant_routings, redundant_paths = \
            Router.check_for_inconsistant_routings(the_machine)
        assert(len(redundant_paths) == 0)
        assert(len(inconsistant_routings) == 0)
コード例 #2
0
    def setUp(self):
        # Create a machine with a vertex mapped to each core.
        self._init_machine_and_vertexes(1.0)

        # Create a connection to all devices
        for v1 in self.vertices:
            for v2 in self.vertices:
                graph.Edge(None, v1, v2)

        # Finish off
        self._partition_place_and_route()
コード例 #3
0
    def setUp(self):
        # Create a machine with a vertex mapped to each core.
        self._init_machine_and_vertexes(1.0)

        # Create a circular connectivity scheme
        for v1, v2 in zip(self.vertices,
                          self.vertices[1:] + [self.vertices[0]]):
            graph.Edge(None, v1, v2)

        # Finish off
        self._partition_place_and_route()
コード例 #4
0
    def test_partition_multiple_productions_with_multiple_subvertices_and_multiple_subedges(
            self):
        """
        Calculates max atoms per vertex based on a vertex model and then
        it creates 48 pre vertices and 48 pro vertices. 
        This test checks if the subvertices are an instance of
        graph.Subvertex, subedges are an instance of graph.SubEdge
        if total number of subvertices (is i+j+2)*48 and subedges is (i+1)*(j+1)*48*48.
        """
        # Specify a SpiNNaker machine
        machine = lib_machine.Machine('test', 1, 1, 'wrapped')

        # Calculate the max atoms per core
        # The following code has been taken from core.mapper.partition_raw
        requirements = pynn.IF_curr_exp.get_requirements_per_atom()
        resources = machine.get_resources_per_processor()
        atoms = resources / requirements

        print "Long Test: (test_partition_multiple_productions_with_multiple_subvertices_and_multiple_subedges)"
        for i in range(16):  # i is the number of subvertices of a prev vertex
            print "   progress: set", i + 1, "of 16"
            for j in range(
                    16):  # j is the number of subvertices of a pro vertex
                preVertices = []
                proVertices = []
                for k in range(48):  # k is the number of vertices
                    preVertices.append(
                        graph.Vertex(atoms * (i + 1), pynn.IF_curr_exp))
                    proVertices.append(
                        graph.Vertex(atoms * (j + 1), pynn.IF_curr_exp))
                for k1 in range(48):
                    for k2 in range(48):
                        edges = graph.Edge(None, preVertices[k1],
                                           proVertices[k2])
                max_atoms_per_core = dict()
                subvertices, subedges = \
                    basic_partitioner.BasicPartitioner.partition_raw(machine, preVertices + proVertices, max_atoms_per_core)

                # subvertices should be an instance of the Subvertex class
                for subvertex in subvertices:
                    self.assertIsInstance(subvertex, graph.Subvertex)

                # subedges should be an instance of the Subvedge class
                for subedge in subedges:
                    self.assertIsInstance(subedge, graph.Subedge)

                # subvertices should be (i+1+j+1)*48
                self.assertEqual(len(subvertices), (i + j + 2) * 48)

                # subedges should be number of preSubvertices times number of proSubvertices
                self.assertEqual(len(subedges), (i + 1) * (j + 1) * 48 * 48)
コード例 #5
0
    def __init__(self,
                 size,
                 cellclass,
                 cellparams,
                 structure=None,
                 label=None):
        """
        Instantiates a :py:object:`Population`.
        """
        global controller, multi_cast_vertex

        # Raise an exception if the Pop. attempts to employ spatial structure
        if structure:
            raise Exception(
                "Spatial structure is unsupported for Populations.")

        # Create a graph vertex for the population and add it to PACMAN
        self.vertex = cellclass(size, label=label, **cellparams)

        #check if the vertex is a cmd sender, if so store for future
        if self.vertex.requires_multi_cast_source():
            if multi_cast_vertex is None:
                multi_cast_vertex = MultiCastSource()
                controller.add_vertex(multi_cast_vertex)
            edge = graph.Edge(multi_cast_vertex, self.vertex)
            controller.add_edge(edge)

        self.parameters = PyNNParametersSurrogate(self.vertex)
        controller.add_vertex(self.vertex)

        #add any dependant edges and verts if needed
        dependant_verts, dependant_edges = \
            self.vertex.get_dependant_vertexes_edges()

        if dependant_verts is not None:
            for dependant_vert in dependant_verts:
                controller.add_vertex(dependant_vert)

        if dependant_edges is not None:
            for dependant_edge in dependant_edges:
                controller.add_edge(dependant_edge)

        #initlise common stuff
        self.size = size
        self.recordSpikeFile = None
        self.recordVFile = None
        self.recordGSynFile = None
コード例 #6
0
    def test_redundant_paths_spinn7_via_router_same_chip():
        the_machine = machine.Machine('spinn-7', type="spinn4")
        src_vertex_constraints = lib_map.VertexConstraints(x=0, y=0, p=2)
        src_vrt = graph.Vertex(1, models.IF_curr_exp,
                               constraints=src_vertex_constraints)
        src_sub_vert = graph.Subvertex(src_vrt, 0,1)

        dest_vertex_constraints = lib_map.VertexConstraints(x=0, y=0, p=5)
        dest_vrt = graph.Vertex(1, models.IF_curr_exp,
                                constraints=dest_vertex_constraints)
        dest_sub_vert = graph.Subvertex(dest_vrt, 0,1)
        dest_sub_vert2 = graph.Subvertex(dest_vrt, 0,1)

        dest_vertex_constraints2 = lib_map.VertexConstraints(x=0, y=0, p=6)
        dest_vrt2 = graph.Vertex(1, models.IF_curr_exp,
                                 constraints=dest_vertex_constraints2)
        dest_sub_vert2 = graph.Subvertex(dest_vrt2, 0, 1)

        edge = graph.Edge(None, src_vrt, dest_vrt)
        sbedge = graph.Subedge(edge, src_sub_vert, dest_sub_vert)
        sbedge2 = graph.Subedge(edge, src_sub_vert, dest_sub_vert2)

        dao_object = dao
        #place vertexes in correct cores
        placements = Placer.place_raw(the_machine,
                                             [src_sub_vert, dest_sub_vert,
                                              dest_sub_vert2])
        dao.placements = placements
        routings = dijkstra_routing.\
            DijkstraRouting.route_raw(the_machine,
                                      [src_sub_vert, dest_sub_vert,
                                       dest_sub_vert2])
        inconsistant_routings, redundant_paths = \
            Router.check_for_inconsistant_routings(the_machine)
        assert(len(redundant_paths) > 0)
        assert(len(inconsistant_routings) == 0)
        #print "entry {} and entry {}".format(redundant_paths[0][2].route, redundant_paths[0][3].route)
        Router.redundant_path_removal(redundant_paths, the_machine)
        inconsistant_routings, redundant_paths = \
            Router.check_for_inconsistant_routings(the_machine)
        assert(len(redundant_paths) == 0)
        assert(len(inconsistant_routings) == 0)
        for key in the_machine.chips[0][0].router.cam.keys():
            entry_list = the_machine.chips[0][0].router.cam.get(key)
            assert(len(entry_list) == 1)
            #print "entry is {}".format(entry_list[0].route)
            assert(entry_list[0].route == 6144)
コード例 #7
0
    def record(self,
               to_file=None,
               focus=None,
               visualiser_mode=visualiser_modes.RASTER,
               visualiser_2d_dimension=None,
               visualiser_raster_seperate=None,
               visualiser_no_colours=None,
               visualiser_average_period_tics=None,
               visualiser_longer_period_tics=None,
               visualiser_update_screen_in_tics=None,
               visualiser_reset_counters=None,
               visualiser_reset_counter_period=None,
               stream=True):
        """
        Record spikes from all cells in the Population.
        A flag is set for this population that is passed to the simulation,
        triggering spike time recording.
        """
        record_attr = getattr(self.vertex, "record", None)
        if ((record_attr == None) or not callable(record_attr)):
            raise Exception("Vertex does not support recording of spikes")

        # Tell the vertex to record spikes
        self.vertex.record()
        self.recordSpikeFile = to_file

        if stream:
            self.vertex.setup_visualizer(
                focus=focus,
                visualiser_mode=visualiser_mode,
                visualiser_2d_dimension=visualiser_2d_dimension,
                visualiser_raster_seperate=visualiser_raster_seperate,
                visualiser_no_colours=visualiser_no_colours,
                visualiser_average_period_tics=visualiser_average_period_tics,
                visualiser_longer_period_tics=visualiser_longer_period_tics,
                visualiser_update_screen_in_tics=
                visualiser_update_screen_in_tics,
                visualiser_reset_counters=visualiser_reset_counters,
                visualiser_reset_counter_period=visualiser_reset_counter_period
            )

            # If the monitor is enabled, add an edge to the monitor
            global appMonitorVertex
            if appMonitorVertex != None:
                controller.add_edge(graph.Edge(self.vertex, appMonitorVertex))
コード例 #8
0
    def test_partition_production_with_multiple_subvertices_and_multiple_subedges(
            self):
        """
        Calculates max atoms per vertex based on a vertex model and then
        it creates two vertices. Vertex2 has a multiple of max atoms per core controlled by i
        while the size of
        vertex1 stays fixed to max atoms per core.
        This test checks if the subvertices are an instance of
        graph.Subvertex, subedges are an instance of graph.SubEdge
        if total number of subvertices is n+2 and subedges is n+1.
        """
        # Specify a SpiNNaker machine
        machine = lib_machine.Machine('test', 1, 1, 'unwrapped')

        # Calculate the max atoms per core
        # The following code has been taken from core.mapper.partition_raw
        requirements = pynn.IF_curr_exp.get_requirements_per_atom()
        resources = machine.get_resources_per_processor()
        atoms = resources / requirements

        for i in range(16):
            for j in range(16):
                vertex1 = graph.Vertex(atoms * (i + 1), pynn.IF_curr_exp)
                vertex2 = graph.Vertex(atoms * (j + 1), pynn.IF_curr_exp)

                # Generate a self projected edge
                edge = graph.Edge(None, vertex1, vertex2)
                max_atoms_per_core = dict()
                subvertices1, subedges1 = basic_partitioner.BasicPartitioner.partition_raw(
                    machine, [vertex1, vertex2], max_atoms_per_core)

                # subvertices should be an instance of the Subvertex class
                for subvertex in subvertices1:
                    self.assertIsInstance(subvertex, graph.Subvertex)

                # subedges should be an instance of the Subvedge class
                for subedge in subedges1:
                    self.assertIsInstance(subedge, graph.Subedge)

                # subvertices should be 1
                self.assertEqual(len(subvertices1), i + j + 2)

                # subedges should be squared the number of subvertices
                self.assertEqual(len(subedges1), (i + 1) * (j + 1))
コード例 #9
0
    def test_partition_production_with_multiple_subvertices_and_self_projected_subedges(
            self):
        """
            Calculates max atoms per vertex based on the vertex model and then
            it creates a vertex with n multiples of max atoms and adds an edge which projects 
            back to itself. This test checks if the subvertices are an instance of 
            graph.Subvertex, subedges are an instance of graph.SubEdge
            if total number of subvertices and subedges is 1.
            
            """
        # Specify a SpiNNaker machine
        machine = lib_machine.Machine('test', 1, 1, 'unwrapped')

        # Calculate the max atoms per core
        # The following code has been taken from core.mapper.partition_raw
        requirements = pynn.IF_curr_exp.get_requirements_per_atom()
        resources = machine.get_resources_per_processor()
        atoms = resources / requirements

        for i in range(16):
            vertex1 = graph.Vertex(atoms * (i + 1), pynn.IF_curr_exp)

            # Generate a self projected edge
            edge = graph.Edge(None, vertex1, vertex1)
            max_atoms_per_core = dict()
            subvertices, subedges = basic_partitioner.BasicPartitioner.partition_raw(
                machine, [vertex1], max_atoms_per_core)

            # subvertices should be an instance of the Subvertex class
            for subvertex in subvertices:
                self.assertIsInstance(subvertex, graph.Subvertex)

            # subedges should be an instance of the Subvedge class
            for subedge in subedges:
                self.assertIsInstance(subedge, graph.Subedge)

            # subvertices are equal to the number of i+1
            self.assertEqual(len(subvertices), (i + 1))

            # subedges should be squared the number of subvertices
            self.assertEqual(len(subedges), (i + 1)**2)
コード例 #10
0
    def test_partition_production_with_self_projected_edge(self):
        """            
            Calculates max atoms per vertex based on the vertex model and then
            it creates a vertex and adds an edge which projects back to itself.
            This test checks if the subvertices are an instance of graph.Subvertex,
            subedges are an instance of graph.SubEdge
            if total number of subvertices and subedges is 1.
            
            """
        # Specify a SpiNNaker machine
        machine = lib_machine.Machine('test', 1, 1, 'unwrapped')

        # Calculate the max atoms per core
        # The following code has been taken from core.mapper.partition_raw
        requirements = pynn.IF_curr_exp.get_requirements_per_atom()
        resources = machine.get_resources_per_processor()
        atoms = resources / requirements

        vertex1 = graph.Vertex(atoms, pynn.IF_curr_exp)

        pdb.set_trace
        edge = graph.Edge(None, vertex1, vertex1)
        max_atoms_per_core = dict()
        subvertices, subedges = basic_partitioner.BasicPartitioner.partition_raw(
            machine, [vertex1], max_atoms_per_core)

        # subvertices should be an instance of the Subvertex class
        for subvertex in subvertices:
            self.assertIsInstance(subvertex, graph.Subvertex)

        # subedges should be an instance of the Subvedge class
        for subedge in subedges:
            self.assertIsInstance(subedge, graph.Subedge)

        # subvertices should have only two vertices since all atoms fit in two
        # cores
        self.assertEqual(len(subvertices), 1)

        # subedges should be zero
        self.assertEqual(len(subedges), 1)
コード例 #11
0
 def stream(self):
     # If the monitor is enabled, add an edge to the monitor
     global appMonitorVertex
     self.vertex.setup_visualizer(visualiser_mode=visualiser_modes.RASTER)
     if appMonitorVertex != None:
         controller.add_edge(graph.Edge(self.vertex, appMonitorVertex))
コード例 #12
0
    def try_creating_route(source, dests, machine_id):
        '''
        create vertexes subverts and placements, run routing, and start backward chasing
        '''
        the_machine = None
        #initilise machine
        description = machines.machines[machine_id]
        the_machine = machine.Machine(**description)
        subedges = dict()
        sub_verts = list()
        src_vertex_constraints = lib_map.VertexConstraints(x=source[0],
                                                           y=source[1],
                                                           p=source[2])
        src_vrt = models.IF_curr_exp(1, constraints=src_vertex_constraints)
        src_sub_vert = graph.Subvertex(src_vrt, 0, 1, 0)
        sub_verts.append(src_sub_vert)

        #place vertexes in correct cores
        placement_chip = the_machine.get_chip(
            src_sub_vert.vertex.constraints.x,
            src_sub_vert.vertex.constraints.y)
        placement_processor = placement_chip.get_processor(
            src_sub_vert.vertex.constraints.p)
        placement = lib_map.Placement(src_sub_vert, placement_processor)
        src_sub_vert.placement = placement

        #add subvert and edge for each destination vertex
        dest_subverts = list()
        for dest in dests:

            dest_vertex_constraints = lib_map.VertexConstraints(x=dest[0],
                                                                y=dest[1],
                                                                p=dest[2])
            dest_vrt = models.IF_curr_exp(1,
                                          constraints=dest_vertex_constraints)
            dest_sub_vert = graph.Subvertex(dest_vrt, 0, 1, 0)

            edge = graph.Edge(src_vrt, dest_vrt)
            sbedge = graph.Subedge(edge, src_sub_vert, dest_sub_vert)
            #give its routing key and mask
            key, mask = src_sub_vert.vertex.generate_routing_info(sbedge)
            sbedge.key = key
            sbedge.mask = mask
            sbedge.key_mask_combo = key & mask

            subedges[dest_sub_vert] = sbedge
            sub_verts.append(dest_sub_vert)
            dest_subverts.append(dest_sub_vert)
            #place vertexes in correct cores
            placement_chip = the_machine.get_chip(
                dest_sub_vert.vertex.constraints.x,
                dest_sub_vert.vertex.constraints.y)
            placement_processor = placement_chip.get_processor(
                dest_sub_vert.vertex.constraints.p)
            placement = lib_map.Placement(dest_sub_vert, placement_processor)
            dest_sub_vert.placement = placement

        fails = list()

        #try to route between the verts
        try:
            dijkstra_routing.DijkstraRouting.route_raw(the_machine, sub_verts)
            return src_sub_vert, dest_subverts, machine, subedges, None
        except Exception as e:
            print traceback.print_exc(e)
            return src_sub_vert, dest_subverts, machine, subedges, \
                   fails.append([src_sub_vert, dests, "failed to generate a route"])
コード例 #13
0
    def test_routing_simple(self):
        #print "test_routing simple"
        the_machine = machine.Machine('host', type="spinn4")

        src_vrt = graph.Vertex(1, None)
        src_vrt.model = models.IF_curr_exp
        dst_vrt = graph.Vertex(1, None)
        dst_vrt.model = models.IF_curr_exp
        edge = graph.Edge(src_vrt, dst_vrt)

        src_sbvrt = graph.Subvertex(src_vrt, 0, 0, None)
        dst_sbvrt = graph.Subvertex(dst_vrt, 0, 0, None)
        sbedge = graph.Subedge(edge, src_sbvrt, dst_sbvrt)

        radial_placer = radial_placer.RadialPlacer(None)
        radial_placer.RadialPlacer.place_raw(the_machine,
                                             [src_sbvrt, dst_sbvrt])

        dijkstra_routing.DijkstraRouting.route_raw(the_machine,
                                                   [src_sbvrt, dst_sbvrt])
        #the machine object now contains all the routes
        #now I need to test that the routes are correct
        #(i.e. from a single source they go to the correct destination(s))

        out_sbedges_lst = src_sbvrt.out_subedges

        #the routing key dictionary associates to a routing key the list of
        #destinations
        rt_key_list = dict()

        for i in range(len(out_sbedges_lst)):

            #for each subvertex and for each subedge key and mask are retrieved
            key, mask = src_sbvrt.vertex.model.generate_routing_info(
                out_sbedges_lst[i])

            #then the destination of the subedge is retrieved
            dst = out_sbedges_lst[
                i].postsubvertex.placement.processor.get_coordinates()

            #and it is added to the appropriate list
            #then all the destinations are merged in the list rt_key_list
            if key in rt_key_list:
                #if the routing key for the subedge is already in the rt_key_list
                #then append the destination to the list of the destinations
                #extracted from the graph
                if dst not in rt_key_list[key]:
                    rt_key_list[key].append(dst)
            else:
                #if the routing key was not present in the lsit of already known
                #routing keys, then append it with the new destination
                rt_key_list.update({key: [dst]})

            #rt_key list at this point is a dictionary of elements; each of these
            #elements contains a list where the elements are destinations

            #{'key1':[dst1, dst2, ...], 'key2':[dst3, dst4, ...], ...}

        for i in range(len(rt_key_list.keys())):
            #retrieve the list of desired destinations from rt_key_list
            key = rt_key_list.keys()[i]
            desired_dsts = rt_key_list[key]
            #sort destinations
            desired_dsts.sort()

            #get from the binaries of the routing tables the destination core(s)
            #for a specific routing key starting from a particular chip
            test = TestRoutes(the_machine, src_sbvrt, key)
            test.TraceRoute()
            dsts = test.dsts
            dsts.sort()
            #dsts contains the list of processors to which the routing key is
            #addresses. this list must be equal to the desired destination(s)
            #extracted from the graph

            #test desired_dsts and dsts. if not equal, the routing made a mess!
            #print "desired_dsts: ", desired_dsts
            #print "dsts: ",dsts
            self.assertEqual(dsts, desired_dsts)
コード例 #14
0
    def test_routing(self):

        the_machine = machine.Machine('host', type="spinn4")

        machine_size = len(the_machine.processors)
        vertexes = list()

        for i in xrange(machine_size):
            v = graph.Vertex(1, None)
            v.model = models.IF_curr_exp
            vertexes.append(v)

        number_of_projections = machine_size * machine_size * test_connectivity_percentage
        src_vertexes = random.sample(
            xrange(machine_size),
            int(math.ceil(math.sqrt(number_of_projections))))
        dst_vertexes = random.sample(
            xrange(machine_size),
            int(math.floor(math.sqrt(number_of_projections))))

        src_vertexes.sort()
        dst_vertexes.sort()

        #        print "test_routing: total number of projections:", number_of_projections
        #        print "test_routing: source vertexes", src_vertexes
        #        print "test_routing: destination vertexes:", dst_vertexes
        #        print "test_routing: number of projections:", len(src_vertexes) * len(dst_vertexes)

        edges = list()
        for i in xrange(len(src_vertexes)):
            for j in xrange(len(dst_vertexes)):
                src = vertexes[src_vertexes[i]]
                dst = vertexes[src_vertexes[j]]
                edges.append(graph.Edge(src, dst))

        subvertexes = list()
        for i in xrange(machine_size):
            subvertexes.append(graph.Subvertex(vertexes[i], 0, 0, None))

        sb_edges = list()
        for i in xrange(len(edges)):
            pre = edges[i].prevertex.subvertices[0]
            post = edges[i].postvertex.subvertices[0]
            sb_edges.append(graph.Subedge(edges[i], pre, post))

        radial_placer.RadialPlacer.place_raw(the_machine, subvertexes)

        dijkstra_routing.DijkstraRouting.route_raw(the_machine, subvertexes)
        #the machine object now contains all the routes
        #now I need to test that the routes are correct
        #(i.e. from a single source they go to the correct destination(s))

        for k in xrange(len(src_vertexes)):
            #take the list of the outgoing edges from each of the subvertexes
            src_sbvrt = subvertexes[src_vertexes[k]]
            out_sbedges_lst = src_sbvrt.out_subedges

            #the routing key dictionary associates to a routing key the list of
            #destinations
            rt_key_list = dict()

            for i in range(len(out_sbedges_lst)):

                #for each subvertex and for each subedge key and mask are retrieved
                key, mask = src_sbvrt.vertex.model.generate_routing_info(
                    out_sbedges_lst[i])

                #then the destination of the subedge is retrieved
                dst = out_sbedges_lst[
                    i].postsubvertex.placement.processor.get_coordinates()

                #and it is added to the appropriate list
                #then all the destinations are merged in the list rt_key_list
                if key in rt_key_list:
                    #if the routing key for the subedge is already in the rt_key_list
                    #then append the destination to the list of the destinations
                    #extracted from the graph
                    if dst not in rt_key_list[key]:
                        rt_key_list[key].append(dst)
                else:
                    #if the routing key was not present in the lsit of already known
                    #routing keys, then append it with the new destination
                    rt_key_list.update({key: [dst]})

                #rt_key list at this point is a dictionary of elements; each of these
                #elements contains a list where the elements are destinations

                #{'key1':[dst1, dst2, ...], 'key2':[dst3, dst4, ...], ...}

            for i in range(len(rt_key_list.keys())):
                #retrieve the list of desired destinations from rt_key_list
                key = rt_key_list.keys()[i]
                desired_dsts = rt_key_list[key]
                #sort destinations
                desired_dsts.sort()
                #print "Desired destinations:", desired_dsts

                #get from the binaries of the routing tables the destination core(s)
                #for a specific routing key starting from a particular chip
                test = TestRoutes(the_machine, src_sbvrt, key)
                test.TraceRoute()
                dsts = test.dsts
                dsts.sort()
                #print "Actual destinations:", dsts
                #dsts contains the list of processors to which the routing key is
                #addresses. this list must be equal to the desired destination(s)
                #extracted from the graph

                #test desired_dsts and dsts. if not equal, the routing made a mess!
                self.assertEqual(dsts, desired_dsts)