From e5717042a42f614323c463f51e9afba1090691d9 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Mon, 9 Sep 2019 08:55:56 +0200 Subject: add more static accounting methods --- lib/automata.py | 27 ++++++++++++++++ lib/codegen.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 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. -- cgit v1.2.3