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