diff options
author | Daniel Friesel <derf@finalrewind.org> | 2018-01-25 13:33:47 +0100 |
---|---|---|
committer | Daniel Friesel <derf@finalrewind.org> | 2018-01-25 13:33:47 +0100 |
commit | 6eabea2d52da2bc26c23453c29b7f88b4fc69cae (patch) | |
tree | 412a67e13ed299edc9cf2e648e319f3bf3d20452 | |
parent | 9771ea33a14ebd90e6878963e4f0e99be09b4aca (diff) |
Re-implement basic state/transition-based analysis
-rwxr-xr-x | bin/analyze-archive.py | 15 | ||||
-rwxr-xr-x | lib/dfatool.py | 110 |
2 files changed, 105 insertions, 20 deletions
diff --git a/bin/analyze-archive.py b/bin/analyze-archive.py index c3a1547..a2596d3 100755 --- a/bin/analyze-archive.py +++ b/bin/analyze-archive.py @@ -7,11 +7,20 @@ from scipy.cluster.vq import kmeans2 import struct import sys import tarfile -from dfatool import AEMRAnalyzer +from dfatool import Analysis, RawData if __name__ == '__main__': filename = sys.argv[1] - analyzer = AEMRAnalyzer(filename) + raw_data = RawData(filename) - analyzer.preprocess() + preprocessed_data = raw_data.get_preprocessed_data() + print(preprocessed_data) + foo = Analysis(preprocessed_data) + res = foo.analyze() + print(res) + for key in res.keys(): + print(key) + for subkey in res[key].keys(): + if subkey != 'isa' and len(res[key][subkey]) > 0: + print(' {:s}: {:f}'.format(subkey, np.mean(res[key][subkey]))) sys.exit(0) diff --git a/lib/dfatool.py b/lib/dfatool.py index 6c3f322..e56e0b0 100755 --- a/lib/dfatool.py +++ b/lib/dfatool.py @@ -110,11 +110,12 @@ def _preprocess_measurement(measurement): return processed_data -class AEMRAnalyzer: +class RawData: def __init__(self, filename): self.filename = filename self.version = 0 + self.preprocessed = False def _state_is_too_short(self, online, offline, state_duration, next_transition): # We cannot control when an interrupt causes a state to be left @@ -166,20 +167,24 @@ class AEMRAnalyzer: if online_trace_part['isa'] == 'state' and online_trace_part['name'] != 'UNINITIALIZED': online_prev_transition = self.traces[online_run_idx]['trace'][online_trace_part_idx-1] online_next_transition = self.traces[online_run_idx]['trace'][online_trace_part_idx+1] - if self._state_is_too_short(online_trace_part, offline_trace_part, state_duration, online_next_transition): - processed_data['error'] = 'Offline #{off_idx:d} (online {on_name:s} @ {on_idx:d}/{on_sub:d}) is too short (duration = {dur:d} us)'.format( - off_idx = offline_idx, on_idx = online_run_idx, - on_sub = online_trace_part_idx, - on_name = online_trace_part['name'], - dur = offline_trace_part['us']) - return False - if self._state_is_too_long(online_trace_part, offline_trace_part, state_duration, online_prev_transition): - processed_data['error'] = 'Offline #{off_idx:d} (online {on_name:s} @ {on_idx:d}/{on_sub:d}) is too long (duration = {dur:d} us)'.format( - off_idx = offline_idx, on_idx = online_run_idx, - on_sub = online_trace_part_idx, - on_name = online_trace_part['name'], - dur = offline_trace_part['us']) - return False + try: + if self._state_is_too_short(online_trace_part, offline_trace_part, state_duration, online_next_transition): + processed_data['error'] = 'Offline #{off_idx:d} (online {on_name:s} @ {on_idx:d}/{on_sub:d}) is too short (duration = {dur:d} us)'.format( + off_idx = offline_idx, on_idx = online_run_idx, + on_sub = online_trace_part_idx, + on_name = online_trace_part['name'], + dur = offline_trace_part['us']) + return False + if self._state_is_too_long(online_trace_part, offline_trace_part, state_duration, online_prev_transition): + processed_data['error'] = 'Offline #{off_idx:d} (online {on_name:s} @ {on_idx:d}/{on_sub:d}) is too long (duration = {dur:d} us)'.format( + off_idx = offline_idx, on_idx = online_run_idx, + on_sub = online_trace_part_idx, + on_name = online_trace_part['name'], + dur = offline_trace_part['us']) + return False + except KeyError: + pass + # TODO es gibt next_transitions ohne 'plan' return True def _merge_measurement_into_online_data(self, measurement): @@ -197,9 +202,47 @@ class AEMRAnalyzer: else: online_trace_part['offline'].append(offline_trace_part) - def preprocess(self): + if not 'offline_aggregates' in online_trace_part: + online_trace_part['offline_aggregates'] = { + 'power_mean' : [], + 'duration' : [], + 'power_std' : [], + 'energy' : [], + 'clipping' : [], + 'timeout' : [], + 'rel_energy_prev' : [], + 'rel_energy_next' : [] + } + + # Note: All state/transitions are 20us "too long" due to injected + # active wait states. These are needed to work around MIMOSA's + # relatively low sample rate of 100 kHz (10us) and removed here. + online_trace_part['offline_aggregates']['power_mean'].append( + offline_trace_part['uW_mean']) + online_trace_part['offline_aggregates']['duration'].append( + offline_trace_part['us'] - 20) + online_trace_part['offline_aggregates']['power_std'].append( + offline_trace_part['uW_std']) + online_trace_part['offline_aggregates']['energy'].append( + offline_trace_part['uW_mean'] * (offline_trace_part['us'] - 20)) + online_trace_part['offline_aggregates']['clipping'].append( + offline_trace_part['clip_rate']) + if online_trace_part['isa'] == 'transition': + online_trace_part['offline_aggregates']['timeout'].append( + offline_trace_part['timeout']) + online_trace_part['offline_aggregates']['rel_energy_prev'].append( + offline_trace_part['uW_mean_delta_prev'] * (offline_trace_part['us'] - 20)) + online_trace_part['offline_aggregates']['rel_energy_next'].append( + offline_trace_part['uW_mean_delta_next'] * (offline_trace_part['us'] - 20)) + + + def get_preprocessed_data(self): + if self.preprocessed: + return self.traces if self.version == 0: self.preprocess_0() + self.preprocessed = True + return self.traces # Loads raw MIMOSA data and turns it into measurements which are ready to # be analyzed. @@ -233,9 +276,42 @@ class AEMRAnalyzer: print('[I] {num_valid:d}/{num_total:d} measurements are valid'.format( num_valid = num_valid, num_total = len(measurements))) + self.setup = setup + self.preprocessing_stats = { + 'num_runs' : len(measurements), + 'num_valid' : num_valid + } + +class Analysis: + + def __init__(self, preprocessed_data): + self.traces = preprocessed_data + self.by_name = {} + self.by_arg = {} + self.by_param = {} + self.by_trace = {} + + def _add_data_to_aggregate(self, aggregate, key, element): + if not key in aggregate: + aggregate[key] = { + 'isa' : element['isa'] + } + for datakey in element['offline_aggregates'].keys(): + aggregate[key][datakey] = [] + for datakey, dataval in element['offline_aggregates'].items(): + aggregate[key][datakey].extend(dataval) + + def _load_run_elem(self, i, elem): + self._add_data_to_aggregate(self.by_name, elem['name'], elem) def analyze(self): - pass + for runidx, run in enumerate(self.traces): + # if opts['ignore-trace-idx'] != runidx + for i, elem in enumerate(run['trace']): + if elem['name'] != 'UNINITIALIZED': + self._load_run_elem(i, elem) + return self.by_name + class MIMOSA: |