Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/master' into p3_fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian-B committed May 23, 2018
2 parents bfd5533 + 893262d commit 3e3dc98
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 36 deletions.
2 changes: 2 additions & 0 deletions pacman/model/constraints/partitioner_constraints/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from .abstract_partitioner_constraint import AbstractPartitionerConstraint
from .fixed_vertex_atoms_constraint import FixedVertexAtomsConstraint
from .max_vertex_atoms_constraint import MaxVertexAtomsConstraint
from .same_atoms_as_vertex_constraint import SameAtomsAsVertexConstraint

__all__ = ["AbstractPartitionerConstraint",
"FixedVertexAtomsConstraint",
"MaxVertexAtomsConstraint",
"SameAtomsAsVertexConstraint"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# pacman import
from .abstract_partitioner_constraint import AbstractPartitionerConstraint


class FixedVertexAtomsConstraint(AbstractPartitionerConstraint):
""" A constraint which specifies the exact number of atoms on each\
division of a vertex
"""

__slots__ = [
# The exact number of atoms to split the application vertex into
"_size"
]

def __init__(self, size):
"""
:param size: The exact number of atoms to split the vertex into
:type size: int
"""
self._size = size

@property
def size(self):
""" The exact number of atoms to split the vertex into
:rtype: int
"""
return self._size

def __repr__(self):
return "FixedVertexAtomsConstraint(size={})".format(self._size)

def __eq__(self, other):
if not isinstance(other, FixedVertexAtomsConstraint):
return False
return self._size == other.size

def __hash__(self):
return hash((self._size,))
25 changes: 22 additions & 3 deletions pacman/operations/partition_algorithms/basic_partitioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from pacman.exceptions import PacmanPartitionException
from pacman.model.constraints.partitioner_constraints \
import AbstractPartitionerConstraint, MaxVertexAtomsConstraint
import AbstractPartitionerConstraint, MaxVertexAtomsConstraint, \
FixedVertexAtomsConstraint
from pacman.model.graphs.common import GraphMapper, Slice
from pacman.model.graphs.machine import MachineGraph
from pacman.utilities import utility_calls
Expand Down Expand Up @@ -47,7 +48,8 @@ def __call__(self, graph, machine):
ResourceTracker.check_constraints(graph.vertices)
utility_calls.check_algorithm_can_support_constraints(
constrained_vertices=graph.vertices,
supported_constraints=[MaxVertexAtomsConstraint],
supported_constraints=[
MaxVertexAtomsConstraint, FixedVertexAtomsConstraint],
abstract_constraint_type=AbstractPartitionerConstraint)

# start progress bar
Expand Down Expand Up @@ -122,8 +124,25 @@ def _compute_atoms_per_core(self, vertex, res_tracker):
atoms_per_cpu = self._get_ratio(
limits.cpu_cycles.get_value(), requirements.cpu_cycles.get_value())

n_atoms = None
for fa_constraint in utility_calls.locate_constraints_of_type(
vertex.constraints, FixedVertexAtomsConstraint):
if n_atoms is not None and n_atoms != fa_constraint.size:
raise PacmanPartitionException(
"Vertex has multiple contradictory fixed atom constraints"
" - cannot be both {} and {}".format(
n_atoms, fa_constraint.size))
n_atoms = fa_constraint.size

max_atom_values = [atoms_per_sdram, atoms_per_dtcm, atoms_per_cpu]
for max_atom_constraint in utility_calls.locate_constraints_of_type(
vertex.constraints, MaxVertexAtomsConstraint):
max_atom_values.append(float(max_atom_constraint.size))
return min(max_atom_values)
max_atoms = min(max_atom_values)

if n_atoms is not None and max_atoms < n_atoms:
raise PacmanPartitionException(
"Max size of {} is incompatible with fixed size of {}".format(
max_atoms, n_atoms))

return n_atoms if n_atoms is not None else max_atoms
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from pacman.exceptions import PacmanPartitionException, PacmanValueError
from pacman.model.graphs.abstract_virtual_vertex import AbstractVirtualVertex
from pacman.model.constraints.partitioner_constraints \
import AbstractPartitionerConstraint, MaxVertexAtomsConstraint
import AbstractPartitionerConstraint, MaxVertexAtomsConstraint, \
FixedVertexAtomsConstraint
from pacman.model.constraints.partitioner_constraints \
import SameAtomsAsVertexConstraint
from pacman.model.graphs.common import GraphMapper, Slice
Expand Down Expand Up @@ -52,7 +53,8 @@ def __call__(self, graph, machine, preallocated_resources=None):
constrained_vertices=graph.vertices,
abstract_constraint_type=AbstractPartitionerConstraint,
supported_constraints=[MaxVertexAtomsConstraint,
SameAtomsAsVertexConstraint])
SameAtomsAsVertexConstraint,
FixedVertexAtomsConstraint])

