def _do_allocation(
            self, one_to_one_groups, same_chip_vertex_groups,
            machine, plan_n_timesteps, machine_graph, progress):
        """
        :param list(set(MachineVertex)) one_to_one_groups:
            Groups of vertexes that would be nice on same chip
        :param same_chip_vertex_groups:
            Mapping of Vertex to the Vertex that must be on the same Chip
        :type same_chip_vertex_groups:
            dict(MachineVertex, collection(MachineVertex))
        :param ~spinn_machine.Machine machine:
            The machine with respect to which to partition the application
            graph
        :param int plan_n_timesteps: number of timesteps to plan for
        :param MachineGraph machine_graph: The machine_graph to place
        :param ~spinn_utilities.progress_bar.ProgressBar progress:
        :rtype: Placements
        """

        placements = Placements()

        resource_tracker = ResourceTracker(
            machine, plan_n_timesteps, self._generate_radial_chips(machine))
        all_vertices_placed = set()

        # RadialPlacementFromChipConstraint won't work here
        for vertex in machine_graph.vertices:
            for constraint in vertex.constraints:
                if isinstance(constraint, RadialPlacementFromChipConstraint):
                    raise PacmanPlaceException(
                        "A RadialPlacementFromChipConstraint will not work "
                        "with the OneToOnePlacer algorithm; use the "
                        "RadialPlacer algorithm instead")

        # Find and place vertices with hard constraints
        for vertex in machine_graph.vertices:
            if isinstance(vertex, AbstractVirtual):
                virtual_p = 0
                while placements.is_processor_occupied(
                        vertex.virtual_chip_x, vertex.virtual_chip_y,
                        virtual_p):
                    virtual_p += 1
                placements.add_placement(Placement(
                    vertex, vertex.virtual_chip_x, vertex.virtual_chip_y,
                    virtual_p))
                all_vertices_placed.add(vertex)
            elif locate_constraints_of_type(
                    vertex.constraints, ChipAndCoreConstraint):
                self._allocate_same_chip_as_group(
                    vertex, placements, resource_tracker,
                    same_chip_vertex_groups, all_vertices_placed, progress,
                    machine_graph)

        for grouped_vertices in one_to_one_groups:
            # Get unallocated vertices and placements of allocated vertices
            unallocated = list()
            chips = list()
            for vert in grouped_vertices:
                if vert in all_vertices_placed:
                    placement = placements.get_placement_of_vertex(vert)
                    chips.append((placement.x, placement.y))
                else:
                    unallocated.append(vert)
            if not chips:
                chips = None

            if 0 < len(unallocated) <=\
                    resource_tracker.get_maximum_cores_available_on_a_chip():
                # Try to allocate all vertices to the same chip
                self._allocate_one_to_one_group(
                    resource_tracker, unallocated, progress, placements, chips,
                    all_vertices_placed, machine_graph)
            # if too big or failed go on to other groups first

        # check all have been allocated if not do so now.
        for vertex in machine_graph.vertices:
            if vertex not in all_vertices_placed:
                self._allocate_same_chip_as_group(
                    vertex, placements, resource_tracker,
                    same_chip_vertex_groups, all_vertices_placed,
                    progress, machine_graph)

        progress.end()
        return placements
    def _do_allocation(
            self, one_to_one_groups, same_chip_vertex_groups,
            machine, plan_n_timesteps, machine_graph, progress):
        """

        :param one_to_one_groups:
            Groups of vertexes that would be nice on same chip
        :type one_to_one_groups:
            list(set(vertex))
        :param same_chip_vertex_groups:
            Mapping of Vertex to the Vertex that must be on the same Chip
        :type same_chip_vertex_groups:
            dict(vertex, collection(vertex))
        :param machine:\
            The machine with respect to which to partition the application\
            graph
        :type machine: :py:class:`spinn_machine.Machine`
        :param plan_n_timesteps: number of timesteps to plan for
        :type  plan_n_timesteps: int
        :param machine_graph: The machine_graph to place
        :type machine_graph:\
            :py:class:`pacman.model.graphs.machine.MachineGraph`
        :param progress:
        :return:
        """

        placements = Placements()

        resource_tracker = ResourceTracker(
            machine, plan_n_timesteps, self._generate_radial_chips(machine))
        all_vertices_placed = set()

        # RadialPlacementFromChipConstraint won't work here
        for vertex in machine_graph.vertices:
            for constraint in vertex.constraints:
                if isinstance(constraint, RadialPlacementFromChipConstraint):
                    raise PacmanPlaceException(
                        "A RadialPlacementFromChipConstraint will not work "
                        "with the OneToOnePlacer algorithm; use the "
                        "RadialPlacer algorithm instead")

        unconstrained = list()
        # Find and place vertices with hard constraints
        for vertex in machine_graph.vertices:
            if isinstance(vertex, AbstractVirtualVertex):
                virtual_p = 0
                while placements.is_processor_occupied(
                        vertex.virtual_chip_x, vertex.virtual_chip_y,
                        virtual_p):
                    virtual_p += 1
                placements.add_placement(Placement(
                    vertex, vertex.virtual_chip_x, vertex.virtual_chip_y,
                    virtual_p))
                all_vertices_placed.add(vertex)
            elif locate_constraints_of_type(
                    vertex.constraints, ChipAndCoreConstraint):
                self._allocate_same_chip_as_group(
                    vertex, placements, resource_tracker,
                    same_chip_vertex_groups,
                    all_vertices_placed, progress)
            else:
                unconstrained.append(vertex)

        for grouped_vertices in one_to_one_groups:
            # Get unallocated vertices and placements of allocated vertices
            unallocated = list()
            chips = list()
            for vert in grouped_vertices:
                if vert in all_vertices_placed:
                    placement = placements.get_placement_of_vertex(vert)
                    chips.append((placement.x, placement.y))
                else:
                    unallocated.append(vert)

            if 0 < len(unallocated) <=\
                    resource_tracker.get_maximum_cores_available_on_a_chip():
                # Try to allocate all vertices to the same chip
                self._allocate_one_to_one_group(
                    resource_tracker, unallocated, progress, placements, chips,
                    all_vertices_placed)
            # if too big or failed go on to other groups first

        # check all have been allocated if not do so now.
        for vertex in machine_graph.vertices:
            if vertex not in all_vertices_placed:
                self._allocate_same_chip_as_group(
                    vertex, placements, resource_tracker,
                    same_chip_vertex_groups, all_vertices_placed,
                    progress)

        progress.end()
        return placements
