lisa.energy_model.EnergyModel#

class lisa.energy_model.EnergyModel(root_node, root_power_domain, freq_domains)[source]#

Bases: Serializable, Loggable

Represents hierarchical CPU topology with power and capacity data

An energy model consists of

  • A CPU topology, representing the physical (cache/interconnect) topology of the CPUs. Each node stores the energy usage of that node’s hardware when it is in each active or idle state. They also store a compute capacity at each frequency, but this is only meaningful for leaf nodes (CPUs) and may be None at higher levels. These capacity values are relative; the maximum capacity would usually be 1024, the value of SCHED_CAPACITY_SCALE in the Linux kernel scheduler. Use EnergyModelNodes to describe this.

  • A power domain topology, representing the hierarchy of areas that can be powered down (idled). The power domains are a single tree. Leaf nodes must contain exactly one CPU and the root node must indirectly contain every CPU. Each power domain has a list (maybe empty) of names of idle states that that domain can enter. Use PowerDomains to describe this.

  • A set of frequency domains, representing groups of CPUs whose clock frequencies must be equal (probably because they share a clock). The frequency domains must be a partition of the CPUs.

Parameters:
  • root_node – Root of EnergyModelNode tree

  • root_power_domain – Root of PowerDomain tree

  • freq_domains – Collection of collections of logical CPU numbers representing frequency (clock) domains.

Note

The most signficant shortcomings of the model are:

  1. Voltage domains are assumed to be congruent to frequency domains

  2. Idle state power is assumed to be independent of voltage

  3. Temperature is ignored entirely

cpu_utils: CPU util distributions

Used throughout this module: A cpu_utils is a list u where u[N] is the sum of the frequency-invariant, capacity-invariant utilization of tasks placed on CPU N. That is, the quantity represented by a CPU runqueue’s util_avg in the Linux kernel scheduler’s load-tracking system with EAS features enabled.

This represents a static utilization, assuming that tasks don’t change in size (for example representing a set of fixed periodic RT-App workloads). For workloads that change over time, a series of cpu_utils items would be needed to describe the utilization, with a distinct estimation for each item in the series.

Warning

Arbitrary code can be executed while loading an instance from a YAML or Pickle file. To include untrusted data in YAML, use the !untrusted tag along with a string

Attributes

capacity_scale

The relative computational capacity of the most powerful CPU at its highest available frequency. Utilisation is in the interval [0, capacity_scale].

cpu_nodes

List of leaf (CPU) EnergyModelNode.

cpus

List of logical CPU numbers in the system.

ATTRIBUTES_SERIALIZATION inherited

Attributes to be treated specially during serialization.

DEFAULT_SERIALIZATION_FMT inherited

Default format used when serializing objects.

YAML_ENCODING inherited

Encoding used for YAML files.

Properties

biggest_cpus

The CPUs with the highest compute capacity at their highest frequency.

cpu_groups

List of lists of CPUs who share the same active state values.

is_heterogeneous

True iff CPUs do not all have the same efficiency and OPP range.

littlest_cpus

The CPUs with the lowest compute capacity at their highest frequency.

node_groups

List of lists of CPUs nodes who share the same active state values.

logger inherited

Convenience short-hand for self.get_logger().

Methods

estimate_from_cpu_util()

Estimate the energy usage of the system under a utilization distribution.

estimate_from_trace()

Estimate the energy consumption of the system by looking at a trace.

from_target()

Create an instance of (a subclass of) :class:EnergyModel by reading a target filesystem.

get_cpu_capacity()

Convenience method to get the capacity of a CPU at a given frequency.

get_optimal_placements()

Find the optimal distribution of work for a set of tasks.

guess_freqs()

Work out CPU frequencies required to execute a workload.

guess_idle_states()

Pessimistically guess the idle states that each CPU may enter.

probe_target()

Check if an EnergyModel can be loaded from the target.

__copy__() inherited

Regular shallow copy operation, without dropping any attributes.

__getstate__() inherited

Filter the instance’s attributes upon serialization.

__setstate__() inherited

from_path() inherited

Deserialize an object from a file.

get_logger() inherited

Provides a logging.Logger named after cls.

log_locals() inherited

Debugging aid: log the local variables of the calling function.

to_path() inherited

Serialize the object to a file.

to_yaml() inherited

Return a YAML string with the serialized object.

Attributes#

EnergyModel.capacity_scale#

The relative computational capacity of the most powerful CPU at its highest available frequency. Utilisation is in the interval [0, capacity_scale].

EnergyModel.cpu_nodes#

List of leaf (CPU) EnergyModelNode

EnergyModel.cpus#

List of logical CPU numbers in the system

EnergyModel.ATTRIBUTES_SERIALIZATION = {'allowed': [], 'ignored': [], 'placeholders': {}}#

