Source code for spinn_front_end_common.interface.interface_functions.spalloc_allocator
# Copyright (c) 2017-2019 The University of Manchester
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import math
import six
import sys
from spinn_utilities.overrides import overrides
from spalloc import Job
from spalloc.states import JobState
from spinn_front_end_common.abstract_models import (
AbstractMachineAllocationController)
from spinn_front_end_common.abstract_models.impl import (
MachineAllocationController)
class _SpallocJobController(MachineAllocationController):
__slots__ = [
# the spalloc job object
"_job",
# the current job's old state
"_state"
]
def __init__(self, job):
if job is None:
raise Exception("must have a real job")
self._job = job
self._state = job.state
super(_SpallocJobController, self).__init__("SpallocJobController")
@overrides(AbstractMachineAllocationController.extend_allocation)
def extend_allocation(self, new_total_run_time):
# Does Nothing in this allocator - machines are held until exit
pass
@overrides(AbstractMachineAllocationController.close)
def close(self):
super(_SpallocJobController, self).close()
self._job.destroy()
@property
def power(self):
return self._job.power
def set_power(self, power):
self._job.set_power(power)
if power:
self._job.wait_until_ready()
def where_is_machine(self, chip_x, chip_y):
return self._job.where_is_machine(chip_y=chip_y, chip_x=chip_x)
@overrides(MachineAllocationController._wait)
def _wait(self):
try:
if self._state != JobState.destroyed:
self._state = self._job.wait_for_state_change(self._state)
except TypeError:
pass
except Exception: # pylint: disable=broad-except
if not self._exited:
six.reraise(*sys.exc_info())
return self._state != JobState.destroyed
@overrides(MachineAllocationController._teardown)
def _teardown(self):
if not self._exited:
self._job.close()
super(_SpallocJobController, self)._teardown()
[docs]class SpallocAllocator(object):
""" Request a machine from a SPALLOC server that will fit the given\
number of chips
"""
# Use a worst case calculation
_N_CHIPS_PER_BOARD = 48.0
_MACHINE_VERSION = 5
def __call__(
self, spalloc_server, spalloc_user, n_chips=None, n_boards=None,
spalloc_port=None, spalloc_machine=None):
"""
:param spalloc_server: \
The server from which the machine should be requested
:param spalloc_port: The port of the SPALLOC server
:param spalloc_user: The user to allocate the machine to
:param n_chips: The number of chips required.
IGNORED if n_boards is not None
:param n_boards: The number of boards required
:param spalloc_port: The optional port number to speak to spalloc
:param spalloc_machine: The optional spalloc machine to use
"""
# pylint: disable=too-many-arguments
# Work out how many boards are needed
if n_boards is None:
n_boards = float(n_chips) / self._N_CHIPS_PER_BOARD
# If the number of boards rounded up is less than 10% of a board
# bigger than the actual number of boards,
# add another board just in case.
if math.ceil(n_boards) - n_boards < 0.1:
n_boards += 1
n_boards = int(math.ceil(n_boards))
spalloc_kw_args = {
'hostname': spalloc_server,
'owner': spalloc_user
}
if spalloc_port is not None:
spalloc_kw_args['port'] = spalloc_port
if spalloc_machine is not None:
spalloc_kw_args['machine'] = spalloc_machine
job, hostname = self._launch_job(n_boards, spalloc_kw_args)
machine_allocation_controller = _SpallocJobController(job)
return (
hostname, self._MACHINE_VERSION, None, False,
False, None, None, machine_allocation_controller
)
def _launch_job(self, n_boards, spalloc_kw_args):
job = Job(n_boards, **spalloc_kw_args)
try:
job.wait_until_ready()
# get param from jobs before starting, so that hanging doesn't
# occur
return job, job.hostname
except Exception:
job.destroy()
raise