Exemple #1
0
    def test_routing(self):
        graph = MachineGraph("Test")
        machine = VirtualMachine(2, 2)
        placements = Placements()
        vertices = list()

        for x in range(machine.max_chip_x + 1):
            for y in range(machine.max_chip_y + 1):
                chip = machine.get_chip_at(x, y)
                if chip is not None:
                    for processor in chip.processors:
                        if not processor.is_monitor:
                            vertex = SimpleMachineVertex(
                                resources=ResourceContainer())
                            graph.add_vertex(vertex)
                            placements.add_placement(
                                Placement(vertex, x, y,
                                          processor.processor_id))
                            vertices.append(vertex)

        for vertex in vertices:
            for vertex_to in vertices:
                if vertex != vertex_to:
                    graph.add_edge(MachineEdge(vertex, vertex_to), "Test")

        router = BasicDijkstraRouting()
        routing_paths = router.__call__(placements, machine, graph)

        for vertex in vertices:
            vertices_reached = set()
            queue = deque()
            seen_entries = set()
            placement = placements.get_placement_of_vertex(vertex)
            partition = graph.get_outgoing_edge_partition_starting_at_vertex(
                vertex, "Test")
            entry = routing_paths.get_entry_on_coords_for_edge(
                partition, placement.x, placement.y)
            self.assertEqual(entry.incoming_processor, placement.p)
            queue.append((placement.x, placement.y))
            while len(queue) > 0:
                x, y = queue.pop()
                entry = routing_paths.get_entry_on_coords_for_edge(
                    partition, x, y)
                self.assertIsNotNone(entry)
                chip = machine.get_chip_at(x, y)
                for p in entry.out_going_processors:
                    self.assertIsNotNone(chip.get_processor_with_id(p))
                    vertex_found = placements.get_vertex_on_processor(x, y, p)
                    vertices_reached.add(vertex_found)
                seen_entries.add((x, y))
                for link_id in entry.out_going_links:
                    link = chip.router.get_link(link_id)
                    self.assertIsNotNone(link)
                    dest_x, dest_y = link.destination_x, link.destination_y
                    if (dest_x, dest_y) not in seen_entries:
                        queue.append((dest_x, dest_y))

            for vertex_to in vertices:
                if vertex != vertex_to:
                    self.assertIn(vertex_to, vertices_reached)
    def test_routing(self):
        graph = MachineGraph("Test")
        machine = VirtualMachine(2, 2)
        placements = Placements()
        vertices = list()

        for x in range(machine.max_chip_x + 1):
            for y in range(machine.max_chip_y + 1):
                chip = machine.get_chip_at(x, y)
                if chip is not None:
                    for processor in chip.processors:
                        if not processor.is_monitor:
                            vertex = SimpleMachineVertex(
                                resources=ResourceContainer())
                            graph.add_vertex(vertex)
                            placements.add_placement(Placement(
                                vertex, x, y, processor.processor_id))
                            vertices.append(vertex)

        for vertex in vertices:
            for vertex_to in vertices:
                if vertex != vertex_to:
                    graph.add_edge(MachineEdge(vertex, vertex_to), "Test")

        router = BasicDijkstraRouting()
        routing_paths = router.__call__(placements, machine, graph)

        for vertex in vertices:
            vertices_reached = set()
            queue = deque()
            seen_entries = set()
            placement = placements.get_placement_of_vertex(vertex)
            partition = graph.get_outgoing_edge_partition_starting_at_vertex(
                vertex, "Test")
            entry = routing_paths.get_entry_on_coords_for_edge(
                partition, placement.x, placement.y)
            self.assertEqual(entry.incoming_processor, placement.p)
            queue.append((placement.x, placement.y))
            while len(queue) > 0:
                x, y = queue.pop()
                entry = routing_paths.get_entry_on_coords_for_edge(
                    partition, x, y)
                self.assertIsNotNone(entry)
                chip = machine.get_chip_at(x, y)
                for p in entry.processor_ids:
                    self.assertIsNotNone(chip.get_processor_with_id(p))
                    vertex_found = placements.get_vertex_on_processor(x, y, p)
                    vertices_reached.add(vertex_found)
                seen_entries.add((x, y))
                for link_id in entry.link_ids:
                    link = chip.router.get_link(link_id)
                    self.assertIsNotNone(link)
                    dest_x, dest_y = link.destination_x, link.destination_y
                    if (dest_x, dest_y) not in seen_entries:
                        queue.append((dest_x, dest_y))

            for vertex_to in vertices:
                if vertex != vertex_to:
                    self.assertIn(vertex_to, vertices_reached)
