summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rwxr-xr-xlib/automata.py27
-rw-r--r--lib/codegen.py96
2 files changed, 118 insertions, 5 deletions
diff --git a/lib/automata.py b/lib/automata.py
index 30634ab..50ae179 100755
--- a/lib/automata.py
+++ b/lib/automata.py
@@ -537,6 +537,33 @@ class PTA:
"""Return PTA-specific ID of state."""
return self.get_state_names().index(state.name)
+ def get_unique_transitions(self):
+ """
+ Return list of PTA transitions without duplicates.
+
+ I.e., each transition name only occurs once, even if it has several entries due to
+ multiple origin states and/or overloading.
+ """
+ seen_transitions = set()
+ ret_transitions = list()
+ for transition in self.transitions:
+ if transition.name not in seen_transitions:
+ ret_transitions.append(transition)
+ seen_transitions.add(transition.name)
+ return ret_transitions
+
+ def get_unique_transition_id(self, transition: Transition) -> int:
+ """
+ Return PTA-specific ID of transition in unique transition list.
+
+ The followinng condition holds:
+ `
+ max_index = max(map(lambda t: pta.get_unique_transition_id(t), pta.get_unique_transitions()))
+ max_index == len(pta.get_unique_transitions) - 1
+ `
+ """
+ return self.get_unique_transitions().index(transition)
+
def get_initial_param_dict(self):
return dict([[self.parameters[i], self.initial_param_values[i]] for i in range(len(self.parameters))])
diff --git a/lib/codegen.py b/lib/codegen.py
index a8cb431..2d106df 100644
--- a/lib/codegen.py
+++ b/lib/codegen.py
@@ -155,8 +155,98 @@ class StaticStateOnlyAccounting(AccountingMethod):
lastState = 0;
lastStateChange = 0;
""".format(num_states = len(self.pta.state))
+
+class StaticAccounting(AccountingMethod):
+ def __init__(self, class_name: str, pta: PTA, ts_type = 'unsigned int', power_type = 'unsigned int', energy_type = 'unsigned long'):
+ super().__init__(class_name, pta)
+ self.ts_type = ts_type
+ self.include_paths.append('driver/uptime.h')
+ self.private_variables.append('unsigned char lastState;')
+ self.private_variables.append('{} lastStateChange;'.format(ts_type))
+ self.private_variables.append(array_template.format(
+ type = power_type,
+ name = 'state_power',
+ length = len(pta.state),
+ elements = ', '.join(map(lambda state_name: '{:.0f}'.format(pta.state[state_name].power), pta.get_state_names()))
+ ))
+ self.private_variables.append(array_template.format(
+ type = energy_type,
+ name = 'transition_energy',
+ length = len(pta.get_unique_transitions()),
+ elements = ', '.join(map(lambda transition: '{:.0f}'.format(transition.energy), pta.get_unique_transitions()))
+ ))
+ self.private_variables.append('{} timeInState[{}];'.format(ts_type, len(pta.state)))
+ self.private_variables.append('{} transitionCount[{}];'.format('unsigned int', len(pta.get_unique_transitions())))
+
+ get_energy_function = """
+ {energy_type} total_energy = 0;
+ for (unsigned char i = 0; i < {num_states}; i++) {{
+ total_energy += timeInState[i] * state_power[i];
+ }}
+ for (unsigned char i = 0; i < {num_transitions}; i++) {{
+ total_energy += transitionCount[i] * transition_energy[i];
+ }}
+ return total_energy;
+ """.format(energy_type = energy_type, num_states = len(pta.state), num_transitions = len(pta.get_unique_transitions()))
+ self.public_functions.append(ClassFunction(class_name, energy_type, 'getEnergy', list(), get_energy_function))
+
+ def pre_transition_hook(self, transition):
+ return """
+ unsigned int now = uptime.get_us();
+ timeInState[lastState] += now - lastStateChange;
+ transitionCount[{}]++;
+ lastStateChange = now;
+ lastState = {};
+ """.format(self.pta.get_unique_transition_id(transition), self.pta.get_state_id(transition.destination))
+
+ def init_code(self):
+ return """
+ for (unsigned char i = 0; i < {num_states}; i++) {{
+ timeInState[i] = 0;
+ }}
+ for (unsigned char i = 0; i < {num_transitions}; i++) {{
+ transitionCount[i] = 0;
+ }}
+ lastState = 0;
+ lastStateChange = 0;
+ """.format(num_states = len(self.pta.state), num_transitions = len(self.pta.get_unique_transitions()))
+class StaticAccountingImmediateCalculation(AccountingMethod):
+ def __init__(self, class_name: str, pta: PTA, ts_type = 'unsigned int', power_type = 'unsigned int', energy_type = 'unsigned long'):
+ super().__init__(class_name, pta)
+ self.ts_type = ts_type
+ self.include_paths.append('driver/uptime.h')
+ self.private_variables.append('unsigned char lastState;')
+ self.private_variables.append('{} lastStateChange;'.format(ts_type))
+ self.private_variables.append('{} totalEnergy;'.format(energy_type))
+ self.private_variables.append(array_template.format(
+ type = power_type,
+ name = 'state_power',
+ length = len(pta.state),
+ elements = ', '.join(map(lambda state_name: '{:.0f}'.format(pta.state[state_name].power), pta.get_state_names()))
+ ))
+
+ get_energy_function = """
+ return total_energy;
+ """.format(energy_type = energy_type, num_states = len(pta.state), num_transitions = len(pta.get_unique_transitions()))
+ self.public_functions.append(ClassFunction(class_name, energy_type, 'getEnergy', list(), get_energy_function))
+
+ def pre_transition_hook(self, transition):
+ return """
+ unsigned int now = uptime.get_us();
+ totalEnergy += (now - lastStateChange) * state_power[lastState];
+ totalEnergy += {};
+ lastStateChange = now;
+ lastState = {};
+ """.format(transition.energy, self.pta.get_state_id(transition.destination))
+
+ def init_code(self):
+ return """
+ lastState = 0;
+ lastStateChange = 0;
+ """.format(num_states = len(self.pta.state), num_transitions = len(self.pta.get_unique_transitions()))
+
class MultipassDriver:
"""Generate C++ header and no-op implementation for a multipass driver based on a DFA model."""
@@ -175,12 +265,8 @@ class MultipassDriver:
public_variables = list()
public_functions.append(ClassFunction(self.name, '', self.name, list(), accounting.init_code()))
- seen_transitions = set()
- for transition in self.pta.transitions:
- if transition.name in seen_transitions:
- continue
- seen_transitions.add(transition.name)
+ for transition in self.pta.get_unique_transitions():
# XXX right now we only verify whether both functions have the
# same number of arguments. This breaks in many overloading cases.