Exemplo n.º 3
0
    def _create_fake_network(self, ethernet_connected_chip):
        """ Generate the fake network for each board

        :param ethernet_connected_chip: the ethernet chip to fire from
        :return: fake graph, fake placements, fake machine.
        """

        fake_graph = MachineGraph(label="routing fake_graph")
        fake_placements = Placements()
        destination_to_partition_id_map = dict()

        # build fake setup for the routing
        eth_x = ethernet_connected_chip.x
        eth_y = ethernet_connected_chip.y
        fake_machine = virtual_submachine(self._real_machine,
                                          ethernet_connected_chip)

        # Build a fake graph with vertices for all the monitors
        for chip in self._real_machine.get_chips_by_ethernet(eth_x, eth_y):
            # locate correct chips extra monitor placement
            placement = self._real_placements.get_placement_of_vertex(
                self._monitors[chip.x, chip.y])

            # adjust for wrap around's
            fake_x, fake_y = self._real_machine.get_local_xy(chip)

            # add destination vertex
            vertex = RoutingMachineVertex()
            fake_graph.add_vertex(vertex)

            # build fake placement
            fake_placements.add_placement(
                Placement(x=fake_x, y=fake_y, p=placement.p, vertex=vertex))

        # build source vertex, which is for the Gatherer
        vertex_source = RoutingMachineVertex()
        fake_graph.add_vertex(vertex_source)

        for free_processor in range(Machine.MAX_CORES_PER_CHIP):
            if not fake_placements.is_processor_occupied(
                    x=FAKE_ETHERNET_CHIP_X,
                    y=FAKE_ETHERNET_CHIP_Y,
                    p=free_processor):
                fake_placements.add_placement(
                    Placement(x=FAKE_ETHERNET_CHIP_X,
                              y=FAKE_ETHERNET_CHIP_Y,
                              p=free_processor,
                              vertex=vertex_source))
                break

        # deal with edges, each one being in a unique partition id, to
        # allow unique routing to each chip.
        counter = KEY_START_VALUE
        for vertex in fake_graph.vertices:
            if vertex == vertex_source:
                continue
            fake_graph.add_edge(
                MachineEdge(pre_vertex=vertex_source, post_vertex=vertex),
                counter)
            placement = fake_placements.get_placement_of_vertex(vertex)

            # adjust to real chip ids
            real_chip_xy = self._real_machine.get_global_xy(
                placement.x, placement.y, eth_x, eth_y)
            destination_to_partition_id_map[real_chip_xy] = counter
            counter += N_KEYS_PER_PARTITION_ID

        return (fake_graph, fake_placements, fake_machine,
                destination_to_partition_id_map)
Exemplo n.º 4
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
    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.link_ids,
                processor_ids=mc_entry.processor_ids)
            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