def test_virtual_vertices_one_to_one():
    """ Test that the placer works with a virtual vertex
    """

    # Create a graph with a virtual vertex
    machine_graph = MachineGraph("Test")
    virtual_vertex = MachineSpiNNakerLinkVertex(
        spinnaker_link_id=0, label="Virtual")
    machine_graph.add_vertex(virtual_vertex)

    # These vertices are fixed on 0, 0
    misc_vertices = list()
    for i in range(3):
        misc_vertex = SimpleMachineVertex(
            resources=ResourceContainer(), constraints=[
                ChipAndCoreConstraint(0, 0)],
            label="Fixed_0_0_{}".format(i))
        machine_graph.add_vertex(misc_vertex)
        misc_vertices.append(misc_vertex)

    # These vertices are 1-1 connected to the virtual vertex
    one_to_one_vertices = list()
    for i in range(16):
        one_to_one_vertex = SimpleMachineVertex(
            resources=ResourceContainer(),
            label="Vertex_{}".format(i))
        machine_graph.add_vertex(one_to_one_vertex)
        edge = MachineEdge(virtual_vertex, one_to_one_vertex)
        machine_graph.add_edge(edge, "SPIKES")
        one_to_one_vertices.append(one_to_one_vertex)

    # Get and extend the machine for the virtual chip
    machine = VirtualMachine(version=5)
    extended_machine = MallocBasedChipIdAllocator()(machine, machine_graph)

    # Do placements
    placements = OneToOnePlacer()(
        machine_graph, extended_machine, plan_n_timesteps=1000)

    # The virtual vertex should be on a virtual chip
    placement = placements.get_placement_of_vertex(virtual_vertex)
    assert machine.get_chip_at(placement.x, placement.y).virtual

    # The 0, 0 vertices should be on 0, 0
    for vertex in misc_vertices:
        placement = placements.get_placement_of_vertex(vertex)
        assert placement.x == placement.y == 0

    # The other vertices should *not* be on a virtual chip
    for vertex in one_to_one_vertices:
        placement = placements.get_placement_of_vertex(vertex)
        assert not machine.get_chip_at(placement.x, placement.y).virtual
Exemple #4
0
    def __call__(self,
                 width=None,
                 height=None,
                 virtual_has_wrap_arounds=False,
                 version=None,
                 n_cpus_per_chip=18,
                 with_monitors=True):
        """
        :param width: The width of the machine in chips
        :param height: The height of the machine in chips
        :param virtual_has_wrap_arounds: True if the machine is virtual and\
                should be created with wrap_arounds
        :param version: The version of board to create
        :param n_cpus_per_chip: The number of cores to put on each chip
        :param with_monitors: If true, CPU 0 will be marked as a monitor
        :return: None
        """

        machine = VirtualMachine(width=width,
                                 height=height,
                                 with_wrap_arounds=virtual_has_wrap_arounds,
                                 version=version,
                                 n_cpus_per_chip=n_cpus_per_chip,
                                 with_monitors=with_monitors)

        return {"machine": machine}