# Load the vertices and create the machine_graph to fill
machine_graph = MachineGraph(
Expand Down Expand Up @@ -85,7 +87,7 @@ def __call__(self, graph, machine, preallocated_resources=None):
if machine_vertices is None:
self._partition_vertex(
vertex, machine_graph, graph_mapper, resource_tracker,
graph, progress, vertex_groups)
progress, vertex_groups)
progress.end()

partition_utils.generate_machine_edges(
Expand All @@ -95,7 +97,7 @@ def __call__(self, graph, machine, preallocated_resources=None):

def _partition_vertex(
self, vertex, machine_graph, graph_mapper, resource_tracker,
graph, progress, vertex_groups):
progress, vertex_groups):
""" Partition a single vertex
:param vertex: the vertex to partition
Expand All @@ -110,39 +112,58 @@ def _partition_vertex(
:param resource_tracker: A tracker of assigned resources
:type resource_tracker:\
:py:class:`pacman.utilities.ResourceTracker`
:param graph: the graph object
:type graph:\
:py:class:`pacman.model.graphs.application.ApplicationGraph`
:param progress: The progress bar
:param vertex_groups: Groups together vertices that are supposed to\
be the same size
:rtype: None
:raise pacman.exceptions.PacmanPartitionException: \
if the extra vertex for partitioning identically has a different\
number of atoms than its counterpart.
"""

partition_together_vertices = list(vertex_groups[vertex])

# locate max atoms per core
# locate max atoms per core and fixed atoms per core
possible_max_atoms = list()
if isinstance(vertex, AbstractHasGlobalMaxAtoms):
possible_max_atoms.append(vertex.get_max_atoms_per_core())

n_atoms = None
for other_vertex in partition_together_vertices:
if isinstance(other_vertex, AbstractHasGlobalMaxAtoms):
possible_max_atoms.append(
other_vertex.get_max_atoms_per_core())
max_atom_constraints = utils.locate_constraints_of_type(
other_vertex.constraints,
MaxVertexAtomsConstraint)
other_vertex.constraints, MaxVertexAtomsConstraint)
for constraint in max_atom_constraints:
possible_max_atoms.append(constraint.size)
n_atom_constraints = utils.locate_constraints_of_type(
other_vertex.constraints, FixedVertexAtomsConstraint)
for constraint in n_atom_constraints:
if n_atoms is not None and constraint.size != n_atoms:
raise PacmanPartitionException(
"Vertex has multiple contradictory fixed atom "
"constraints - cannot be both {} and {}".format(
n_atoms, constraint.size))
n_atoms = constraint.size

max_atoms_per_core = int(min(possible_max_atoms))
if n_atoms is not None and max_atoms_per_core < n_atoms:
raise PacmanPartitionException(
"Max size of {} is incompatible with fixed size of {}".format(
max_atoms_per_core, n_atoms))
if n_atoms is not None:
max_atoms_per_core = n_atoms
if vertex.n_atoms % n_atoms != 0:
raise PacmanPartitionException(
"Vertex of {} atoms cannot be divided into units of {}"
.format(vertex.n_atoms, n_atoms))

# partition by atoms
self._partition_by_atoms(
partition_together_vertices, vertex.n_atoms, max_atoms_per_core,
machine_graph, graph, graph_mapper, resource_tracker, progress)
machine_graph, graph_mapper, resource_tracker, progress,
n_atoms is not None)

def _partition_by_atoms(
self, vertices, n_atoms, max_atoms_per_core, machine_graph, graph,
graph_mapper, resource_tracker, progress):
self, vertices, n_atoms, max_atoms_per_core, machine_graph,
graph_mapper, resource_tracker, progress, fixed_n_atoms=False):
""" Try to partition vertices on how many atoms it can fit on\
each vertex
Expand All @@ -160,15 +181,17 @@ def _partition_by_atoms(
:param machine_graph: the machine graph
:type machine_graph:\
:py:class:`pacman.model.graphs.machine.MachineGraph`
:param graph: the application graph
:type graph:\
:py:class:`pacman.model.graphs.application.ApplicationGraph`
:param graph_mapper: the mapper between graphs
:type graph_mapper:\
:py:class:'pacman.model.graphs.common.GraphMapper'
:param resource_tracker: A tracker of assigned resources
:type resource_tracker:\
:py:class:`pacman.utilities.ResourceTracker`
:param progress: The progress bar
:param fixed_n_atoms:\
True if max_atoms_per_core is actually the fixed number of atoms\
per core and cannot be reduced
:type fixed_n_atoms: bool
"""
n_atoms_placed = 0
while n_atoms_placed < n_atoms:
Expand All @@ -180,7 +203,7 @@ def _partition_by_atoms(
# Scale down the number of atoms to fit the available resources
used_placements, hi_atom = self._scale_down_resources(
lo_atom, hi_atom, vertices, resource_tracker,
max_atoms_per_core, graph)
max_atoms_per_core, fixed_n_atoms)