Inherited attribute, see lisa.utils.Serializable.ATTRIBUTES_SERIALIZATION

Attributes to be treated specially during serialization.

EnergyModel.DEFAULT_SERIALIZATION_FMT = 'yaml'#

Inherited attribute, see lisa.utils.Serializable.DEFAULT_SERIALIZATION_FMT

Default format used when serializing objects.

EnergyModel.YAML_ENCODING = 'utf-8'#

Inherited attribute, see lisa.utils.Serializable.YAML_ENCODING

Encoding used for YAML files.

Properties#

property EnergyModel.biggest_cpus[source]#

The CPUs with the highest compute capacity at their highest frequency

property EnergyModel.cpu_groups[source]#

List of lists of CPUs who share the same active state values

property EnergyModel.is_heterogeneous[source]#

True iff CPUs do not all have the same efficiency and OPP range

property EnergyModel.littlest_cpus[source]#

The CPUs with the lowest compute capacity at their highest frequency

property EnergyModel.node_groups[source]#

List of lists of CPUs nodes who share the same active state values

property EnergyModel.logger#

Inherited property, see lisa.utils.Loggable.logger

Convenience short-hand for self.get_logger().

Methods#

EnergyModel.estimate_from_cpu_util(cpu_utils, freqs=None, idle_states=None)[source]#

Estimate the energy usage of the system under a utilization distribution

Optionally also take freqs; a list of frequencies at which each CPU is assumed to run, and idle_states, the idle states that each CPU can enter between activations. If not provided, they will be estimated assuming an ideal selection system (i.e. perfect cpufreq & cpuidle governors).

Parameters:
  • cpu_utils – Utilization distribution, see cpu_utils

  • freqs – List of CPU frequencies. Got from guess_freqs() by default.

  • idle_states – List of CPU frequencies. Got from guess_idle_states() by default.

Returns:

Dict with power in bogo-Watts (bW), with contributions from each system component keyed with a tuple of the CPUs comprising that component (i.e. :attr:EnergyModelNode.cpus)

{
    (0,)    : 10,
    (1,)    : 10,
    (0, 1)  : 5,
}

This represents CPUs 0 and 1 each using 10bW and their shared resources using 5bW for a total of 25bW.

EnergyModel.estimate_from_trace(trace)[source]#

Estimate the energy consumption of the system by looking at a trace

It uses the EAS energy model data, and the idle and DVFS conditions reported in the trace, to estimate the energy usage of the system at every given moment.

Takes into account knowledge of power domains - where cpuidle makes impossible claims about idle states (e.g. a CPU in ‘cluster sleep’ while its cluster siblings are running), the states will be minimised.

The accuracy of this is otherwise totally dependent on the accuracy of the EAS energy model and the kernel’s information. This does not take into account cost of idle state of DVFS transitions, nor any other conditions that are invisible to the kernel. The effect any power decisions that the platform makes independently of the kernel cannot be seen in this data. Examples of this _might_ include firmware thermal management invisibly restricting CPU frequencies, or secure-world software with real-time constraints preventing deep CPU idle states.

Parameters:

trace (lisa.trace.Trace) – The trace

Returns:

A DataFrame with a column for each node in the energy model, labelled with the CPU members of the node joined by ‘-‘s. Shows the energy use by each node at each given moment. If you don’t care about those details, call .sum(axis=1) on the returned DataFrame to get a Series that shows overall estimated power usage over time.

Required trace events:
  • cpu_frequency or userspace@cpu_frequency_devlib

  • cpu_idle

classmethod EnergyModel.from_target(target)[source]#

Create an instance of (a subclass of) :class:EnergyModel by reading a target filesystem.

Parameters:

target (devlib.target.Target) – Target object to read filesystem from.

Returns:

A instance of a subclass of EnergyModel.

EnergyModel.get_cpu_capacity(cpu, freq=None)[source]#

Convenience method to get the capacity of a CPU at a given frequency

Parameters:
  • cpu – CPU to get capacity for

  • freq – Frequency to get the CPU capacity at. Default is max capacity.

EnergyModel.get_optimal_placements(capacities, capacity_margin_pct=0)[source]#

Find the optimal distribution of work for a set of tasks

Find a list of candidates which are estimated to be optimal in terms of power consumption, but that do not result in any CPU becoming over-utilized.

If no such candidates exist, i.e. the system being modeled cannot satisfy the workload’s throughput requirements, an EnergyModelCapacityError is raised. For example, if e was an EnergyModel modeling two CPUs with capacity 1024, this error would be raised by:

