mirror of
https://github.com/ARM-software/devlib.git
synced 2025-02-07 13:40:48 +00:00
DerivedMeasurements: Add DerivedEnergyMeasurments
Adds `DerivedMeasurements` which are designed to perform post processing on a provided MeasurementCsv. Currently only a `DerivedEnergyMeasurements` class has been added which has 2 purposes: - Calculate energy from power results if not present using recorded timestamps, falling back to a provided sample rate - Calculate cumulative energy and average power from a specified MeasurementCSV file.
This commit is contained in:
parent
049b275665
commit
c093d56754
@ -19,6 +19,9 @@ from devlib.instrument.monsoon import MonsoonInstrument
|
|||||||
from devlib.instrument.netstats import NetstatsInstrument
|
from devlib.instrument.netstats import NetstatsInstrument
|
||||||
from devlib.instrument.gem5power import Gem5PowerInstrument
|
from devlib.instrument.gem5power import Gem5PowerInstrument
|
||||||
|
|
||||||
|
from devlib.derived import DerivedMeasurements
|
||||||
|
from devlib.derived.derived_measurements import DerivedEnergyMeasurements
|
||||||
|
|
||||||
from devlib.trace.ftrace import FtraceCollector
|
from devlib.trace.ftrace import FtraceCollector
|
||||||
|
|
||||||
from devlib.host import LocalConnection
|
from devlib.host import LocalConnection
|
||||||
|
19
devlib/derived/__init__.py
Normal file
19
devlib/derived/__init__.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Copyright 2015 ARM Limited
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# http://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.
|
||||||
|
#
|
||||||
|
class DerivedMeasurements(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process(measurements_csv):
|
||||||
|
raise NotImplementedError()
|
97
devlib/derived/derived_measurements.py
Normal file
97
devlib/derived/derived_measurements.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# Copyright 2013-2015 ARM Limited
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# http://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 __future__ import division
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from devlib import DerivedMeasurements
|
||||||
|
from devlib.instrument import Measurement, MEASUREMENT_TYPES, InstrumentChannel
|
||||||
|
|
||||||
|
|
||||||
|
class DerivedEnergyMeasurements(DerivedMeasurements):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process(measurements_csv):
|
||||||
|
|
||||||
|
should_calculate_energy = []
|
||||||
|
use_timestamp = False
|
||||||
|
|
||||||
|
# Determine sites to calculate energy for
|
||||||
|
channel_map = defaultdict(list)
|
||||||
|
for channel in measurements_csv.channels:
|
||||||
|
channel_map[channel].append(channel.kind)
|
||||||
|
for channel, kinds in channel_map.iteritems():
|
||||||
|
if 'power' in kinds and not 'energy' in kinds:
|
||||||
|
should_calculate_energy.append(channel.site)
|
||||||
|
if channel.site == 'timestamp':
|
||||||
|
use_timestamp = True
|
||||||
|
time_measurment = channel.measurement_type
|
||||||
|
|
||||||
|
if measurements_csv.sample_rate_hz is None and not use_timestamp:
|
||||||
|
msg = 'Timestamp data is unavailable, please provide a sample rate'
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
if use_timestamp:
|
||||||
|
# Find index of timestamp column
|
||||||
|
ts_index = [i for i, chan in enumerate(measurements_csv.channels)
|
||||||
|
if chan.site == 'timestamp']
|
||||||
|
if len(ts_index) > 1:
|
||||||
|
raise ValueError('Multiple timestamps detected')
|
||||||
|
ts_index = ts_index[0]
|
||||||
|
|
||||||
|
row_ts = 0
|
||||||
|
last_ts = 0
|
||||||
|
energy_results = defaultdict(dict)
|
||||||
|
power_results = defaultdict(float)
|
||||||
|
|
||||||
|
# Process data
|
||||||
|
for count, row in enumerate(measurements_csv.itermeasurements()):
|
||||||
|
if use_timestamp:
|
||||||
|
last_ts = row_ts
|
||||||
|
row_ts = time_measurment.convert(float(row[ts_index].value), 'time')
|
||||||
|
for entry in row:
|
||||||
|
channel = entry.channel
|
||||||
|
site = channel.site
|
||||||
|
if channel.kind == 'energy':
|
||||||
|
if count == 0:
|
||||||
|
energy_results[site]['start'] = entry.value
|
||||||
|
else:
|
||||||
|
energy_results[site]['end'] = entry.value
|
||||||
|
|
||||||
|
if channel.kind == 'power':
|
||||||
|
power_results[site] += entry.value
|
||||||
|
|
||||||
|
if site in should_calculate_energy:
|
||||||
|
if count == 0:
|
||||||
|
energy_results[site]['start'] = 0
|
||||||
|
energy_results[site]['end'] = 0
|
||||||
|
elif use_timestamp:
|
||||||
|
energy_results[site]['end'] += entry.value * (row_ts - last_ts)
|
||||||
|
else:
|
||||||
|
energy_results[site]['end'] += entry.value * (1 /
|
||||||
|
measurements_csv.sample_rate_hz)
|
||||||
|
|
||||||
|
# Calculate final measurements
|
||||||
|
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))
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
return derived_measurements
|
Loading…
x
Reference in New Issue
Block a user