Source code for spinn_front_end_common.utilities.utility_objs.power_used

# Copyright (c) 2017 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 collections import defaultdict
from typing import Dict, Iterable, Tuple


class PowerUsed(object):
    """
    Describes the power used by a simulation.
    """

    __slots__ = (
        "__num_chips", "__num_cores", "__num_fpgas", "__num_frames",
        "__exec_time", "__mapping_time", "__data_gen_time", "__loading_time",
        "__saving_time",
        "__chip_energy", "__fpga_total_energy", "__fpga_exec_energy",
        "__baseline_energy", "__packet_energy", "__mapping_energy",
        "__data_gen_energy", "__loading_energy", "__saving_energy",
        "__core_energy", "__router_energy")

    def __init__(self) -> None:
        self.__num_chips = 0
        self.__num_cores = 0
        self.__num_fpgas = 0
        self.__num_frames = 0
        self.__exec_time = 0.0
        self.__mapping_time = 0.0
        self.__data_gen_time = 0.0
        self.__loading_time = 0.0
        self.__saving_time = 0.0
        self.__chip_energy = 0.0
        self.__fpga_total_energy = 0.0
        self.__fpga_exec_energy = 0.0
        self.__baseline_energy = 0.0
        self.__packet_energy = 0.0
        self.__mapping_energy = 0.0
        self.__data_gen_energy = 0.0
        self.__loading_energy = 0.0
        self.__saving_energy = 0.0
        self.__core_energy: Dict[
            Tuple[int, int, int], float] = defaultdict(float)
        self.__router_energy: Dict[Tuple[int, int], float] = defaultdict(float)

    @property
    def num_chips(self) -> int:
        """
        The total number of chips used.

        :rtype: int
        """
        return self.__num_chips

    @num_chips.setter
    def num_chips(self, value: int):
        self.__num_chips = int(value)

    @property
    def num_cores(self) -> int:
        """
        The total number of cores used, including for SCAMP.

        :rtype: int
        """
        return self.__num_cores

    @num_cores.setter
    def num_cores(self, value: int):
        self.__num_cores = int(value)

    @property
    def num_fpgas(self) -> int:
        """
        The total number of FPGAs used.

        :rtype: int
        """
        return self.__num_fpgas

    @num_fpgas.setter
    def num_fpgas(self, value: int):
        self.__num_fpgas = int(value)

    @property
    def num_frames(self) -> int:
        """
        The total number of frames used.

        :rtype: int
        """
        return self.__num_frames

    @num_frames.setter
    def num_frames(self, value: int):
        self.__num_frames = int(value)

    @property
    def total_time_secs(self) -> float:
        """
        Time taken in total, in seconds.

        :rtype: float
        """
        return self.exec_time_secs + self.loading_time_secs + \
            self.saving_time_secs + self.data_gen_time_secs + \
            self.mapping_time_secs

    @property
    def booted_time_secs(self) -> float:
        """
        Time taken when the machine is booted, in seconds.

        :rtype: float
        """
        return self.exec_time_secs + self.loading_time_secs + \
            self.saving_time_secs

    @property
    def exec_time_secs(self) -> float:
        """
        Time taken by active simulation running, in seconds.

        :rtype: float
        """
        return self.__exec_time

    @exec_time_secs.setter
    def exec_time_secs(self, value: float):
        self.__exec_time = float(value)

    @property
    def mapping_time_secs(self) -> float:
        """
        Time taken by the mapping phase, in seconds.

        :rtype: float
        """
        return self.__mapping_time

    @mapping_time_secs.setter
    def mapping_time_secs(self, value: float):
        self.__mapping_time = float(value)

    @property
    def data_gen_time_secs(self) -> float:
        """
        Time taken by data generation phase, in seconds.

        :rtype: float
        """
        return self.__data_gen_time

    @data_gen_time_secs.setter
    def data_gen_time_secs(self, value: float):
        self.__data_gen_time = float(value)

    @property
    def loading_time_secs(self) -> float:
        """
        Time taken by data loading, in seconds.

        :rtype: float
        """
        return self.__loading_time

    @loading_time_secs.setter
    def loading_time_secs(self, value: float):
        self.__loading_time = float(value)

    @property
    def saving_time_secs(self) -> float:
        """
        Time taken by data extraction, in seconds.

        :rtype: float
        """
        return self.__saving_time

    @saving_time_secs.setter
    def saving_time_secs(self, value: float):
        self.__saving_time = float(value)

    @property
    def total_energy_joules(self) -> float:
        """
        Total of all energy costs, in Joules.

        :rtype: float
        """
        baseline_energy = self.baseline_joules + self.fpga_total_energy_joules
        idle_energy = self.mapping_joules + self.data_gen_joules
        active_energy = self.chip_energy_joules + self.packet_joules + \
            self.loading_joules + self.saving_joules
        return baseline_energy + idle_energy + active_energy

    @property
    def chip_energy_joules(self) -> float:
        """
        Energy used by all SpiNNaker chips during active simulation
        running, in Joules.

        :rtype: float
        """
        return self.__chip_energy

    @chip_energy_joules.setter
    def chip_energy_joules(self, value: float):
        self.__chip_energy = float(value)

    @property
    def fpga_total_energy_joules(self) -> float:
        """
        Energy used by all FPGAs in total, in Joules.

        :rtype: float
        """
        return self.__fpga_total_energy

    @fpga_total_energy_joules.setter
    def fpga_total_energy_joules(self, value: float):
        self.__fpga_total_energy = float(value)

    @property
    def fpga_exec_energy_joules(self) -> float:
        """
        Energy used by all FPGAs during active simulation running, in
        Joules. This is *included* in the total FPGA energy.

        :rtype: float
        """
        return self.__fpga_exec_energy

    @fpga_exec_energy_joules.setter
    def fpga_exec_energy_joules(self, value: float):
        self.__fpga_exec_energy = float(value)

    @property
    def baseline_joules(self) -> float:
        """
        Baseline/idle energy used, in Joules. This is used by things like the
        frames the SpiNNaker boards are held in, the cooling system, etc.

        :rtype: float
        """
        return self.__baseline_energy

    @baseline_joules.setter
    def baseline_joules(self, value: float):
        self.__baseline_energy = float(value)

    @property
    def packet_joules(self) -> float:
        """
        Energy used by packet transmission, in Joules.

        :rtype: float
        """
        return self.__packet_energy

    @packet_joules.setter
    def packet_joules(self, value: float):
        self.__packet_energy = float(value)

    @property
    def mapping_joules(self) -> float:
        """
        Energy used during the mapping phase, in Joules. Assumes that
        the SpiNNaker system has been shut down.

        :rtype: float
        """
        return self.__mapping_energy

    @mapping_joules.setter
    def mapping_joules(self, value: float):
        self.__mapping_energy = float(value)

    @property
    def data_gen_joules(self) -> float:
        """
        Energy used during the data generation phase, in Joules. Assumes
        that the SpiNNaker system has been shut down.

        :rtype: float
        """
        return self.__data_gen_energy

    @data_gen_joules.setter
    def data_gen_joules(self, value: float):
        self.__data_gen_energy = float(value)

    @property
    def loading_joules(self) -> float:
        """
        Energy used during data loading, in Joules.

        :rtype: float
        """
        return self.__loading_energy

    @loading_joules.setter
    def loading_joules(self, value: float):
        self.__loading_energy = float(value)

    @property
    def saving_joules(self) -> float:
        """
        Energy used during data extraction, in Joules.

        :rtype: float
        """
        return self.__saving_energy

    @saving_joules.setter
    def saving_joules(self, value: float):
        self.__saving_energy = float(value)

