From 85374727ad66b884b25ddd659600ee9317db071b Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Thu, 3 Dec 2020 15:16:24 +0100 Subject: use common energytrace loader code this also fixes a nasty off-by-one in the barcode loader (now _load_energytrace): wrong: interval_start_timestamp = data[:-1, 0] * 1e-6 correct: interval_start_timestamp = data[1:, 0] * 1e-6 --- lib/lennart/DataProcessor.py | 37 +++++---------- lib/lennart/EnergyInterface.py | 33 ------------- lib/loader.py | 105 ++++++++++++++++++++++++----------------- 3 files changed, 73 insertions(+), 102 deletions(-) (limited to 'lib') diff --git a/lib/lennart/DataProcessor.py b/lib/lennart/DataProcessor.py index 32d4dae..a8b49bf 100644 --- a/lib/lennart/DataProcessor.py +++ b/lib/lennart/DataProcessor.py @@ -7,7 +7,7 @@ logger = logging.getLogger(__name__) class DataProcessor: - def __init__(self, sync_data, energy_data): + def __init__(self, sync_data, et_timestamps, et_power): """ Creates DataProcessor object. @@ -18,13 +18,14 @@ class DataProcessor: # high-precision LA/Timer timestamps at synchronization events self.sync_timestamps = [] # low-precision energytrace timestamps - self.et_timestamps = [] + self.et_timestamps = et_timestamps # energytrace power values - self.et_power_values = [] + self.et_power_values = et_power self.sync_data = sync_data - self.energy_data = energy_data self.start_offset = 0 + # TODO determine automatically based on minimum (or p1) power draw over measurement area + X + # use 0.02 for HFXT runs self.power_sync_watt = 0.011 self.power_sync_len = 0.7 self.power_sync_max_outliers = 2 @@ -53,8 +54,6 @@ class DataProcessor: f"LogicAnalyzer sync data has length {len(time_stamp_data)}, expected >= 12" ) - last_data = [0, 0, 0, 0] - self.raw_sync_timestamps = time_stamp_data # NEW @@ -63,11 +62,8 @@ class DataProcessor: outliers = 0 pre_outliers_ts = None # TODO only consider the first few and the last few seconds for sync points - for i, energytrace_dataset in enumerate(self.energy_data): - usedtime = energytrace_dataset[0] - last_data[0] # in microseconds - timestamp = energytrace_dataset[0] - usedenergy = energytrace_dataset[3] - last_data[3] - power = usedenergy / usedtime * 1e-3 # in watts + for i, timestamp in enumerate(self.et_timestamps): + power = self.et_power_values[i] if power > 0: if power > self.power_sync_watt: if sync_start is None: @@ -80,27 +76,18 @@ class DataProcessor: outliers += 1 if outliers > self.power_sync_max_outliers: if sync_start is not None: - if ( - pre_outliers_ts - sync_start - ) / 1_000_000 > self.power_sync_len: + if (pre_outliers_ts - sync_start) > self.power_sync_len: datasync_timestamps.append( ( - sync_start / 1_000_000, - pre_outliers_ts / 1_000_000, + sync_start, + pre_outliers_ts, ) ) sync_start = None - last_data = energytrace_dataset - - self.et_timestamps.append(timestamp / 1_000_000) - self.et_power_values.append(power) - if power > self.power_sync_watt: - if (self.energy_data[-1][0] - sync_start) / 1_000_000 > self.power_sync_len: - datasync_timestamps.append( - (sync_start / 1_000_000, pre_outliers_ts / 1_000_000) - ) + if (self.et_timestamps[-1] - sync_start) > self.power_sync_len: + datasync_timestamps.append((sync_start, pre_outliers_ts)) # print(datasync_timestamps) diff --git a/lib/lennart/EnergyInterface.py b/lib/lennart/EnergyInterface.py index 19aae84..55bf7c1 100644 --- a/lib/lennart/EnergyInterface.py +++ b/lib/lennart/EnergyInterface.py @@ -70,39 +70,6 @@ class EnergyInterface(DataInterface): return self.energytrace.wait() - def getData(self): - """ - cleans the string data and creates int list - :return: list of data, in format [[int,int,int,int], [int,int,int,int], ... ] - """ - energytrace_log = open(self.temp_file) - lines = energytrace_log.readlines()[21:] - data = [] - for line in lines: - if "MSP430_DisableEnergyTrace" in line: - break - else: - data.append([int(i) for i in line.split()]) - return data - - @classmethod - def getDataFromString(cls, string, delimiter="\\n"): - """ - Parsing the data from string - - :param string: input string which will be parsed - :param delimiter: for normal file its \n - :return: list of data, in format [[int,int,int,int], [int,int,int,int], ... ] - """ - lines = string.split(delimiter)[21:] - data = [] - for line in lines: - if "MSP430_DisableEnergyTrace" in line: - break - else: - data.append([int(i) for i in line.split()]) - return data - def setFile(self, path): """ changeing the temporary file diff --git a/lib/loader.py b/lib/loader.py index 60be648..7a0fc4e 100644 --- a/lib/loader.py +++ b/lib/loader.py @@ -1232,6 +1232,47 @@ def pta_trace_to_aggregate(traces, ignore_trace_indexes=[]): return by_name, parameter_names, arg_count +def _load_energytrace(data_string): + """ + Load log data (raw energytrace .txt file, one line per event). + + :param log_data: raw energytrace log file in 4-column .txt format + """ + + lines = data_string.decode("ascii").split("\n") + data_count = sum(map(lambda x: len(x) > 0 and x[0] != "#", lines)) + data_lines = filter(lambda x: len(x) > 0 and x[0] != "#", lines) + + data = np.empty((data_count, 4)) + + for i, line in enumerate(data_lines): + fields = line.split(" ") + if len(fields) == 4: + timestamp, current, voltage, total_energy = map(int, fields) + elif len(fields) == 5: + # cpustate = fields[0] + timestamp, current, voltage, total_energy = map(int, fields[1:]) + else: + raise RuntimeError('cannot parse line "{}"'.format(line)) + data[i] = [timestamp, current, voltage, total_energy] + + interval_start_timestamp = data[1:, 0] * 1e-6 + interval_duration = (data[1:, 0] - data[:-1, 0]) * 1e-6 + interval_power = (data[1:, 3] - data[:-1, 3]) / (data[1:, 0] - data[:-1, 0]) * 1e-3 + + m_duration_us = data[-1, 0] - data[0, 0] + + sample_rate = data_count / (m_duration_us * 1e-6) + + logger.debug( + "got {} samples with {} seconds of log data ({} Hz)".format( + data_count, m_duration_us * 1e-6, sample_rate + ) + ) + + return (interval_start_timestamp, interval_duration, interval_power, sample_rate) + + class EnergyTraceWithBarcode: """ EnergyTrace log loader for DFA traces. @@ -1297,44 +1338,12 @@ class EnergyTraceWithBarcode: ) return list() - lines = log_data[0].decode("ascii").split("\n") - data_count = sum(map(lambda x: len(x) > 0 and x[0] != "#", lines)) - data_lines = filter(lambda x: len(x) > 0 and x[0] != "#", lines) - - data = np.empty((data_count, 4)) - - for i, line in enumerate(data_lines): - fields = line.split(" ") - if len(fields) == 4: - timestamp, current, voltage, total_energy = map(int, fields) - elif len(fields) == 5: - # cpustate = fields[0] - timestamp, current, voltage, total_energy = map(int, fields[1:]) - else: - raise RuntimeError('cannot parse line "{}"'.format(line)) - data[i] = [timestamp, current, voltage, total_energy] - - self.interval_start_timestamp = data[:-1, 0] * 1e-6 - self.interval_duration = (data[1:, 0] - data[:-1, 0]) * 1e-6 - self.interval_power = ((data[1:, 3] - data[:-1, 3]) * 1e-9) / ( - (data[1:, 0] - data[:-1, 0]) * 1e-6 - ) - - m_duration_us = data[-1, 0] - data[0, 0] - - self.sample_rate = data_count / (m_duration_us * 1e-6) - - logger.debug( - "got {} samples with {} seconds of log data ({} Hz)".format( - data_count, m_duration_us * 1e-6, self.sample_rate - ) - ) - - return ( + ( self.interval_start_timestamp, self.interval_duration, self.interval_power, - ) + self.sample_rate, + ) = _load_energytrace(log_data[0]) def ts_to_index(self, timestamp): """ @@ -1709,7 +1718,12 @@ class EnergyTraceWithLogicAnalyzer: # Daten laden self.sync_data = SigrokResult.fromString(log_data[0]) - self.energy_data = EnergyInterface.getDataFromString(str(log_data[1])) + ( + self.interval_start_timestamp, + self.interval_duration, + self.interval_power, + self.sample_rate, + ) = _load_energytrace(log_data[1]) def analyze_states(self, traces, offline_index: int): """ @@ -1743,7 +1757,11 @@ class EnergyTraceWithLogicAnalyzer: # print(names[:15]) from dfatool.lennart.DataProcessor import DataProcessor - dp = DataProcessor(sync_data=self.sync_data, energy_data=self.energy_data) + dp = DataProcessor( + sync_data=self.sync_data, + et_timestamps=self.interval_start_timestamp, + et_power=self.interval_power, + ) dp.run() energy_trace_new = dp.getStatesdfatool( state_sleep=self.state_duration, with_traces=self.with_traces @@ -1814,14 +1832,13 @@ class EnergyTraceWithTimer(EnergyTraceWithLogicAnalyzer): super().__init__(voltage, state_duration, transition_names, with_traces) def load_data(self, log_data): - from dfatool.lennart.SigrokInterface import SigrokResult - from dfatool.lennart.EnergyInterface import EnergyInterface - - # Daten laden self.sync_data = None - self.energy_data = EnergyInterface.getDataFromString(str(log_data[0])) - - pass + ( + self.interval_start_timestamp, + self.interval_duration, + self.interval_power, + self.sample_rate, + ) = _load_energytrace(log_data[0]) def analyze_states(self, traces, offline_index: int): -- cgit v1.2.3