Exemple #5
0
    def test_partition_with_fixed_atom_constraints_at_limit(self):
        """
        test a partitioning with a graph with fixed atom constraint which\
        should fit but is close to the limit
        """

        # Create a 2x2 machine with 1 core per chip (so 4 cores),
        # and 8MB SDRAM per chip
        n_cores_per_chip = 1
        sdram_per_chip = 8
        machine = VirtualMachine(width=2,
                                 height=2,
                                 with_monitors=False,
                                 n_cpus_per_chip=n_cores_per_chip,
                                 sdram_per_chip=sdram_per_chip)

        # Create a vertex which will need to be split perfectly into 4 cores
        # to work and which max atoms per core must be ignored
        vertex = SimpleTestVertex(
            sdram_per_chip * 2,
            max_atoms_per_core=sdram_per_chip,
            constraints=[FixedVertexAtomsConstraint(sdram_per_chip // 2)])
        app_graph = ApplicationGraph("Test")
        app_graph.add_vertex(vertex)

        # Do the partitioning - this should just work
        partitioner = BasicPartitioner()
        machine_graph, _, _ = partitioner(app_graph, machine)
        self.assert_(len(machine_graph.vertices) == 4)
Exemple #6
0
    def test_partition_with_fixed_atom_constraints(self):
        """
        test a partitioning with a graph with fixed atom constraint
        """

        # Create a 2x2 machine with 10 cores per chip (so 40 cores),
        # but 1MB off 2MB per chip (so 19MB per chip)
        n_cores_per_chip = 10
        sdram_per_chip = (n_cores_per_chip * 2) - 1
        machine = VirtualMachine(width=2,
                                 height=2,
                                 with_monitors=False,
                                 n_cpus_per_chip=n_cores_per_chip,
                                 sdram_per_chip=sdram_per_chip)

        # Create a vertex where each atom requires 1MB (default) of SDRAM
        # but which can't be subdivided lower than 2 atoms per core.
        # The vertex has 1 atom per MB of SDRAM, and so would fit but will
        # be disallowed by the fixed atoms per core constraint
        vertex = SimpleTestVertex(sdram_per_chip * machine.n_chips,
                                  max_atoms_per_core=2,
                                  constraints=[FixedVertexAtomsConstraint(2)])
        app_graph = ApplicationGraph("Test")
        app_graph.add_vertex(vertex)

        # Do the partitioning - this should result in an error
        with self.assertRaises(PacmanValueError):
            partitioner = BasicPartitioner()
            partitioner(app_graph, machine)
Exemple #7
0
def test_create_constraints_to_file(tmpdir):
    # Construct the sample machine and graph
    machine = VirtualMachine(version=3, with_wrap_arounds=None)
    # TODO: define some extra monitor cores (how?)
    graph = MachineGraph("foo")
    tag1 = IPtagResource("1.2.3.4", 5, False, tag="footag")
    tag2 = ReverseIPtagResource(tag="bartag")
    v0 = SimpleMachineVertex(ResourceContainer(iptags=[tag1],
                                               reverse_iptags=[tag2]),
                             constraints=[ChipAndCoreConstraint(1, 1, 3)])
    graph.add_vertex(v0)
    v0_id = ident(v0)
    v1 = MachineSpiNNakerLinkVertex(2,
                                    constraints=[ChipAndCoreConstraint(1, 1)])
    v1.set_virtual_chip_coordinates(0, 2)
    graph.add_vertex(v1)
    v1_id = ident(v1)

    algo = CreateConstraintsToFile()
    fn = tmpdir.join("foo.json")
    filename, mapping = algo(graph, machine, str(fn))
    assert filename == str(fn)
    for vid in mapping:
        assert vid in [v0_id, v1_id]
        assert vid == ident(mapping[vid])
    obj = json.loads(fn.read())
    baseline = [{
        "type": "reserve_resource",
        "location": None,
        "reservation": [0, 1],
        "resource": "cores"
    }, {
        "type": "location",
        "location": [1, 1],
        "vertex": v0_id
    }, {
        "type": "resource",
        "resource": "cores",
        "range": [3, 4],
        "vertex": v0_id
    }, {
        "type": "resource",
        "resource": "iptag",
        "range": [0, 1],
        "vertex": v0_id
    }, {
        "type": "resource",
        "resource": "reverse_iptag",
        "range": [0, 1],
        "vertex": v0_id
    }, {
        "type": "route_endpoint",
        "direction": "south",
        "vertex": v1_id
    }, {
        "type": "location",
        "location": [1, 0],
        "vertex": v1_id
    }]
    assert obj == baseline
    def __call__(self,
                 spalloc_server,
                 spalloc_port=22244,
                 spalloc_machine=None):
        with ProtocolClient(spalloc_server, spalloc_port) as client:
            machines = client.list_machines()
            # Close the context immediately; don't want to keep this particular
            # connection around as there's not a great chance of this code
            # being rerun in this process any time soon.
        max_width = None
        max_height = None
        max_area = -1

        for machine in self._filter(machines, spalloc_machine):
            # Get the width and height in chips, and logical area in chips**2
            width, height, area = self._get_size(machine)

            # The "biggest" board is the one with the most chips
            if area > max_area:
                max_area = area
                max_width = width
                max_height = height

        if max_width is None:
            raise Exception(
                "The spalloc server appears to have no compatible machines")

        # Return the width and height, and make no assumption about wrap-
        # arounds or version.
        return VirtualMachine(width=max_width,
                              height=max_height,
                              with_wrap_arounds=None,
                              version=None)
Exemple #9
0
    def test_call(self):
        executor = HostExecuteDataSpecification()
        transceiver = _MockTransceiver(user_0_addresses={0: 1000})
        machine = VirtualMachine(2, 2)

        # Write a data spec to execute
        temp_spec = mktemp()
        spec_writer = FileDataWriter(temp_spec)
        spec = DataSpecificationGenerator(spec_writer)
        spec.reserve_memory_region(0, 100)
        spec.reserve_memory_region(1, 100, empty=True)
        spec.reserve_memory_region(2, 100)
        spec.switch_write_focus(0)
        spec.write_value(0)
        spec.write_value(1)
        spec.write_value(2)
        spec.switch_write_focus(2)
        spec.write_value(3)
        spec.end_specification()

        # Execute the spec
        dsg_targets = {(0, 0, 0): temp_spec}
        executor.__call__(transceiver, machine, 30, dsg_targets)

        # Test regions - although 3 are created, only 2 should be uploaded
        # (0 and 2), and only the data written should be uploaded
        # The space between regions should be as allocated regardless of
        # how much data is written
        header_and_table_size = (constants.MAX_MEM_REGIONS + 2) * 4
        regions = transceiver.regions_written
        self.assertEqual(len(regions), 4)

        # Base address for header and table
        self.assertEqual(regions[0][0], 0)

        # Base address for region 0 (after header and table)
        self.assertEqual(regions[1][0], header_and_table_size)

        # Base address for region 2
        self.assertEqual(regions[2][0], header_and_table_size + 200)

        # User 0 write address
        self.assertEqual(regions[3][0], 1000)

        # Size of header and table
        self.assertEqual(len(regions[0][1]), header_and_table_size)

        # Size of region 0
        self.assertEqual(len(regions[1][1]), 12)

        # Size of region 2
        self.assertEqual(len(regions[2][1]), 4)

        # Size of user 0
        self.assertEqual(len(regions[3][1]), 4)
    def __call__(self, hbp_server_url, total_run_time):
        """
        :param hbp_server_url: \
            The URL of the HBP server from which to get the machine
        :param total_run_time: The total run time to request
        """

        max_machine = self._max_machine_request(hbp_server_url, total_run_time)

        # Return the width and height and assume that it has wrap arounds
        return VirtualMachine(
            width=max_machine["width"], height=max_machine["height"],
            with_wrap_arounds=None, version=None)
Exemple #11
0
def test_convert_to_file_machine(tmpdir):
    # Construct the sample machine
    machine = VirtualMachine(version=3, with_wrap_arounds=None)

    # Convert it to JSON
    algo = ConvertToFileMachine()
    fn = tmpdir.join("foo.json")
    filename = algo(machine, str(fn))
    assert filename == str(fn)

    def fix_cre(obj):
        obj = dict(obj)
        if "chip_resource_exceptions" in obj:
            cre = list(obj["chip_resource_exceptions"])
            cre.sort(key=lambda e: (e[0], e[1]))
            obj["chip_resource_exceptions"] = cre
        return obj

    # Rebuild and compare; simplest way of checking given that order is not
    # preserved in the underlying string and altering that is hard
    obj = json.loads(fn.read())
    baseline = {
        "chip_resource_exceptions": [[0, 1, {
            "cores": 17
        }], [1, 0, {
            "cores": 17
        }], [0, 0, {
            "cores": 17,
            "tags": 7
        }], [1, 1, {
            "cores": 17
        }]],
        "chip_resources": {
            "cores": 18,
            "router_entries": 1024,
            "sdram": 119275520,
            "sram": 24320,
            "tags": 0
        },
        "dead_chips": [],
        "dead_links": [[0, 0, "west"], [0, 0, "south_west"], [0, 1, "west"],
                       [0, 1, "south_west"], [1, 0, "east"],
                       [1, 0, "north_east"], [1, 1, "east"],
                       [1, 1, "north_east"]],
        "height":
        2,
        "width":
        2
    }
    assert fix_cre(obj) == fix_cre(baseline)
Exemple #12
0
    def _do_dynamic_routing(
            self, fixed_route_tables, placements, ethernet_connected_chip,
            destination_class, machine, board_version):
        """ Uses a router to route fixed routes

        :param fixed_route_tables: fixed route tables entry holder
        :param placements: placements
        :param ethernet_connected_chip: the chip to consider for this routing
        :param destination_class: the class at the Ethernet connected chip\
            for receiving all these routes.
        :param machine: SpiNNMachine instance
        :param board_version: The version of the machine
        :rtype: None
        """
        graph = MachineGraph(label="routing graph")
        fake_placements = Placements()

        # build fake setup for the routing
        eth_x = ethernet_connected_chip.x
        eth_y = ethernet_connected_chip.y
        down_links = set()
        for (chip_x, chip_y) in machine.get_chips_on_board(
                ethernet_connected_chip):
            vertex = RoutingMachineVertex()
            graph.add_vertex(vertex)
            rel_x = chip_x - eth_x
            if rel_x < 0:
                rel_x += machine.max_chip_x + 1
            rel_y = chip_y - eth_y
            if rel_y < 0:
                rel_y += machine.max_chip_y + 1

            free_processor = 0
            while ((free_processor < machine.MAX_CORES_PER_CHIP) and
                   fake_placements.is_processor_occupied(
                       self.FAKE_ETHERNET_CHIP_X,
                       y=self.FAKE_ETHERNET_CHIP_Y,
                       p=free_processor)):
                free_processor += 1

            fake_placements.add_placement(Placement(
                x=rel_x, y=rel_y, p=free_processor, vertex=vertex))
            down_links.update({
                (rel_x, rel_y, link) for link in range(
                    Router.MAX_LINKS_PER_ROUTER)
                if not machine.is_link_at(chip_x, chip_y, link)})

        # Create a fake machine consisting of only the one board that
        # the routes should go over
        fake_machine = machine
        if (board_version in machine.BOARD_VERSION_FOR_48_CHIPS and
                (machine.max_chip_x > machine.MAX_CHIP_X_ID_ON_ONE_BOARD or
                 machine.max_chip_y > machine.MAX_CHIP_Y_ID_ON_ONE_BOARD)):
            down_chips = {
                (x, y) for x, y in zip(
                    range(machine.SIZE_X_OF_ONE_BOARD),
                    range(machine.SIZE_Y_OF_ONE_BOARD))
                if not machine.is_chip_at(
                    (x + eth_x) % (machine.max_chip_x + 1),
                    (y + eth_y) % (machine.max_chip_y + 1))}

            # build a fake machine which is just one board but with the missing
            # bits of the real board
            fake_machine = VirtualMachine(
                machine.SIZE_X_OF_ONE_BOARD, machine.SIZE_Y_OF_ONE_BOARD,
                False, down_chips=down_chips, down_links=down_links)

        # build destination
        verts = graph.vertices
        vertex_dest = RoutingMachineVertex()
        graph.add_vertex(vertex_dest)
        destination_processor = self._locate_destination(
            ethernet_chip_x=ethernet_connected_chip.x,
            ethernet_chip_y=ethernet_connected_chip.y,
            destination_class=destination_class,
            placements=placements)
        fake_placements.add_placement(Placement(
            x=self.FAKE_ETHERNET_CHIP_X, y=self.FAKE_ETHERNET_CHIP_Y,
            p=destination_processor, vertex=vertex_dest))

        # deal with edges
        for vertex in verts:
            graph.add_edge(
                MachineEdge(pre_vertex=vertex, post_vertex=vertex_dest),
                self.FAKE_ROUTING_PARTITION)

        # route as if using multicast
        router = BasicDijkstraRouting()
        routing_tables_by_partition = router(
            placements=fake_placements, machine=fake_machine,
            machine_graph=graph, use_progress_bar=False)

        # convert to fixed route entries
        for (chip_x, chip_y) in routing_tables_by_partition.get_routers():
            mc_entries = routing_tables_by_partition.get_entries_for_router(
                chip_x, chip_y)
            # only want the first entry, as that will all be the same.
            mc_entry = next(itervalues(mc_entries))
            fixed_route_entry = FixedRouteEntry(
                link_ids=mc_entry.out_going_links,
                processor_ids=mc_entry.out_going_processors)
            x = (chip_x + eth_x) % (machine.max_chip_x + 1)
            y = (chip_y + eth_y) % (machine.max_chip_y + 1)
            key = (x, y)
            if key in fixed_route_tables:
                raise PacmanAlreadyExistsException(
                    "fixed route entry", str(key))
            fixed_route_tables[key] = fixed_route_entry