Source code for pacman.utilities.algorithm_utilities.element_allocator_algorithm
from six import add_metaclass
import math
from pacman.model.resources import ElementFreeSpace
from pacman.exceptions import PacmanElementAllocationException
from spinn_utilities.abstract_base import AbstractBase
[docs]@add_metaclass(AbstractBase)
class ElementAllocatorAlgorithm(object):
""" Abstract element allocator algorithm which allocates elements from\
a pool of a given size
"""
__slots__ = [
# the space object for memory allocation
"_free_space_tracker"
]
def __init__(self, size_begin, size_end):
self._free_space_tracker = list()
self._free_space_tracker.append(ElementFreeSpace(size_begin, size_end))
def _allocate_elements(self, base_element_id, n_elements):
""" Handle the allocating of space for a given set of elements
:param base_element_id: the first element id to allocate
:param n_elements: the number of elements to allocate
:raises: PacmanRouteInfoAllocationException when the element id\
cannot be assigned with the given number of elements
"""
index = self._find_slot(base_element_id)
if index is None:
raise PacmanElementAllocationException(
"Space for {} elements starting at {} has already "
"been allocated".format(n_elements, base_element_id))
# base element should be >= slot element at this point
self._do_allocation(index, base_element_id, n_elements)
def _find_slot(self, base_element_id, lo=0):
""" Find the free slot with the closest\
base element id <= base element using a binary search
"""
hi = len(self._free_space_tracker) - 1
while lo < hi:
mid = int(math.ceil(float(lo + hi) / 2.0))
free_space_slot = self._free_space_tracker[mid]
if free_space_slot.start_address > base_element_id:
hi = mid - 1
else:
lo = mid
# If we have gone off the end of the array, we haven't found a slot
if (lo >= len(self._free_space_tracker) or hi < 0 or
self._free_space_tracker[lo].start_address > base_element_id):
return None
return lo
def _do_allocation(self, index, base_element_id, n_elements):
""" Allocate a given base element id and number of elements into the\
space at the given slot
:param index: The index of the free space slot to check
:param base_element_id: The element id to start with - must be\
inside the slot
:param n_elements: The number of elements to be allocated -\
should be power of 2
"""
free_space_slot = self._free_space_tracker[index]
if free_space_slot.start_address > base_element_id:
raise PacmanElementAllocationException(
"Trying to allocate a element in the wrong slot!")
# Check if there is enough space to allocate
space = self._check_allocation(index, base_element_id, n_elements)
if space is None:
raise PacmanElementAllocationException(
"Not enough space to allocate {} elements starting at {}"
.format(n_elements, hex(base_element_id)))
if (free_space_slot.start_address == base_element_id and
free_space_slot.size == n_elements):
# If the slot exactly matches the space, remove it
del self._free_space_tracker[index]
elif free_space_slot.start_address == base_element_id:
# If the slot starts with the element id, reduce the size
self._free_space_tracker[index] = ElementFreeSpace(
free_space_slot.start_address + n_elements,
free_space_slot.size - n_elements)
elif space == n_elements:
# If the space at the end exactly matches the spot, reduce the size
self._free_space_tracker[index] = ElementFreeSpace(
free_space_slot.start_address,
free_space_slot.size - n_elements)
else:
# Otherwise, the allocation lies in the middle of the region:
# First, reduce the size of the space before the allocation
self._free_space_tracker[index] = ElementFreeSpace(
free_space_slot.start_address,
base_element_id - free_space_slot.start_address)
# Then add a new space after the allocation
self._free_space_tracker.insert(index + 1, ElementFreeSpace(
base_element_id + n_elements,
free_space_slot.start_address + free_space_slot.size -
(base_element_id + n_elements)))
def _check_allocation(self, index, base_element_id, n_elements):
""" Check if there is enough space for a given set of element ids
starting at a base element id inside a given slot
:param index: The index of the free space slot to check
:param base_element_id: The element id to start with -\
must be inside the slot
:param n_elements: The number of elements to be allocated -\
should be power of 2
"""
free_space_slot = self._free_space_tracker[index]
space = (free_space_slot.size -
(base_element_id - free_space_slot.start_address))
if free_space_slot.start_address > base_element_id:
raise PacmanElementAllocationException(
"Trying to allocate a element id in the wrong slot!")
# Check if there is enough space for the elements
if space < n_elements:
return None
return space