[docs] def get_router_active_energy_joules(self, x: int, y: int) -> float: """ Energy used (above idle baseline) by a particular router, in Joules. Unused routers always report 0.0 for this. :param int x: :param int y: :rtype: float """ return self.__router_energy.get((x, y), 0.0)
[docs] def add_router_active_energy(self, x: int, y: int, joules: float): """ Adds energy for a particular router. It can be called multiple times per router. Only intended to be used during construction of this object. :param int x: :param int y: :param float joules: the energy to add for this router, in Joules. """ self.__router_energy[x, y] += float(joules)
@property def active_routers(self) -> Iterable[Tuple[int, int]]: """ Enumeration of the coordinates of the routers that can report active energy usage. :rtype: iterable(tuple(int, int)) """ return self.__router_energy.keys()
[docs] def get_core_active_energy_joules(self, x: int, y: int, p: int) -> float: """ Energy used (above idle baseline) by a particular core, in Joules. Unused cores always report 0.0 for this. :param int x: :param int y: :param int p: :rtype: float """ return self.__core_energy.get((x, y, p), 0.0)
[docs] def add_core_active_energy(self, x: int, y: int, p: int, joules: float): """ Adds energy for a particular core. It can be called multiple times per core. Only intended to be used during construction of this object. :param int x: :param int y: :param int p: :param float joules: the energy to add for this core, in Joules. """ self.__core_energy[x, y, p] += float(joules)
@property def active_cores(self) -> Iterable[Tuple[int, int, int]]: """ Enumeration of the coordinates of the cores that can report active energy usage. :rtype: iterable(tuple(int, int, int)) """ return self.__core_energy.keys()