Skip to content
21 changes: 11 additions & 10 deletions pacman/operations/fixed_route_router/fixed_route_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Dict, List, Tuple, Type
from typing import Dict, List, Optional, Tuple, Type
from spinn_utilities.progress_bar import ProgressBar
from spinn_machine import Chip, RoutingEntry
from pacman.data import PacmanDataView
from pacman.exceptions import (
PacmanAlreadyExistsException, PacmanConfigurationException,
PacmanRoutingException)
PacmanAlreadyExistsException, PacmanRoutingException)


def fixed_route_router(
Expand Down Expand Up @@ -83,6 +82,12 @@ def _route_board(self, ethernet_chip: Chip) -> None:
:raises PacmanRoutingException:
:raises PacmanAlreadyExistsException:
"""
# locate where to put data on Ethernet chip
processor_id = self.__locate_destination(ethernet_chip)
if processor_id is None:
# board not used so no routes needed
return

eth_x = ethernet_chip.x
eth_y = ethernet_chip.y

Expand Down Expand Up @@ -115,8 +120,6 @@ def _route_board(self, ethernet_chip: Chip) -> None:
routed |= found

# create final fixed route entry
# locate where to put data on Ethernet chip
processor_id = self.__locate_destination(ethernet_chip)
# build entry and add to tables
self.__add_fixed_route_entry((eth_x, eth_y), [], [processor_id])

Expand All @@ -132,16 +135,14 @@ def __add_fixed_route_entry(self, key: Tuple[int, int],
self._fixed_route_tables[key] = RoutingEntry(
link_ids=link_ids, processor_ids=processor_ids)

def __locate_destination(self, chip: Chip) -> int:
def __locate_destination(self, chip: Chip) -> Optional[int]:
"""
Locate destination vertex on an (Ethernet-connected) chip to send
fixed data to.

:return: processor ID as a int
:raises PacmanConfigurationException: if no placement processor found
:return: processor ID as a int or None if not found
"""
for placement in PacmanDataView.iterate_placements_by_xy_and_type(
chip, self._destination_class):
return placement.p
raise PacmanConfigurationException(
f"no destination vertex found on Ethernet chip {chip.x}:{chip.y}")
return None
46 changes: 21 additions & 25 deletions pacman/operations/placer_algorithms/application_placer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
logger = FormatAdapter(logging.getLogger(__name__))


def place_application_graph(system_placements: Placements) -> Placements:
def place_application_graph(system_placements: Placements) -> None:
"""
Perform placement of an application graph on the machine.

Expand All @@ -43,10 +43,9 @@ def place_application_graph(system_placements: Placements) -> Placements:

:param system_placements:
The placements of cores doing system tasks. This is what we start from.
:return: Placements for the application. *Includes the system placements.*
"""
placer = ApplicationPlacer(system_placements)
return placer.do_placements(system_placements)
placer.do_placements()


class ApplicationPlacer(object):
Expand All @@ -62,8 +61,6 @@ class ApplicationPlacer(object):
"__plan_n_timesteps",
# Sdram available on perfect none Ethernet Chip after Monitors placed
"__max_sdram",
# Maximum sdram that should be used for a Chip to not be full
"__cap_sdram",
# N Cores free on perfect none Ethernet Chip after Monitors placed
"__max_cores",

Expand All @@ -89,6 +86,8 @@ class ApplicationPlacer(object):
"__current_cores_free",
# Used sdram after the current group is placed
"__current_sdram_used",
# Number of cores needed for monitors
"__current_monitor_cores",

# Data about the neighbouring Chips to ones used
# Current board being placed on
Expand All @@ -114,8 +113,6 @@ def __init__(self, placements: Placements):
self.__max_cores = (
version.max_cores_per_chip - version.n_scamp_cores -
PacmanDataView.get_all_monitor_cores())
self.__cap_sdram = self.__max_sdram - (
self.__max_sdram // self.__max_cores)

self.__placements = placements
self.__chips = self._chip_order()
Expand All @@ -127,6 +124,7 @@ def __init__(self, placements: Placements):

self.__current_chip: Optional[Chip] = None
self.__current_cores_free: List[int] = list()
self.__current_monitor_cores = 0
self.__current_sdram_used: AbstractSDRAM = ConstantSDRAM(0)
self.__app_vertex_label: Optional[str] = None

Expand All @@ -136,17 +134,13 @@ def __init__(self, placements: Placements):
self.__same_board_chips: Dict[Chip, Chip] = dict()
self.__other_board_chips: Dict[Chip, Chip] = dict()

def do_placements(self, system_placements: Placements) -> Placements:
def do_placements(self) -> None:
"""
Perform placement of an application graph on the machine.

.. note::
app_graph must have been partitioned

:param system_placements:
The placements of cores doing system tasks.
:return: Placements for the application.
*Includes the system placements.*
:raises PacmanPlaceException: If no new start Chip is available
:raises PacmanTooBigToPlace:
If the requirements are too big for any chip
Expand All @@ -164,13 +158,11 @@ def do_placements(self, system_placements: Placements) -> Placements:
# as this checks if placed already not need to check if fixed
self._place_vertex(app_vertex)
except PacmanPlaceException as e:
raise self._place_error(system_placements, e) from e
raise self._place_error(self.__placements, e) from e

if get_config_bool("Reports", "draw_placements"):
report_file = get_report_path("path_placements")
dp(self.__placements, system_placements, report_file)

return self.__placements
dp(self.__placements, self.__placements, report_file)

def _place_vertex(self, app_vertex: ApplicationVertex) -> None:
"""
Expand Down Expand Up @@ -457,30 +449,33 @@ def _space_on_chip(
If the requirements are too big for any chip
"""
cores_free = list(chip.placable_processors_ids)
sdram_used: AbstractSDRAM = ConstantSDRAM(0)
if chip.ip_address: # Ethernet
sdram_used = PacmanDataView.get_ethernet_monitor_sdram()
self.__current_monitor_cores = (
PacmanDataView.get_ethernet_monitor_cores())
else:
sdram_used = PacmanDataView.get_all_monitor_sdram()
self.__current_monitor_cores = (
PacmanDataView.get_all_monitor_cores())

# remove the already placed for other Application Vertices
on_chip = self.__placements.placements_on_chip(chip)
if len(on_chip) == len(cores_free):
if len(on_chip) + self.__current_monitor_cores >= len(cores_free):
self.__full_chips.add(chip)
return False

for placement in on_chip:
cores_free.remove(placement.p)
sdram_used += placement.vertex.sdram_required

if sdram_used.get_total_sdram(
self.__plan_n_timesteps) > self.__cap_sdram:
self.__full_chips.add(chip)
return False

# Remember this chip so it is not tried again in this preparation
# This assumes all groups are the same size so even if too small
self.__prepared_chips.add(chip)

total_sdram = sdram_used + sdram
plan_sdram = total_sdram.get_total_sdram(self.__plan_n_timesteps)
if len(cores_free) < n_cores or plan_sdram > chip.sdram:
if (len(cores_free) < n_cores + self.__current_monitor_cores
or plan_sdram > chip.sdram):
self._check_could_fit(n_cores, sdram)
return False

Expand Down Expand Up @@ -639,7 +634,8 @@ def _get_next_chip_with_space(
total_sdram = sdram + self.__current_sdram_used
plan_sdram = total_sdram.get_total_sdram(
self.__plan_n_timesteps)
if (len(self.__current_cores_free) >= n_cores and
if (len(self.__current_cores_free) >=
n_cores + self.__current_monitor_cores and
plan_sdram <= self.__current_chip.sdram):
# Cores are popped out later
self.__current_sdram_used = total_sdram
Expand Down
56 changes: 42 additions & 14 deletions unittests/operations_tests/router_algorithms_tests/test_routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,9 @@ def test_simple(params: TA_PARAMS) -> None:
target_vertex = _make_vertices(writer, 1000, n_m_vertices, "target")
writer.add_edge(ApplicationEdge(source_vertex, target_vertex), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -623,7 +625,9 @@ def test_self(params: TA_PARAMS) -> None:
source_vertex = _make_vertices(writer, 1000, n_m_vertices, "self")
writer.add_edge(ApplicationEdge(source_vertex, source_vertex), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -639,7 +643,9 @@ def test_simple_self(params: TA_PARAMS) -> None:
writer.add_edge(ApplicationEdge(target_vertex, target_vertex), "Test")
writer.add_edge(ApplicationEdge(source_vertex, target_vertex), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -656,7 +662,9 @@ def test_multi(params: TA_PARAMS) -> None:
if source != target:
writer.add_edge(ApplicationEdge(source, target), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -672,7 +680,9 @@ def test_multi_self(params: TA_PARAMS) -> None:
for target in writer.iterate_vertices():
writer.add_edge(ApplicationEdge(source, target), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -692,7 +702,9 @@ def test_multi_split(params: TA_PARAMS) -> None:

writer.set_machine(virtual_machine_by_cores(
n_cores=writer.get_n_machine_vertices()))
writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -711,7 +723,9 @@ def test_multi_self_split(params: TA_PARAMS) -> None:

writer.set_machine(virtual_machine_by_cores(
n_cores=writer.get_n_machine_vertices()))
writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -727,7 +741,9 @@ def test_multi_down_chips_and_links(params: TA_PARAMS) -> None:
for target in writer.iterate_vertices():
writer.add_edge(ApplicationEdge(source, target), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)

# Pick a few of the chips and links used and take them out
Expand Down Expand Up @@ -768,7 +784,9 @@ def test_multi_down_chips_and_links(params: TA_PARAMS) -> None:
print("Down links:", down_links[:-1].split(":"))
set_config("Machine", "down_chips", down_chips[:-1])
set_config("Machine", "down_links", down_links[:-1])
writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -784,7 +802,9 @@ def test_internal_only(params: TA_PARAMS) -> None:

writer.set_machine(virtual_machine_by_cores(
n_cores=writer.get_n_machine_vertices()))
writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -805,7 +825,9 @@ def test_internal_and_split(params: TA_PARAMS) -> None:

writer.set_machine(virtual_machine_by_cores(
n_cores=writer.get_n_machine_vertices()))
writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -830,7 +852,9 @@ def test_spinnaker_link(params: TA_PARAMS) -> None:
writer.add_edge(ApplicationEdge(in_device, app_vertex), "Test")
writer.add_edge(ApplicationEdge(app_vertex, out_device), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand Down Expand Up @@ -858,7 +882,9 @@ def test_fpga_link(params: TA_PARAMS) -> None:
writer.add_edge(ApplicationEdge(in_device, app_vertex), "Test")
writer.add_edge(ApplicationEdge(app_vertex, out_device), "Test")

writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand All @@ -882,7 +908,9 @@ def test_fpga_link_overlap(params: TA_PARAMS) -> None:

writer.set_machine(virtual_machine_by_cores(
n_cores=writer.get_n_machine_vertices()))
writer.set_placements(place_application_graph(Placements()))
placements = Placements()
writer.set_placements(placements)
place_application_graph(placements)
routing_tables = _route_and_time(algorithm)
_check_edges(routing_tables)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ def make_infos(self, writer: PacmanDataWriter,
if system_placements is None:
system_placements = Placements()
splitter_partitioner()
writer.set_placements(place_application_graph(system_placements))
writer.set_placements(system_placements)
place_application_graph(system_placements)
writer.set_routing_table_by_partition(route_application_graph())
allocator = ZonedRoutingInfoAllocator()
writer.set_routing_infos(allocator.allocate([]))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ def make_infos(self, writer: PacmanDataWriter,
if system_placements is None:
system_placements = Placements()
splitter_partitioner()
writer.set_placements(place_application_graph(system_placements))
writer.set_placements(system_placements)
place_application_graph(system_placements)
writer.set_routing_table_by_partition(route_application_graph())
allocator = ZonedRoutingInfoAllocator()
writer.set_routing_infos(allocator.allocate([]))
Expand Down
Loading