e.get_optimal_placements({"t1": 800, "t2": 800, "t3: "800"})

This estimation assumes an ideal system of selecting OPPs and idle states for CPUs.

Note

This is a brute force search taking time exponential wrt. the number of tasks.

Parameters:
  • capacities – Dict mapping tasks to expected utilization values. These tasks are assumed not to change; they have a single static utilization value. A set of single-phase periodic RT-App tasks is an example of a suitable workload for this model.

  • capacity_margin_pct – Capacity margin before overutilizing a CPU

Returns:

List of cpu_utils items representing distributions of work under optimal task placements, see cpu_utils. Multiple task placements that result in the same CPU utilizations are considered equivalent.

EnergyModel.guess_freqs(cpu_utils, capacity_margin_pct=0)[source]#

Work out CPU frequencies required to execute a workload

Find the lowest possible frequency for each CPU that provides enough capacity to satisfy the utilization, taking into account frequency domains.

Parameters:
  • cpu_utils – Utilization distribution, see cpu_utils

  • capacity_margin_pct – Capacity margin before overutilizing a CPU

Returns:

List ret where ret[N] is the frequency that CPU N must run at

EnergyModel.guess_idle_states(cpus_active)[source]#

Pessimistically guess the idle states that each CPU may enter

If a CPU has any tasks it is estimated that it may only enter its shallowest idle state in between task activations. If all the CPUs within a power domain have no tasks, they will all be judged able to enter that domain’s deepest idle state. If any CPU in a domain has work, no CPUs in that domain are assumed to enter any domain shared state.

e.g. Consider a system with

  • two power domains PD0 and PD1

  • 4 CPUs, with CPUs [0, 1] in PD0 and CPUs [2, 3] in PD1

  • 4 idle states: “WFI”, “cpu-sleep”, “cluster-sleep-0” and “cluster-sleep-1”, where the “cluster-sleep-*” states domain states, i.e. a CPU can only enter those states when both CPUs in the domain are idle.

Then here are some example inputs and outputs:

# All CPUs idle:
[0, 0, 0, 0] -> ["cluster-sleep-1", "cluster-sleep-1",
                 "cluster-sleep-1", "cluster-sleep-1"]

# All CPUs have work
[1, 1, 1, 1] -> ["WFI","WFI","WFI", "WFI"]

# One power domain active, the other idle
[0, 0, 1, 1] -> ["cluster-sleep-1", "cluster-sleep-1", "WFI","WFI"]

# One CPU active.
# Note that CPU 2 has no work but is assumed to never be able to enter
# any "cluster" state.
[0, 0, 0, 1] -> ["cluster-sleep-1", "cluster-sleep-1",
                 "cpu-sleep","WFI"]
Parameters:

cpus_active – list where bool(cpus_active[N]) is False iff no tasks will run on CPU N.

Returns:

List ret where ret[N] is the name of the estimated idle state that CPU N can enter during idle periods.

classmethod EnergyModel.probe_target(target)[source]#

Check if an EnergyModel can be loaded from the target.

Parameters:

target (devlib.target.Target) – Target to look at.

EnergyModel.__copy__()#

Inherited method, see lisa.utils.Serializable.__copy__()

Regular shallow copy operation, without dropping any attributes.

EnergyModel.__getstate__()#

Inherited method, see lisa.utils.Serializable.__getstate__()

Filter the instance’s attributes upon serialization.

EnergyModel.__setstate__(dct)#

Inherited method, see lisa.utils.Serializable.__setstate__()

classmethod EnergyModel.from_path(filepath, fmt=None)#

Inherited method, see lisa.utils.Serializable.from_path()

Deserialize an object from a file.

classmethod EnergyModel.get_logger(suffix=None)#

Inherited method, see lisa.utils.Loggable.get_logger()

Provides a logging.Logger named after cls.

classmethod EnergyModel.log_locals(var_names=None, level='debug')#

Inherited method, see lisa.utils.Loggable.log_locals()

Debugging aid: log the local variables of the calling function.

EnergyModel.to_path(filepath, fmt=None)#

Inherited method, see lisa.utils.Serializable.to_path()

Serialize the object to a file.

EnergyModel.to_yaml()#

Inherited method, see lisa.utils.Serializable.to_yaml()

Return a YAML string with the serialized object.

static EnergyModel.from_debugfsEM_target(*args, **kwargs)[source]#

See LinuxEnergyModel.from_target()

Deprecated since version 2.0.

from_debugfsEM_target() is deprecated and will be removed in version 4.0, use lisa.energy_model.LinuxEnergyModel.from_target instead

static EnergyModel.from_sd_target(*args, **kwargs)[source]#

See LegacyEnergyModel.from_target()

Deprecated since version 2.0.

from_sd_target() is deprecated and will be removed in version 4.0, use lisa.energy_model.LegacyEnergyModel.from_target instead