Source code for mendevi.models.power_cores
"""Power prediction based on CPU utilisation rate."""
import logging
import math
import numpy as np
from context_verbose import Printer
from mendevi.models import Model
MIN_POINTS = 2 # minimal number of points
[docs]
class PowerCores(Model):
r"""Affine model to predict the power from the core utilisation.
.. math:
P(c) = P_{static} + c \times P_{core}
With :math:`P_{static}` and :math:`P_{core}`
two hyperparameters specific to each machine,
but independent of the programme being executed.
Examples
--------
>>> from mendevi.models.power_cores import PowerCores
>>> model = PowerCores().fit("<multithread.db>")
>>> model.predict(["paradoxe-32.rennes.grid5000.fr"], [0.0])
{'power': [247.53499079469898]}
>>>
"""
def __init__(self) -> None:
"""Initialise the model."""
super().__init__(
"Power estimation based on the utilisation rate of logic cores",
sources="""
F. C. Heinrich, T. Cornebize, A. Degomme, A. Legrand, A. Carpen-
Amarie, S. Hunold, A.-C. Orgerie, and M. Quinson, “Predicting the
Energy Consumption of MPI Applications at Scale Using a Single
Node,” in IEEE Cluster Conference, 2017.
R. Rodriguez-Sánchez, F. D. Igual, J. L. Martinez, R. Mayo, and E. S.
Quintana-Orti, “Parallel performance and energy efficiency of modern
video encoders on multithreaded architectures,” in Eur
""",
input_labels=["hostname", "cores"],
output_labels=["power"],
parameters={}, # to each hostname, associate P_{static} and P_{core}
)
def _fit(self, values: dict[str]) -> None:
"""Perform a linear regression for the 2 constants P_{static} and P_{core}."""
for hostname in set(values["hostname"]):
with Printer(f"Affine regression of power = f(cores) on {hostname}...") as prt:
mask = [i for i, h in enumerate(values["hostname"]) if h == hostname]
prt.print(f"fit on {len(mask)} points")
if len(mask) < MIN_POINTS:
logging.getLogger(__name__).error(
"can not fit model for hostname=%s, not enouth points", hostname,
)
continue
cores = [values["cores"][i] for i in mask]
power = [values["power"][i] for i in mask]
p_cores, p_static = np.polyfit(cores, power, deg=1)
prt.print(f"power = {p_static:.3g} + cores * {p_cores:.3g}")
self.parameters[hostname] = {"p_static": float(p_static), "p_cores": float(p_cores)}
def _predict(self, values: dict[str]) -> dict[str]:
all_power = []
for hostname, cores in zip(values["hostname"], values["cores"], strict=True):
if hostname not in self.parameters:
logging.getLogger(__name__).error(
"fit the model for the hostname %s before to predict", hostname,
)
all_power.append(math.nan)
else:
all_power.append(
self.parameters[hostname]["p_static"]
+ cores * self.parameters[hostname]["p_cores"],
)
return {"power": all_power}