diff --git a/devlib/__init__.py b/devlib/__init__.py index 19232c7..42509f9 100644 --- a/devlib/__init__.py +++ b/devlib/__init__.py @@ -19,7 +19,7 @@ from devlib.instrument.monsoon import MonsoonInstrument from devlib.instrument.netstats import NetstatsInstrument from devlib.instrument.gem5power import Gem5PowerInstrument -from devlib.derived import DerivedMeasurements +from devlib.derived import DerivedMeasurements, DerivedMetric from devlib.derived.energy import DerivedEnergyMeasurements from devlib.trace.ftrace import FtraceCollector diff --git a/devlib/derived/__init__.py b/devlib/derived/__init__.py index 5689a58..5f7dc6e 100644 --- a/devlib/derived/__init__.py +++ b/devlib/derived/__init__.py @@ -12,6 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. # + +from devlib.instrument import MeasurementType, MEASUREMENT_TYPES + + +class DerivedMetric(object): + + __slots__ = ['name', 'value', 'measurement_type'] + + @property + def units(self): + return self.measurement_type.units + + def __init__(self, name, value, measurement_type): + self.name = name + self.value = value + if isinstance(measurement_type, MeasurementType): + self.measurement_type = measurement_type + else: + try: + self.measurement_type = MEASUREMENT_TYPES[measurement_type] + except KeyError: + msg = 'Unknown measurement type: {}' + raise ValueError(msg.format(measurement_type)) + + def __cmp__(self, other): + if hasattr(other, 'value'): + return cmp(self.value, other.value) + else: + return cmp(self.value, other) + + def __str__(self): + if self.units: + return '{}: {} {}'.format(self.name, self.value, self.units) + else: + return '{}: {}'.format(self.name, self.value) + + __repr__ = __str__ + + class DerivedMeasurements(object): @staticmethod diff --git a/devlib/derived/energy.py b/devlib/derived/energy.py index b3f9c82..84d3d7c 100644 --- a/devlib/derived/energy.py +++ b/devlib/derived/energy.py @@ -15,8 +15,8 @@ from __future__ import division from collections import defaultdict -from devlib import DerivedMeasurements -from devlib.instrument import Measurement, MEASUREMENT_TYPES, InstrumentChannel +from devlib import DerivedMeasurements, DerivedMetric +from devlib.instrument import MEASUREMENT_TYPES, InstrumentChannel class DerivedEnergyMeasurements(DerivedMeasurements): @@ -86,12 +86,12 @@ class DerivedEnergyMeasurements(DerivedMeasurements): derived_measurements = [] for site in energy_results: total_energy = energy_results[site]['end'] - energy_results[site]['start'] - instChannel = InstrumentChannel('cum_energy', site, MEASUREMENT_TYPES['energy']) - derived_measurements.append(Measurement(total_energy, instChannel)) + name = '{}_total_energy'.format(site) + derived_measurements.append(DerivedMetric(name, total_energy, MEASUREMENT_TYPES['energy'])) for site in power_results: power = power_results[site] / (count + 1) #pylint: disable=undefined-loop-variable - instChannel = InstrumentChannel('avg_power', site, MEASUREMENT_TYPES['power']) - derived_measurements.append(Measurement(power, instChannel)) + name = '{}_average_power'.format(site) + derived_measurements.append(DerivedMetric(name, power, MEASUREMENT_TYPES['power'])) return derived_measurements diff --git a/doc/derived_measurements.rst b/doc/derived_measurements.rst index fcd497c..02a6daa 100644 --- a/doc/derived_measurements.rst +++ b/doc/derived_measurements.rst @@ -9,7 +9,7 @@ Example ------- The following example shows how to use an implementation of a -:class:`DerivedMeasurement` to obtain a list of calculated ``Measurements``. +:class:`DerivedMeasurement` to obtain a list of calculated ``DerivedMetric``'s. .. code-block:: ipython @@ -42,9 +42,39 @@ Derived Measurements .. method:: DerivedMeasurements.process(measurement_csv) - Returns a list of :class:`Measurement` objects that have been calculated. + Returns a list of :class:`DerivedMetric` objects that have been calculated. +Derived Metric +~~~~~~~~~~~~~~ + +.. class:: DerivedMetric + + Represents a metric derived from previously collected ``Measurement``s. + Unlike, a ``Measurement``, this was not measured directly from the target. + + +.. attribute:: DerivedMetric.name + + The name of the derived metric. This uniquely defines a metric -- two + ``DerivedMetric`` objects with the same ``name`` represent to instances of + the same metric (e.g. computed from two different inputs). + +.. attribute:: DerivedMetric.value + + The ``numeric`` value of the metric that has been computed for a particular + input. + +.. attribute:: DerivedMetric.measurement_type + + The ``MeasurementType`` of the metric. This indicates which conceptual + category the metric falls into, its units, and conversions to other + measurement types. + +.. attribute:: DerivedMetric.units + + The units in which the metric's value is expressed. + Available Derived Measurements ------------------------------- @@ -63,7 +93,7 @@ Available Derived Measurements .. method:: DerivedEnergyMeasurements.process(measurement_csv) - Returns a list of :class:`Measurement` objects that have been calculated for + Returns a list of :class:`DerivedMetric` objects that have been calculated for the average power and cumulative energy for each site.