from ScEpTIC.AST.elements.instructions.other_operations import CallOperation from ScEpTIC.analysis.utils.saved_state_calculator import SavedStateCalculator from ScEpTIC.analysis.utils.settings_cache import SettingsCache class MaxStateIdentifier: """ Utility that identifies the volatile state maximum size. """ cache_element = "max_state" def __init__(self, vm): """ :param vm: ScEpTIC vm """ self.vm = vm self.n_registers = 0 self.n_memory_cells = 0 self.save_only_pc = True self.has_static_placement = self.vm.state_retention.static_placement self.state_calc = SavedStateCalculator(self.vm) # Cache file_name = self.vm.state.config.program.file cache_target = "{}_{}".format(file_name, 'static' if self.has_static_placement else 'interrupt') self._cache = SettingsCache(self.cache_element, cache_target) def _load_cache(self): """ Load data from the cache file """ self._cache.load() try: self.n_registers = self._cache.data['n_registers'] self.n_memory_cells = self._cache.data['n_memory_cells'] self.save_only_pc = self._cache.data['save_only_pc'] print(f"Max state loaded - Regs: {self.n_registers}; Memory: {self.n_memory_cells}; Save only pc: {self.save_only_pc}") return True except KeyError: return False def _save_cache(self): """ Save data into the cache file """ self._cache.data = { 'n_registers': self.n_registers, 'n_memory_cells': self.n_memory_cells, 'save_only_pc': self.save_only_pc } self._cache.save() def identify(self): """ Identifies the maximum state to be saved """ if self._load_cache(): return print(f"Identifying maximum state") self.vm.reset() state_save_function_name = self.vm.state_retention.routine_names['save'] while not self.vm.state.program_end_reached: current_instruction = self.vm.state.current_instruction self.vm.state.run_step() # Static placement -> state saved only when state-save operation reached if self.has_static_placement: # Skip calc if state-saving operation not reached if not isinstance(current_instruction, CallOperation) or current_instruction.resolve_function_name() != state_save_function_name: continue save_only_pc, n_registers = self.state_calc.get_saved_registers(current_instruction) n_memory_cells = self.state_calc.get_saved_memory_cells(current_instruction) self.n_registers = max(self.n_registers, n_registers) self.n_memory_cells = max(self.n_memory_cells, n_memory_cells) self.save_only_pc = self.save_only_pc & save_only_pc self._save_cache() print(f" -> Regs: {self.n_registers}; Memory: {self.n_memory_cells}; Save only pc: {self.save_only_pc}") self.vm.reset()