summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2019-02-01 15:55:45 +0100
committerDaniel Friesel <derf@finalrewind.org>2019-02-01 15:55:45 +0100
commit7dd98ebe0f52c85fd0e8f016b9a6d1ae4e932594 (patch)
treec22d82efbe019b9ea00af443af1aeb7f59fc1f07
parentd5a256640e60c7ed3211c57e3a22bf47af5dfc43 (diff)
move parameter influence detection to newly introduced ParamStat class
-rwxr-xr-xbin/analyze-archive.py24
-rwxr-xr-xbin/test.py24
-rwxr-xr-xlib/dfatool.py98
3 files changed, 75 insertions, 71 deletions
diff --git a/bin/analyze-archive.py b/bin/analyze-archive.py
index f203038..dbfe0d1 100755
--- a/bin/analyze-archive.py
+++ b/bin/analyze-archive.py
@@ -79,17 +79,17 @@ def print_text_model_data(model, pm, pq, lm, lq, am, ai, aq):
print(r'key attribute $1 - \frac{\sigma_X}{...}$')
for state_or_tran in model.by_name.keys():
for attribute in model.attributes(state_or_tran):
- print('{} {} {:.8f}'.format(state_or_tran, attribute, model.generic_param_dependence_ratio(state_or_tran, attribute)))
+ print('{} {} {:.8f}'.format(state_or_tran, attribute, model.stats.generic_param_dependence_ratio(state_or_tran, attribute)))
print('')
print(r'key attribute parameter $1 - \frac{...}{...}$')
for state_or_tran in model.by_name.keys():
for attribute in model.attributes(state_or_tran):
for param in model.parameters():
- print('{} {} {} {:.8f}'.format(state_or_tran, attribute, param, model.param_dependence_ratio(state_or_tran, attribute, param)))
+ print('{} {} {} {:.8f}'.format(state_or_tran, attribute, param, model.stats.param_dependence_ratio(state_or_tran, attribute, param)))
if state_or_tran in model._num_args:
for arg_index in range(model._num_args[state_or_tran]):
- print('{} {} {:d} {:.8f}'.format(state_or_tran, attribute, arg_index, model.arg_dependence_ratio(state_or_tran, attribute, arg_index)))
+ print('{} {} {:d} {:.8f}'.format(state_or_tran, attribute, arg_index, model.stats.arg_dependence_ratio(state_or_tran, attribute, arg_index)))
if __name__ == '__main__':
@@ -168,20 +168,20 @@ if __name__ == '__main__':
print('{:10s}: {:.0f} µW ({:.2f})'.format(
state,
static_model(state, 'power'),
- model.generic_param_dependence_ratio(state, 'power')))
+ model.stats.generic_param_dependence_ratio(state, 'power')))
for param in model.parameters():
print('{:10s} dependence on {:15s}: {:.2f}'.format(
'',
param,
- model.param_dependence_ratio(state, 'power', param)))
+ model.stats.param_dependence_ratio(state, 'power', param)))
for trans in model.transitions():
print('{:10s}: {:.0f} / {:.0f} / {:.0f} pJ ({:.2f} / {:.2f} / {:.2f})'.format(
trans, static_model(trans, 'energy'),
static_model(trans, 'rel_energy_prev'),
static_model(trans, 'rel_energy_next'),
- model.generic_param_dependence_ratio(trans, 'energy'),
- model.generic_param_dependence_ratio(trans, 'rel_energy_prev'),
- model.generic_param_dependence_ratio(trans, 'rel_energy_next')))
+ model.stats.generic_param_dependence_ratio(trans, 'energy'),
+ model.stats.generic_param_dependence_ratio(trans, 'rel_energy_prev'),
+ model.stats.generic_param_dependence_ratio(trans, 'rel_energy_next')))
print('{:10s}: {:.0f} µs'.format(trans, static_model(trans, 'duration')))
static_quality = model.assess(static_model)
@@ -200,14 +200,14 @@ if __name__ == '__main__':
for attribute in model.attributes(state):
info = param_info(state, attribute)
print('{:10s} {:10s} non-param stddev {:f}'.format(
- state, attribute, model.stats[state][attribute]['std_static']
+ state, attribute, model.stats.stats[state][attribute]['std_static']
))
print('{:10s} {:10s} param-lut stddev {:f}'.format(
- state, attribute, model.stats[state][attribute]['std_param_lut']
+ state, attribute, model.stats.stats[state][attribute]['std_param_lut']
))
- for param in sorted(model.stats[state][attribute]['std_by_param'].keys()):
+ for param in sorted(model.stats.stats[state][attribute]['std_by_param'].keys()):
print('{:10s} {:10s} {:10s} stddev {:f}'.format(
- state, attribute, param, model.stats[state][attribute]['std_by_param'][param]
+ state, attribute, param, model.stats.stats[state][attribute]['std_by_param'][param]
))
if info != None:
for param_name in sorted(info['fit_result'].keys(), key=str):
diff --git a/bin/test.py b/bin/test.py
index 433b423..0b015f4 100755
--- a/bin/test.py
+++ b/bin/test.py
@@ -43,18 +43,18 @@ class TestStaticModel(unittest.TestCase):
self.assertAlmostEqual(static_model('stopListening', 'duration'), 260, places=0)
self.assertAlmostEqual(static_model('write_nb', 'duration'), 510, places=0)
- self.assertAlmostEqual(model.param_dependence_ratio('POWERDOWN', 'power', 'datarate'), 0, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('POWERDOWN', 'power', 'txbytes'), 0, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('POWERDOWN', 'power', 'txpower'), 0, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('RX', 'power', 'datarate'), 0.99, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('RX', 'power', 'txbytes'), 0, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('RX', 'power', 'txpower'), 0.01, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('STANDBY1', 'power', 'datarate'), 0.04, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('STANDBY1', 'power', 'txbytes'), 0.35, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('STANDBY1', 'power', 'txpower'), 0.32, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('TX', 'power', 'datarate'), 1, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('TX', 'power', 'txbytes'), 0.09, places=2)
- self.assertAlmostEqual(model.param_dependence_ratio('TX', 'power', 'txpower'), 1, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('POWERDOWN', 'power', 'datarate'), 0, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('POWERDOWN', 'power', 'txbytes'), 0, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('POWERDOWN', 'power', 'txpower'), 0, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('RX', 'power', 'datarate'), 0.99, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('RX', 'power', 'txbytes'), 0, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('RX', 'power', 'txpower'), 0.01, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('STANDBY1', 'power', 'datarate'), 0.04, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('STANDBY1', 'power', 'txbytes'), 0.35, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('STANDBY1', 'power', 'txpower'), 0.32, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('TX', 'power', 'datarate'), 1, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('TX', 'power', 'txbytes'), 0.09, places=2)
+ self.assertAlmostEqual(model.stats.param_dependence_ratio('TX', 'power', 'txpower'), 1, places=2)
param_model, param_info = model.get_fitted()
self.assertEqual(param_info('POWERDOWN', 'power'), None)
diff --git a/lib/dfatool.py b/lib/dfatool.py
index 5c55993..1dc5df5 100755
--- a/lib/dfatool.py
+++ b/lib/dfatool.py
@@ -283,6 +283,52 @@ def _preprocess_measurement(measurement):
return processed_data
+class ParamStats:
+
+ def __init__(self, by_name, by_param, parameter_names, arg_count):
+ self.stats = dict()
+ # Note: This is deliberately single-threaded. The overhead incurred
+ # by multiprocessing is higher than the speed gained by parallel
+ # computation of statistics measures.
+ for state_or_tran in by_name.keys():
+ self.stats[state_or_tran] = dict()
+ for attribute in by_name[state_or_tran]['attributes']:
+ self.stats[state_or_tran][attribute] = compute_param_statistics(by_name, by_param, parameter_names, arg_count, state_or_tran, attribute)
+
+ def generic_param_independence_ratio(self, state_or_trans, attribute, use_corrcoef = False):
+ statistics = self.stats[state_or_trans][attribute]
+ if use_corrcoef:
+ # not supported
+ return 0
+ if statistics['std_static'] == 0:
+ return 0
+ return statistics['std_param_lut'] / statistics['std_static']
+
+ def generic_param_dependence_ratio(self, state_or_trans, attribute, use_corrcoef = False):
+ return 1 - self.generic_param_independence_ratio(state_or_trans, attribute, use_corrcoef)
+
+ def param_independence_ratio(self, state_or_trans, attribute, param, use_corrcoef = False):
+ statistics = self.stats[state_or_trans][attribute]
+ if use_corrcoef:
+ return 1 - np.abs(statistics['corr_by_param'][param])
+ if statistics['std_by_param'][param] == 0:
+ return 0
+ return statistics['std_param_lut'] / statistics['std_by_param'][param]
+
+ def param_dependence_ratio(self, state_or_trans, attribute, param, use_corrcoef = False):
+ return 1 - self.param_independence_ratio(state_or_trans, attribute, param, use_corrcoef)
+
+ def arg_independence_ratio(self, state_or_trans, attribute, arg_index, use_corrcoef = False):
+ statistics = self.stats[state_or_trans][attribute]
+ if use_corrcoef:
+ return 1 - np.abs(statistics['corr_by_arg'][arg_index])
+ if statistics['std_by_arg'][arg_index] == 0:
+ return 0
+ return statistics['std_param_lut'] / statistics['std_by_arg'][arg_index]
+
+ def arg_dependence_ratio(self, state_or_trans, attribute, arg_index, use_corrcoef = False):
+ return 1 - self.arg_independence_ratio(state_or_trans, attribute, arg_index, use_corrcoef)
+
class RawData:
"""
Loader for hardware model traces measured with MIMOSA.
@@ -733,7 +779,6 @@ class EnergyModel:
self.by_name = {}
self.by_param = {}
self.by_trace = {}
- self.stats = {}
self.cache = {}
np.seterr('raise')
self._parameter_names = sorted(self.traces[0]['trace'][0]['parameter'].keys())
@@ -782,20 +827,12 @@ class EnergyModel:
def _compute_all_param_statistics(self):
- # Note: This is deliberately single-threaded. The overhead incurred
- # by multiprocessing is higher than the speed gained by parallel
- # computation of statistics measures.
- for state_or_trans in self.by_name.keys():
- self.stats[state_or_trans] = {}
- for key in self.by_name[state_or_trans]['attributes']:
- if key in self.by_name[state_or_trans]:
- self.stats[state_or_trans][key] = compute_param_statistics(self.by_name, self.by_param, self._parameter_names, self._num_args, state_or_trans, key)
+ self.stats = ParamStats(self.by_name, self.by_param, self._parameter_names, self._num_args)
@classmethod
def from_model(self, model_data, parameter_names):
self.by_name = {}
self.by_param = {}
- self.stats = {}
np.seterr('raise')
self._parameter_names = parameter_names
for state_or_tran, values in model_data.items():
@@ -849,55 +886,22 @@ class EnergyModel:
self._add_data_to_aggregate(self.by_name, elem['name'], elem)
self._add_data_to_aggregate(self.by_param, (elem['name'], tuple(_elem_param_and_arg_list(elem))), elem)
- def generic_param_independence_ratio(self, state_or_trans, key):
- statistics = self.stats[state_or_trans][key]
- if self._use_corrcoef:
- return 0
- if statistics['std_static'] == 0:
- return 0
- return statistics['std_param_lut'] / statistics['std_static']
-
- def generic_param_dependence_ratio(self, state_or_trans, key):
- return 1 - self.generic_param_independence_ratio(state_or_trans, key)
-
- def param_independence_ratio(self, state_or_trans, key, param):
- statistics = self.stats[state_or_trans][key]
- if self._use_corrcoef:
- return 1 - np.abs(statistics['corr_by_param'][param])
- if statistics['std_by_param'][param] == 0:
- return 0
- return statistics['std_param_lut'] / statistics['std_by_param'][param]
-
- def param_dependence_ratio(self, state_or_trans, key, param):
- return 1 - self.param_independence_ratio(state_or_trans, key, param)
-
# This heuristic is very similar to the "function is not much better than
# median" checks in get_fitted. So far, doing it here as well is mostly
# a performance and not an algorithm quality decision.
# --df, 2018-04-18
def depends_on_param(self, state_or_trans, key, param):
if self._use_corrcoef:
- return self.param_dependence_ratio(state_or_trans, key, param) > 0.1
+ return self.stats.param_dependence_ratio(state_or_trans, key, param, self._use_corrcoef) > 0.1
else:
- return self.param_dependence_ratio(state_or_trans, key, param) > 0.5
-
- def arg_independence_ratio(self, state_or_trans, key, arg_index):
- statistics = self.stats[state_or_trans][key]
- if self._use_corrcoef:
- return 1 - np.abs(statistics['corr_by_arg'][arg_index])
- if statistics['std_by_arg'][arg_index] == 0:
- return 0
- return statistics['std_param_lut'] / statistics['std_by_arg'][arg_index]
-
- def arg_dependence_ratio(self, state_or_trans, key, arg_index):
- return 1 - self.arg_independence_ratio(state_or_trans, key, arg_index)
+ return self.stats.param_dependence_ratio(state_or_trans, key, param, self._use_corrcoef) > 0.5
# See notes on depends_on_param
def depends_on_arg(self, state_or_trans, key, param):
if self._use_corrcoef:
- return self.arg_dependence_ratio(state_or_trans, key, param) > 0.1
+ return self.stats.arg_dependence_ratio(state_or_trans, key, param, self._use_corrcoef) > 0.1
else:
- return self.arg_dependence_ratio(state_or_trans, key, param) > 0.5
+ return self.stats.arg_dependence_ratio(state_or_trans, key, param, self._use_corrcoef) > 0.5
def _get_model_from_dict(self, model_dict, model_function):
model = {}