summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <daniel.friesel@uos.de>2020-05-14 15:57:49 +0200
committerDaniel Friesel <daniel.friesel@uos.de>2020-05-14 16:01:33 +0200
commit09fadc865649e7726577153f50a87b4803e74e86 (patch)
treeec6653a298523a563148b2ad0ec0105b89207f51
parentf057c3af79962cfa953fe3f4b7464cec4a3ba74e (diff)
Allow individual energy/power traces to be exported to the file system
-rwxr-xr-xbin/analyze-archive.py36
-rw-r--r--lib/dfatool.py28
2 files changed, 57 insertions, 7 deletions
diff --git a/bin/analyze-archive.py b/bin/analyze-archive.py
index 770e5d5..f7847c5 100755
--- a/bin/analyze-archive.py
+++ b/bin/analyze-archive.py
@@ -21,6 +21,22 @@ Options:
parameters. Also plots the corresponding measurements.
If gplearn function is set, it is plotted using dashed lines.
+--export-traces=<directory>
+ Export power traces of all states and transitions to <directory>.
+ Creates a JSON file for each state and transition. Each JSON file
+ lists all occurences of the corresponding state/transition in the
+ benchmark's PTA trace. Each occurence contains the corresponding PTA
+ parameters (if any) in 'parameter' and measurement results in 'offline'.
+ As measurements are typically run repeatedly, 'offline' is in turn a list
+ of measurements: offline[0]['uW'] is the power trace of the first
+ measurement of this state/transition, offline[1]['uW'] corresponds t the
+ second measurement, etc. Values are provided in microwatts.
+ For example, TX.json[0].offline[0].uW corresponds to the first measurement
+ of the first TX state in the benchmark, and TX.json[5].offline[2].uW
+ corresponds to the third measurement of the sixth TX state in the benchmark.
+ WARNING: Several GB of RAM and disk space are required for complex measurements.
+ (JSON files may grow very large -- we trade efficiency for easy handling)
+
--param-info
Show parameter names and values
@@ -220,6 +236,7 @@ if __name__ == '__main__':
show_quality = []
pta = None
energymodel_export_file = None
+ trace_export_dir = None
xv_method = None
xv_count = 10
@@ -227,6 +244,7 @@ if __name__ == '__main__':
optspec = (
'plot-unparam= plot-param= param-info show-models= show-quality= '
'ignored-trace-indexes= discard-outliers= function-override= '
+ 'export-traces= '
'filter-param= '
'cross-validate= '
'with-safe-functions hwmodel= export-energymodel='
@@ -275,10 +293,26 @@ if __name__ == '__main__':
print(err)
sys.exit(2)
- raw_data = RawData(args)
+ raw_data = RawData(args, with_traces=('export-traces' in opts))
preprocessed_data = raw_data.get_preprocessed_data()
+ if 'export-traces' in opts:
+ uw_per_sot = dict()
+ for trace in preprocessed_data:
+ for state_or_transition in trace['trace']:
+ name = state_or_transition['name']
+ if name not in uw_per_sot:
+ uw_per_sot[name] = list()
+ for elem in state_or_transition['offline']:
+ elem['uW'] = list(elem['uW'])
+ uw_per_sot[name].append(state_or_transition)
+ for name, data in uw_per_sot.items():
+ target = f"{opts['export-traces']}/{name}.json"
+ print(f'exporting {target} ...')
+ with open(target, 'w') as f:
+ json.dump(data, f)
+
if raw_data.preprocessing_stats['num_valid'] == 0:
print('No valid data available. Abort.')
sys.exit(2)
diff --git a/lib/dfatool.py b/lib/dfatool.py
index 177bd7b..8fb41a5 100644
--- a/lib/dfatool.py
+++ b/lib/dfatool.py
@@ -332,7 +332,7 @@ class CrossValidator:
def _preprocess_mimosa(measurement):
setup = measurement['setup']
- mim = MIMOSA(float(setup['mimosa_voltage']), int(setup['mimosa_shunt']))
+ mim = MIMOSA(float(setup['mimosa_voltage']), int(setup['mimosa_shunt']), with_traces=measurement['with_traces'])
try:
charges, triggers = mim.load_data(measurement['content'])
trigidx = mim.trigger_edges(triggers)
@@ -489,14 +489,16 @@ class RawData:
Expects a specific trace format and UART log output (as produced by the
dfatool benchmark generator). Loads data, prunes bogus measurements, and
- provides preprocessed data suitable for PTAModel.
+ provides preprocessed data suitable for PTAModel. Results are cached on the
+ file system, making subsequent loads near-instant.
"""
- def __init__(self, filenames):
+ def __init__(self, filenames, with_traces=False):
"""
Create a new RawData object.
- Each filename element corresponds to a measurement run. It must be a tar archive with the following contents:
+ Each filename element corresponds to a measurement run.
+ It must be a tar archive with the following contents:
Version 0:
@@ -540,8 +542,12 @@ class RawData:
`.opt.configs`: ....
* EnergyTrace log files (`*.etlog`) as specified in `.opt.files`
+ If a cached result for a file is available, it is loaded and the file
+ is not preprocessed, unless `with_traces` is set.
+
tbd
"""
+ self.with_traces = with_traces
self.filenames = filenames.copy()
self.traces_by_fileno = []
self.setup_by_fileno = []
@@ -562,7 +568,8 @@ class RawData:
break
self.set_cache_file()
- self.load_cache()
+ if not with_traces:
+ self.load_cache()
def set_cache_file(self):
cache_key = hashlib.sha256('!'.join(self.filenames).encode()).hexdigest()
@@ -580,6 +587,8 @@ class RawData:
self.preprocessed = True
def save_cache(self):
+ if self.with_traces:
+ return
try:
os.mkdir(self.cache_dir)
except FileExistsError:
@@ -920,6 +929,7 @@ class RawData:
def get_preprocessed_data(self, verbose=True):
"""
Return a list of DFA traces annotated with energy, timing, and parameter data.
+ The list is cached on disk, unless the constructor was called with `with_traces` set.
Each DFA trace contains the following elements:
* `id`: Numeric ID, starting with 1
@@ -1000,6 +1010,7 @@ class RawData:
'fileno': i,
'info': member,
'setup': self.setup_by_fileno[i],
+ 'with_traces': self.with_traces,
})
elif version == 1:
@@ -1049,6 +1060,7 @@ class RawData:
'setup': self.setup_by_fileno[j],
'repeat_id': repeat_id,
'expected_trace': ptalog['traces'][j],
+ 'with_traces': self.with_traces,
})
self.filenames = new_filenames
@@ -2507,7 +2519,7 @@ class MIMOSA:
Resulting data is a list of state/transition/state/transition/... measurements.
"""
- def __init__(self, voltage: float, shunt: int, verbose=True):
+ def __init__(self, voltage: float, shunt: int, verbose=True, with_traces=False):
"""
Initialize MIMOSA loader for a specific voltage and shunt setting.
@@ -2518,6 +2530,7 @@ class MIMOSA:
self.voltage = voltage
self.shunt = shunt
self.verbose = verbose
+ self.with_traces = with_traces
self.r1 = 984 # "1k"
self.r2 = 99013 # "100k"
self.errors = list()
@@ -2855,6 +2868,9 @@ class MIMOSA:
'us': (idx - previdx) * 10,
}
+ if self.with_traces:
+ data['uW'] = range_ua * self.voltage
+
if 'states' in substates:
data['substates'] = substates
ssum = np.sum(list(map(lambda x: x['duration'], substates['states'])))