blob: 770db889e1943911fbe5cc50e3d691edc0d481c6 [file] [log] [blame]
Marc Bonnicic093d562017-08-07 14:29:40 +01001# Copyright 2013-2015 ARM Limited
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15from __future__ import division
16from collections import defaultdict
17
18from devlib import DerivedMeasurements
19from devlib.instrument import Measurement, MEASUREMENT_TYPES, InstrumentChannel
20
21
22class DerivedEnergyMeasurements(DerivedMeasurements):
23
24 @staticmethod
25 def process(measurements_csv):
26
27 should_calculate_energy = []
28 use_timestamp = False
29
30 # Determine sites to calculate energy for
31 channel_map = defaultdict(list)
32 for channel in measurements_csv.channels:
33 channel_map[channel].append(channel.kind)
34 for channel, kinds in channel_map.iteritems():
35 if 'power' in kinds and not 'energy' in kinds:
36 should_calculate_energy.append(channel.site)
37 if channel.site == 'timestamp':
38 use_timestamp = True
39 time_measurment = channel.measurement_type
40
41 if measurements_csv.sample_rate_hz is None and not use_timestamp:
42 msg = 'Timestamp data is unavailable, please provide a sample rate'
43 raise ValueError(msg)
44
45 if use_timestamp:
46 # Find index of timestamp column
47 ts_index = [i for i, chan in enumerate(measurements_csv.channels)
48 if chan.site == 'timestamp']
49 if len(ts_index) > 1:
50 raise ValueError('Multiple timestamps detected')
51 ts_index = ts_index[0]
52
53 row_ts = 0
54 last_ts = 0
55 energy_results = defaultdict(dict)
56 power_results = defaultdict(float)
57
58 # Process data
59 for count, row in enumerate(measurements_csv.itermeasurements()):
60 if use_timestamp:
61 last_ts = row_ts
62 row_ts = time_measurment.convert(float(row[ts_index].value), 'time')
63 for entry in row:
64 channel = entry.channel
65 site = channel.site
66 if channel.kind == 'energy':
67 if count == 0:
68 energy_results[site]['start'] = entry.value
69 else:
70 energy_results[site]['end'] = entry.value
71
72 if channel.kind == 'power':
73 power_results[site] += entry.value
74
75 if site in should_calculate_energy:
76 if count == 0:
77 energy_results[site]['start'] = 0
78 energy_results[site]['end'] = 0
79 elif use_timestamp:
80 energy_results[site]['end'] += entry.value * (row_ts - last_ts)
81 else:
82 energy_results[site]['end'] += entry.value * (1 /
83 measurements_csv.sample_rate_hz)
84
85 # Calculate final measurements
86 derived_measurements = []
87 for site in energy_results:
88 total_energy = energy_results[site]['end'] - energy_results[site]['start']
89 instChannel = InstrumentChannel('cum_energy', site, MEASUREMENT_TYPES['energy'])
90 derived_measurements.append(Measurement(total_energy, instChannel))
91
92 for site in power_results:
93 power = power_results[site] / (count + 1) #pylint: disable=undefined-loop-variable
94 instChannel = InstrumentChannel('avg_power', site, MEASUREMENT_TYPES['power'])
95 derived_measurements.append(Measurement(power, instChannel))
96
97 return derived_measurements