1e3c9fc78SDaniel Bristot de Oliveira#!/usr/bin/env python3 2e3c9fc78SDaniel Bristot de Oliveira# SPDX-License-Identifier: GPL-2.0-only 3e3c9fc78SDaniel Bristot de Oliveira# 4e3c9fc78SDaniel Bristot de Oliveira# Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org> 5e3c9fc78SDaniel Bristot de Oliveira# 6e3c9fc78SDaniel Bristot de Oliveira# Automata object: parse an automata in dot file digraph format into a python object 74041b9bbSDaniel Bristot de Oliveira# 84041b9bbSDaniel Bristot de Oliveira# For further information, see: 94041b9bbSDaniel Bristot de Oliveira# Documentation/trace/rv/deterministic_automata.rst 10e3c9fc78SDaniel Bristot de Oliveira 11e3c9fc78SDaniel Bristot de Oliveiraimport ntpath 12e3c9fc78SDaniel Bristot de Oliveira 13e3c9fc78SDaniel Bristot de Oliveiraclass Automata: 14e3c9fc78SDaniel Bristot de Oliveira """Automata class: Reads a dot file and part it as an automata. 15e3c9fc78SDaniel Bristot de Oliveira 16e3c9fc78SDaniel Bristot de Oliveira Attributes: 17e3c9fc78SDaniel Bristot de Oliveira dot_file: A dot file with an state_automaton definition. 18e3c9fc78SDaniel Bristot de Oliveira """ 19e3c9fc78SDaniel Bristot de Oliveira 20e3c9fc78SDaniel Bristot de Oliveira invalid_state_str = "INVALID_STATE" 21e3c9fc78SDaniel Bristot de Oliveira 22e3c9fc78SDaniel Bristot de Oliveira def __init__(self, file_path): 23e3c9fc78SDaniel Bristot de Oliveira self.__dot_path = file_path 24e3c9fc78SDaniel Bristot de Oliveira self.name = self.__get_model_name() 25e3c9fc78SDaniel Bristot de Oliveira self.__dot_lines = self.__open_dot() 26e3c9fc78SDaniel Bristot de Oliveira self.states, self.initial_state, self.final_states = self.__get_state_variables() 27e3c9fc78SDaniel Bristot de Oliveira self.events = self.__get_event_variables() 28e3c9fc78SDaniel Bristot de Oliveira self.function = self.__create_matrix() 29e3c9fc78SDaniel Bristot de Oliveira 30e3c9fc78SDaniel Bristot de Oliveira def __get_model_name(self): 31e3c9fc78SDaniel Bristot de Oliveira basename = ntpath.basename(self.__dot_path) 32*56233417SGabriele Monaco if not basename.endswith(".dot") and not basename.endswith(".gv"): 33e3c9fc78SDaniel Bristot de Oliveira print("not a dot file") 34e3c9fc78SDaniel Bristot de Oliveira raise Exception("not a dot file: %s" % self.__dot_path) 35e3c9fc78SDaniel Bristot de Oliveira 36*56233417SGabriele Monaco model_name = ntpath.splitext(basename)[0] 37e3c9fc78SDaniel Bristot de Oliveira if model_name.__len__() == 0: 38e3c9fc78SDaniel Bristot de Oliveira raise Exception("not a dot file: %s" % self.__dot_path) 39e3c9fc78SDaniel Bristot de Oliveira 40e3c9fc78SDaniel Bristot de Oliveira return model_name 41e3c9fc78SDaniel Bristot de Oliveira 42e3c9fc78SDaniel Bristot de Oliveira def __open_dot(self): 43e3c9fc78SDaniel Bristot de Oliveira cursor = 0 44e3c9fc78SDaniel Bristot de Oliveira dot_lines = [] 45e3c9fc78SDaniel Bristot de Oliveira try: 46e3c9fc78SDaniel Bristot de Oliveira dot_file = open(self.__dot_path) 47e3c9fc78SDaniel Bristot de Oliveira except: 48e3c9fc78SDaniel Bristot de Oliveira raise Exception("Cannot open the file: %s" % self.__dot_path) 49e3c9fc78SDaniel Bristot de Oliveira 50e3c9fc78SDaniel Bristot de Oliveira dot_lines = dot_file.read().splitlines() 51e3c9fc78SDaniel Bristot de Oliveira dot_file.close() 52e3c9fc78SDaniel Bristot de Oliveira 53e3c9fc78SDaniel Bristot de Oliveira # checking the first line: 54e3c9fc78SDaniel Bristot de Oliveira line = dot_lines[cursor].split() 55e3c9fc78SDaniel Bristot de Oliveira 56e3c9fc78SDaniel Bristot de Oliveira if (line[0] != "digraph") and (line[1] != "state_automaton"): 57e3c9fc78SDaniel Bristot de Oliveira raise Exception("Not a valid .dot format: %s" % self.__dot_path) 58e3c9fc78SDaniel Bristot de Oliveira else: 59e3c9fc78SDaniel Bristot de Oliveira cursor += 1 60e3c9fc78SDaniel Bristot de Oliveira return dot_lines 61e3c9fc78SDaniel Bristot de Oliveira 62e3c9fc78SDaniel Bristot de Oliveira def __get_cursor_begin_states(self): 63e3c9fc78SDaniel Bristot de Oliveira cursor = 0 64e3c9fc78SDaniel Bristot de Oliveira while self.__dot_lines[cursor].split()[0] != "{node": 65e3c9fc78SDaniel Bristot de Oliveira cursor += 1 66e3c9fc78SDaniel Bristot de Oliveira return cursor 67e3c9fc78SDaniel Bristot de Oliveira 68e3c9fc78SDaniel Bristot de Oliveira def __get_cursor_begin_events(self): 69e3c9fc78SDaniel Bristot de Oliveira cursor = 0 70e3c9fc78SDaniel Bristot de Oliveira while self.__dot_lines[cursor].split()[0] != "{node": 71e3c9fc78SDaniel Bristot de Oliveira cursor += 1 72e3c9fc78SDaniel Bristot de Oliveira while self.__dot_lines[cursor].split()[0] == "{node": 73e3c9fc78SDaniel Bristot de Oliveira cursor += 1 74e3c9fc78SDaniel Bristot de Oliveira # skip initial state transition 75e3c9fc78SDaniel Bristot de Oliveira cursor += 1 76e3c9fc78SDaniel Bristot de Oliveira return cursor 77e3c9fc78SDaniel Bristot de Oliveira 78e3c9fc78SDaniel Bristot de Oliveira def __get_state_variables(self): 79e3c9fc78SDaniel Bristot de Oliveira # wait for node declaration 80e3c9fc78SDaniel Bristot de Oliveira states = [] 81e3c9fc78SDaniel Bristot de Oliveira final_states = [] 82e3c9fc78SDaniel Bristot de Oliveira 83e3c9fc78SDaniel Bristot de Oliveira has_final_states = False 84e3c9fc78SDaniel Bristot de Oliveira cursor = self.__get_cursor_begin_states() 85e3c9fc78SDaniel Bristot de Oliveira 86e3c9fc78SDaniel Bristot de Oliveira # process nodes 87e3c9fc78SDaniel Bristot de Oliveira while self.__dot_lines[cursor].split()[0] == "{node": 88e3c9fc78SDaniel Bristot de Oliveira line = self.__dot_lines[cursor].split() 89e3c9fc78SDaniel Bristot de Oliveira raw_state = line[-1] 90e3c9fc78SDaniel Bristot de Oliveira 91e3c9fc78SDaniel Bristot de Oliveira # "enabled_fired"}; -> enabled_fired 92e3c9fc78SDaniel Bristot de Oliveira state = raw_state.replace('"', '').replace('};', '').replace(',','_') 93e3c9fc78SDaniel Bristot de Oliveira if state[0:7] == "__init_": 94e3c9fc78SDaniel Bristot de Oliveira initial_state = state[7:] 95e3c9fc78SDaniel Bristot de Oliveira else: 96e3c9fc78SDaniel Bristot de Oliveira states.append(state) 97*56233417SGabriele Monaco if "doublecircle" in self.__dot_lines[cursor]: 98e3c9fc78SDaniel Bristot de Oliveira final_states.append(state) 99e3c9fc78SDaniel Bristot de Oliveira has_final_states = True 100e3c9fc78SDaniel Bristot de Oliveira 101*56233417SGabriele Monaco if "ellipse" in self.__dot_lines[cursor]: 102e3c9fc78SDaniel Bristot de Oliveira final_states.append(state) 103e3c9fc78SDaniel Bristot de Oliveira has_final_states = True 104e3c9fc78SDaniel Bristot de Oliveira 105e3c9fc78SDaniel Bristot de Oliveira cursor += 1 106e3c9fc78SDaniel Bristot de Oliveira 107e3c9fc78SDaniel Bristot de Oliveira states = sorted(set(states)) 108e3c9fc78SDaniel Bristot de Oliveira states.remove(initial_state) 109e3c9fc78SDaniel Bristot de Oliveira 110e3c9fc78SDaniel Bristot de Oliveira # Insert the initial state at the bein og the states 111e3c9fc78SDaniel Bristot de Oliveira states.insert(0, initial_state) 112e3c9fc78SDaniel Bristot de Oliveira 113*56233417SGabriele Monaco if not has_final_states: 114e3c9fc78SDaniel Bristot de Oliveira final_states.append(initial_state) 115e3c9fc78SDaniel Bristot de Oliveira 116e3c9fc78SDaniel Bristot de Oliveira return states, initial_state, final_states 117e3c9fc78SDaniel Bristot de Oliveira 118e3c9fc78SDaniel Bristot de Oliveira def __get_event_variables(self): 119e3c9fc78SDaniel Bristot de Oliveira # here we are at the begin of transitions, take a note, we will return later. 120e3c9fc78SDaniel Bristot de Oliveira cursor = self.__get_cursor_begin_events() 121e3c9fc78SDaniel Bristot de Oliveira 122e3c9fc78SDaniel Bristot de Oliveira events = [] 123*56233417SGabriele Monaco while self.__dot_lines[cursor].lstrip()[0] == '"': 124e3c9fc78SDaniel Bristot de Oliveira # transitions have the format: 125e3c9fc78SDaniel Bristot de Oliveira # "all_fired" -> "both_fired" [ label = "disable_irq" ]; 126e3c9fc78SDaniel Bristot de Oliveira # ------------ event is here ------------^^^^^ 127e3c9fc78SDaniel Bristot de Oliveira if self.__dot_lines[cursor].split()[1] == "->": 128e3c9fc78SDaniel Bristot de Oliveira line = self.__dot_lines[cursor].split() 129e3c9fc78SDaniel Bristot de Oliveira event = line[-2].replace('"','') 130e3c9fc78SDaniel Bristot de Oliveira 131e3c9fc78SDaniel Bristot de Oliveira # when a transition has more than one lables, they are like this 132e3c9fc78SDaniel Bristot de Oliveira # "local_irq_enable\nhw_local_irq_enable_n" 133e3c9fc78SDaniel Bristot de Oliveira # so split them. 134e3c9fc78SDaniel Bristot de Oliveira 135e3c9fc78SDaniel Bristot de Oliveira event = event.replace("\\n", " ") 136e3c9fc78SDaniel Bristot de Oliveira for i in event.split(): 137e3c9fc78SDaniel Bristot de Oliveira events.append(i) 138e3c9fc78SDaniel Bristot de Oliveira cursor += 1 139e3c9fc78SDaniel Bristot de Oliveira 140e3c9fc78SDaniel Bristot de Oliveira return sorted(set(events)) 141e3c9fc78SDaniel Bristot de Oliveira 142e3c9fc78SDaniel Bristot de Oliveira def __create_matrix(self): 143e3c9fc78SDaniel Bristot de Oliveira # transform the array into a dictionary 144e3c9fc78SDaniel Bristot de Oliveira events = self.events 145e3c9fc78SDaniel Bristot de Oliveira states = self.states 146e3c9fc78SDaniel Bristot de Oliveira events_dict = {} 147e3c9fc78SDaniel Bristot de Oliveira states_dict = {} 148e3c9fc78SDaniel Bristot de Oliveira nr_event = 0 149e3c9fc78SDaniel Bristot de Oliveira for event in events: 150e3c9fc78SDaniel Bristot de Oliveira events_dict[event] = nr_event 151e3c9fc78SDaniel Bristot de Oliveira nr_event += 1 152e3c9fc78SDaniel Bristot de Oliveira 153e3c9fc78SDaniel Bristot de Oliveira nr_state = 0 154e3c9fc78SDaniel Bristot de Oliveira for state in states: 155e3c9fc78SDaniel Bristot de Oliveira states_dict[state] = nr_state 156e3c9fc78SDaniel Bristot de Oliveira nr_state += 1 157e3c9fc78SDaniel Bristot de Oliveira 158e3c9fc78SDaniel Bristot de Oliveira # declare the matrix.... 159e3c9fc78SDaniel Bristot de Oliveira matrix = [[ self.invalid_state_str for x in range(nr_event)] for y in range(nr_state)] 160e3c9fc78SDaniel Bristot de Oliveira 161e3c9fc78SDaniel Bristot de Oliveira # and we are back! Let's fill the matrix 162e3c9fc78SDaniel Bristot de Oliveira cursor = self.__get_cursor_begin_events() 163e3c9fc78SDaniel Bristot de Oliveira 164*56233417SGabriele Monaco while self.__dot_lines[cursor].lstrip()[0] == '"': 165e3c9fc78SDaniel Bristot de Oliveira if self.__dot_lines[cursor].split()[1] == "->": 166e3c9fc78SDaniel Bristot de Oliveira line = self.__dot_lines[cursor].split() 167e3c9fc78SDaniel Bristot de Oliveira origin_state = line[0].replace('"','').replace(',','_') 168e3c9fc78SDaniel Bristot de Oliveira dest_state = line[2].replace('"','').replace(',','_') 169e3c9fc78SDaniel Bristot de Oliveira possible_events = line[-2].replace('"','').replace("\\n", " ") 170e3c9fc78SDaniel Bristot de Oliveira for event in possible_events.split(): 171e3c9fc78SDaniel Bristot de Oliveira matrix[states_dict[origin_state]][events_dict[event]] = dest_state 172e3c9fc78SDaniel Bristot de Oliveira cursor += 1 173e3c9fc78SDaniel Bristot de Oliveira 174e3c9fc78SDaniel Bristot de Oliveira return matrix 175