Source code for spinn_machine.data.machine_data_view
# Copyright (c) 2021 The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from spinn_utilities.data import UtilsDataView
# pylint: disable=protected-access
class _MachineDataModel(object):
"""
Singleton data model.
This class should not be accessed directly please use the DataView and
DataWriter classes.
Accessing or editing the data held here directly is NOT SUPPORTED
There may be other DataModel classes which sit next to this one and hold
additional data. The DataView and DataWriter classes will combine these
as needed.
What data is held where and how can change without notice.
"""
__singleton = None
__slots__ = [
# Data values cached
"_machine",
"_machine_generator",
"_user_accessed_machine"
]
def __new__(cls):
if cls.__singleton:
return cls.__singleton
# pylint: disable=protected-access
obj = object.__new__(cls)
cls.__singleton = obj
obj._clear()
return obj
def _clear(self):
"""
Clears out all data
"""
self._hard_reset()
self._machine_generator = None
def _hard_reset(self):
"""
Clears out all data that should change after a reset and graph change
This does NOT clear the machine as it may have been asked for before
"""
self._soft_reset()
self._machine = None
self._user_accessed_machine = False
def _soft_reset(self):
"""
Clears timing and other data that should changed every reset
"""
# Holder for any later additions
[docs]class MachineDataView(UtilsDataView):
"""
Adds the extra Methods to the View for Machine level.
See :py:class:`~spinn_utilities.data.UtilsDataView` for a more detailed
description.
This class is designed to only be used directly within the SpiNNMachine
repository as all methods are available to subclasses
"""
__data = _MachineDataModel()
__slots__ = []
# machine methods
[docs] @classmethod
def has_machine(cls):
"""
Reports if a machine is currently set or can be mocked.
:rtype: bool
"""
return (cls.__data._machine is not None or
cls._is_mocked())
[docs] @classmethod
def get_machine(cls):
"""
Returns the Machine if it has been set.
In Mock mode will create and return a virtual 8 * 8 board
:raises ~spinn_utilities.exceptions.SpiNNUtilsException:
If the machine is currently unavailable
:rtype: ~spinn_machine.Machine
"""
if cls.is_user_mode():
if cls.is_soft_reset():
cls.__data._machine = None
cls.__data._user_accessed_machine = True
if cls.__data._machine is None:
if cls.__data._machine_generator:
# pylint: disable=not-callable
cls.__data._machine_generator()
return cls.__data._machine
raise cls._exception("machine")
return cls.__data._machine
[docs] @classmethod
def get_chip_at(cls, x, y):
"""
Gets the chip at x and y.
Almost Semantic sugar for `get_machine().get_chip_at()`
The method however does not return `None` but rather raises a KeyError
if the chip is not known
:param int x:
:param int y:
:rtype: Chip
:raises ~spinn_utilities.exceptions.SpiNNUtilsException:
If the machine is currently unavailable
:raises KeyError: If the chip does not exist but the machine does
"""
return cls.get_machine()._chips[(x, y)]
[docs] @classmethod
def get_nearest_ethernet(cls, x, y):
"""
Gets the nearest ethernet x and y for the chip at x, y if it exists.
If there is no machine or no chip at (x, y) this method,
or any other issue will just return x,y
.. note::
This method will never request a new machine.
Therefore a call to this method will not trigger a hard reset
:param int x:
:param int y:
:return: Chip(x,y)'s nearest_ethernet info
or if that is not available just x, and y
:rtype: tuple(int, int)
"""
try:
chip = cls.__data._machine._chips[(x, y)]
return chip.nearest_ethernet_x, chip.nearest_ethernet_y
except Exception: # pylint: disable=broad-except
if cls.__data._machine is None:
return x, y
return x, y
[docs] @classmethod
def where_is_xy(cls, x, y):
"""
Gets a string saying where chip at x and y is if possible.
Almost Semantic sugar for `get_machine().where_is_xy()`
The method does not raise an exception rather returns a String of the
exception
.. note::
This method will never request a new machine.
Therefore a call to this method will not trigger a hard reset
:param int x:
:param int y:
:rtype: str
"""
try:
return cls.__data._machine.where_is_xy(x, y)
except Exception as ex: # pylint: disable=broad-except
if cls.__data._machine is None:
return "No Machine created yet"
return str(ex)
[docs] @classmethod
def where_is_chip(cls, chip):
"""
Gets a string saying where chip is if possible.
Almost Semantic sugar for `get_machine().where_is_chip()`
The method does not raise an exception rather returns a String of the
exception
.. note::
This method will never request a new machine.
Therefore a call to this method will not trigger a hard reset
:param int x:
:param int y:
:rtype: str
"""
try:
return cls.__data._machine.where_is_chip(chip)
except Exception as ex: # pylint: disable=broad-except
if cls.__data._machine is None:
return "Chip is from a previous machine"
return str(ex)