# Update where we are
n_atoms_placed = hi_atom + 1
Expand Down Expand Up @@ -248,7 +271,7 @@ def _reallocate_resources(
# noinspection PyUnusedLocal
def _scale_down_resources(
self, lo_atom, hi_atom, vertices, resource_tracker,
max_atoms_per_core, graph):
max_atoms_per_core, fixed_n_atoms=False):
""" Reduce the number of atoms on a core so that it fits within the
resources available.
Expand All @@ -265,11 +288,12 @@ def _scale_down_resources(
the max atoms from all the vertexes considered that have max_atom\
constraints
:type max_atoms_per_core: int
:param graph: the application graph object
:type graph:\
:py:class:`pacman.model.graphs.application.ApplicationGraph`
:param resource_tracker: Tracker of used resources
:type resource_tracker: spinn_machine.Machine object
:param fixed_n_atoms:\
True if max_atoms_per_core is actually the fixed number of atoms\
per core
:type fixed_n_atoms: bool
:return: the list of placements made by this method and the new amount\
of atoms partitioned
:rtype: tuple of (iterable of tuples, int)
Expand Down Expand Up @@ -301,6 +325,16 @@ def _scale_down_resources(
# Work out the ratio of used to available resources
ratio = self._find_max_ratio(used_resources, resources)

if fixed_n_atoms and ratio > 1.0:
raise PacmanPartitionException(
"No more of vertex '{}' would fit on the board:\n"
" Allocated so far: {} atoms\n"
" Request for SDRAM: {}\n"
" Largest SDRAM space: {}".format(
vertex, lo_atom - 1,
used_resources.sdram.get_value(),
resources.sdram.get_value()))

while ratio > 1.0 and hi_atom >= lo_atom:
# Scale the resources by the ratio
old_n_atoms = (hi_atom - lo_atom) + 1
Expand Down Expand Up @@ -332,7 +366,7 @@ def _scale_down_resources(
# Try to scale up until just below the resource usage
used_resources, hi_atom = self._scale_up_resource_usage(
used_resources, hi_atom, lo_atom, max_atoms_per_core,
vertex, resources, ratio, graph)
vertex, resources, ratio)

# If this hi_atom is smaller than the current minimum, update
# the other placements to use (hopefully) less resources
Expand Down Expand Up @@ -364,7 +398,7 @@ def _scale_down_resources(

def _scale_up_resource_usage(
self, used_resources, hi_atom, lo_atom, max_atoms_per_core, vertex,
resources, ratio, graph):
resources, ratio):
""" Try to push up the number of atoms in a vertex to be as close\
to the available resources as possible
Expand Down Expand Up @@ -450,8 +484,8 @@ def _get_max_atoms_per_core(vertices):

@staticmethod
def _ratio(a, b):
"""Get the ratio between two resource descriptors, with special\
handling for when either descriptor is zero.
""" Get the ratio between two resource descriptors, with special\
handling for when either descriptor is zero.
"""
aval = a.get_value()
bval = b.get_value()
Expand Down
16 changes: 15 additions & 1 deletion unittests/model_tests/test_partition.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import unittest
from pacman.model.graphs.machine import SimpleMachineVertex
from pacman.model.constraints.partitioner_constraints import \
MaxVertexAtomsConstraint, SameAtomsAsVertexConstraint
MaxVertexAtomsConstraint, SameAtomsAsVertexConstraint,\
FixedVertexAtomsConstraint


class TestPartitionConstraints(unittest.TestCase):
Expand All @@ -21,6 +22,19 @@ def test_max_vertex_atoms_constraint(self):
d[c2] = 2
self.assertEqual(len(d), 2)

def test_fixed_vertex_atoms_constraint(self):
c1 = FixedVertexAtomsConstraint(5)
self.assertEqual(c1.size, 5)
self.assertEqual(c1, FixedVertexAtomsConstraint(5))
self.assertEqual(str(c1), 'FixedVertexAtomsConstraint(size=5)')
c2 = FixedVertexAtomsConstraint(7)
self.assertNotEqual(c1, c2)
self.assertNotEqual(c1, "1.2.3.4")
d = {}
d[c1] = 1
d[c2] = 2
self.assertEqual(len(d), 2)

def test_same_atoms_as_vertex_constraint(self):
v1 = SimpleMachineVertex(None, "v1")
v2 = SimpleMachineVertex(None, "v2")
Expand Down

0 comments on commit 3e3dc98

Please sign in to comment.