From d7649bf570a86da31da9353eee6faf6b12e7e96a Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Wed, 22 Jan 2025 15:04:53 +0100 Subject: [PATCH 01/21] bumped to qtpy6 --- b_asic/scheduler_gui/main_window.py | 16 +- b_asic/scheduler_gui/ui_main_window.py | 796 ++++++++----------------- 2 files changed, 268 insertions(+), 544 deletions(-) diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py index bd03b5f2..4de6e4cd 100644 --- a/b_asic/scheduler_gui/main_window.py +++ b/b_asic/scheduler_gui/main_window.py @@ -31,7 +31,7 @@ from qtpy.QtCore import ( Qt, Slot, ) -from qtpy.QtGui import QCloseEvent, QColor, QFont, QIcon, QIntValidator +from qtpy.QtGui import QCloseEvent, QColor, QFont, QIcon, QIntValidator, QPalette from qtpy.QtWidgets import ( QAbstractButton, QAction, @@ -98,9 +98,9 @@ if __debug__: log.debug(f"Qt version (compile time): {QtCore.__version__}") log.debug(f"QT_API: {QT_API}") if QT_API.lower().startswith("pyside"): - import PySide2 + import PySide6 - log.debug(f"PySide version: {PySide2.__version__}") + log.debug(f"PySide version: {PySide6.__version__}") if QT_API.lower().startswith("pyqt"): from qtpy.QtCore import PYQT_VERSION_STR @@ -1688,8 +1688,16 @@ def start_scheduler(schedule: Optional[Schedule] = None) -> Optional[Schedule]: The edited schedule. """ if not QApplication.instance(): - QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) app = QApplication(sys.argv) + # Enforce a light palette regardless of laptop theme + palette = QPalette() + palette.setColor(QPalette.ColorRole.Window, QtCore.Qt.white) + palette.setColor(QPalette.ColorRole.WindowText, QtCore.Qt.black) + palette.setColor(QPalette.ColorRole.ButtonText, QtCore.Qt.black) + palette.setColor(QPalette.ColorRole.Base, QtCore.Qt.white) + palette.setColor(QPalette.ColorRole.AlternateBase, QtCore.Qt.lightGray) + palette.setColor(QPalette.ColorRole.Text, QtCore.Qt.black) + app.setPalette(palette) else: app = QApplication.instance() window = ScheduleMainWindow() diff --git a/b_asic/scheduler_gui/ui_main_window.py b/b_asic/scheduler_gui/ui_main_window.py index ec174369..7def5879 100644 --- a/b_asic/scheduler_gui/ui_main_window.py +++ b/b_asic/scheduler_gui/ui_main_window.py @@ -1,293 +1,220 @@ -################################################################################ -## Form generated from reading UI file 'main_window.ui' -## -## Created by: Qt User Interface Compiler version 5.15.8 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ +# Form implementation generated from reading ui file '.\B-ASIC\b_asic\scheduler_gui\main_window.ui' +# +# Created by: PyQt6 UI code generator 6.8.0 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. -from qtpy.QtCore import QSize, QCoreApplication, QRect, QMetaObject -from qtpy.QtGui import QIcon, QColor, QFont, QBrush, Qt, QPainter -from qtpy.QtWidgets import ( - QSizePolicy, - QAction, - QMenu, - QMenuBar, - QToolBar, - QHBoxLayout, - QWidget, - QGraphicsView, - QSplitter, - QTableWidgetItem, - QTableWidget, - QAbstractItemView, - QStatusBar, -) +from qtpy import QtCore, QtGui, QtWidgets -class Ui_MainWindow: + +class Ui_MainWindow(object): def setupUi(self, MainWindow): - if not MainWindow.objectName(): - MainWindow.setObjectName("MainWindow") + MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) - sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) - icon = QIcon() - icon.addFile(":/icons/basic/small_logo.png", QSize(), QIcon.Normal, QIcon.Off) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/basic/small_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) MainWindow.setWindowIcon(icon) - self.menu_load_from_file = QAction(MainWindow) + self.centralwidget = QtWidgets.QWidget(parent=MainWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) + self.centralwidget.setSizePolicy(sizePolicy) + self.centralwidget.setObjectName("centralwidget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.splitter = QtWidgets.QSplitter(parent=self.centralwidget) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.splitter.setHandleWidth(0) + self.splitter.setObjectName("splitter") + self.view = QtWidgets.QGraphicsView(parent=self.splitter) + self.view.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop) + self.view.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing|QtGui.QPainter.RenderHint.TextAntialiasing) + self.view.setViewportUpdateMode(QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate) + self.view.setObjectName("view") + self.info_table = QtWidgets.QTableWidget(parent=self.splitter) + self.info_table.setStyleSheet("alternate-background-color: #fadefb;background-color: #ebebeb;") + self.info_table.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.info_table.setAlternatingRowColors(True) + self.info_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.info_table.setRowCount(2) + self.info_table.setColumnCount(2) + self.info_table.setObjectName("info_table") + item = QtWidgets.QTableWidgetItem() + self.info_table.setVerticalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.info_table.setVerticalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + item.setFont(font) + self.info_table.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter) + self.info_table.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + font.setKerning(True) + item.setFont(font) + brush = QtGui.QBrush(QtGui.QColor(160, 160, 164)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + item.setBackground(brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + item.setForeground(brush) + item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable) + self.info_table.setItem(0, 0, item) + item = QtWidgets.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + item.setFont(font) + brush = QtGui.QBrush(QtGui.QColor(160, 160, 164)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + item.setBackground(brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + item.setForeground(brush) + item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable) + self.info_table.setItem(1, 0, item) + self.info_table.horizontalHeader().setHighlightSections(False) + self.info_table.horizontalHeader().setStretchLastSection(True) + self.info_table.verticalHeader().setVisible(False) + self.info_table.verticalHeader().setDefaultSectionSize(24) + self.horizontalLayout.addWidget(self.splitter) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(parent=MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 20)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(parent=self.menubar) + self.menuFile.setObjectName("menuFile") + self.menu_Recent_Schedule = QtWidgets.QMenu(parent=self.menuFile) + self.menu_Recent_Schedule.setObjectName("menu_Recent_Schedule") + self.menuView = QtWidgets.QMenu(parent=self.menubar) + self.menuView.setObjectName("menuView") + self.menu_view_execution_times = QtWidgets.QMenu(parent=self.menuView) + self.menu_view_execution_times.setEnabled(False) + self.menu_view_execution_times.setObjectName("menu_view_execution_times") + self.menu_Edit = QtWidgets.QMenu(parent=self.menubar) + self.menu_Edit.setObjectName("menu_Edit") + self.menuWindow = QtWidgets.QMenu(parent=self.menubar) + self.menuWindow.setObjectName("menuWindow") + self.menuHelp = QtWidgets.QMenu(parent=self.menubar) + self.menuHelp.setObjectName("menuHelp") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.toolBar = QtWidgets.QToolBar(parent=MainWindow) + self.toolBar.setObjectName("toolBar") + MainWindow.addToolBar(QtCore.Qt.ToolBarArea.TopToolBarArea, self.toolBar) + self.menu_load_from_file = QtGui.QAction(parent=MainWindow) + icon = QtGui.QIcon.fromTheme("document-open-folder") + self.menu_load_from_file.setIcon(icon) + self.menu_load_from_file.setStatusTip("") self.menu_load_from_file.setObjectName("menu_load_from_file") - icon1 = QIcon() - iconThemeName = "document-open-folder" - if QIcon.hasThemeIcon(iconThemeName): - icon1 = QIcon.fromTheme(iconThemeName) - else: - icon1.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off) - - self.menu_load_from_file.setIcon(icon1) - self.menu_save = QAction(MainWindow) - self.menu_save.setObjectName("menu_save") + self.menu_save = QtGui.QAction(parent=MainWindow) self.menu_save.setEnabled(False) - icon2 = QIcon() - iconThemeName = "document-save" - if QIcon.hasThemeIcon(iconThemeName): - icon2 = QIcon.fromTheme(iconThemeName) - else: - icon2.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off) - - self.menu_save.setIcon(icon2) - self.menu_node_info = QAction(MainWindow) - self.menu_node_info.setObjectName("menu_node_info") + icon = QtGui.QIcon.fromTheme("document-save") + self.menu_save.setIcon(icon) + self.menu_save.setObjectName("menu_save") + self.menu_node_info = QtGui.QAction(parent=MainWindow) self.menu_node_info.setCheckable(True) self.menu_node_info.setChecked(True) - icon3 = QIcon() - icon3.addFile(":/icons/misc/right_panel.svg", QSize(), QIcon.Normal, QIcon.Off) - icon3.addFile( - ":/icons/misc/right_filled_panel.svg", QSize(), QIcon.Normal, QIcon.On - ) - self.menu_node_info.setIcon(icon3) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_filled_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On) + self.menu_node_info.setIcon(icon1) self.menu_node_info.setIconVisibleInMenu(False) - self.menu_quit = QAction(MainWindow) + self.menu_node_info.setObjectName("menu_node_info") + self.menu_quit = QtGui.QAction(parent=MainWindow) + icon = QtGui.QIcon.fromTheme("application-exit") + self.menu_quit.setIcon(icon) self.menu_quit.setObjectName("menu_quit") - icon4 = QIcon() - iconThemeName = "application-exit" - if QIcon.hasThemeIcon(iconThemeName): - icon4 = QIcon.fromTheme(iconThemeName) - else: - icon4.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off) - - self.menu_quit.setIcon(icon4) - self.menu_save_as = QAction(MainWindow) - self.menu_save_as.setObjectName("menu_save_as") + self.menu_save_as = QtGui.QAction(parent=MainWindow) self.menu_save_as.setEnabled(False) - icon5 = QIcon() - iconThemeName = "document-save-as" - if QIcon.hasThemeIcon(iconThemeName): - icon5 = QIcon.fromTheme(iconThemeName) - else: - icon5.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off) - - self.menu_save_as.setIcon(icon5) - self.menu_exit_dialog = QAction(MainWindow) - self.menu_exit_dialog.setObjectName("menu_exit_dialog") + icon = QtGui.QIcon.fromTheme("document-save-as") + self.menu_save_as.setIcon(icon) + self.menu_save_as.setObjectName("menu_save_as") + self.menu_exit_dialog = QtGui.QAction(parent=MainWindow) self.menu_exit_dialog.setCheckable(True) self.menu_exit_dialog.setChecked(True) - icon6 = QIcon() - iconThemeName = "view-close" - if QIcon.hasThemeIcon(iconThemeName): - icon6 = QIcon.fromTheme(iconThemeName) - else: - icon6.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off) - - self.menu_exit_dialog.setIcon(icon6) - self.menu_close_schedule = QAction(MainWindow) - self.menu_close_schedule.setObjectName("menu_close_schedule") + icon = QtGui.QIcon.fromTheme("view-close") + self.menu_exit_dialog.setIcon(icon) + self.menu_exit_dialog.setObjectName("menu_exit_dialog") + self.menu_close_schedule = QtGui.QAction(parent=MainWindow) self.menu_close_schedule.setEnabled(False) - self.menu_close_schedule.setIcon(icon6) - self.actionAbout = QAction(MainWindow) + icon = QtGui.QIcon.fromTheme("view-close") + self.menu_close_schedule.setIcon(icon) + self.menu_close_schedule.setObjectName("menu_close_schedule") + self.actionAbout = QtGui.QAction(parent=MainWindow) self.actionAbout.setObjectName("actionAbout") - self.actionDocumentation = QAction(MainWindow) + self.actionDocumentation = QtGui.QAction(parent=MainWindow) self.actionDocumentation.setObjectName("actionDocumentation") - self.actionReorder = QAction(MainWindow) + self.actionReorder = QtGui.QAction(parent=MainWindow) self.actionReorder.setObjectName("actionReorder") - self.actionPlot_schedule = QAction(MainWindow) + self.actionPlot_schedule = QtGui.QAction(parent=MainWindow) self.actionPlot_schedule.setObjectName("actionPlot_schedule") - self.action_view_variables = QAction(MainWindow) - self.action_view_variables.setObjectName("action_view_variables") + self.action_view_variables = QtGui.QAction(parent=MainWindow) self.action_view_variables.setEnabled(False) - self.action_view_port_accesses = QAction(MainWindow) - self.action_view_port_accesses.setObjectName("action_view_port_accesses") + self.action_view_variables.setObjectName("action_view_variables") + self.action_view_port_accesses = QtGui.QAction(parent=MainWindow) self.action_view_port_accesses.setEnabled(False) - self.actionUndo = QAction(MainWindow) - self.actionUndo.setObjectName("actionUndo") + self.action_view_port_accesses.setObjectName("action_view_port_accesses") + self.actionUndo = QtGui.QAction(parent=MainWindow) self.actionUndo.setEnabled(False) - self.actionRedo = QAction(MainWindow) - self.actionRedo.setObjectName("actionRedo") + self.actionUndo.setObjectName("actionUndo") + self.actionRedo = QtGui.QAction(parent=MainWindow) self.actionRedo.setEnabled(False) - self.actionIncrease_time_resolution = QAction(MainWindow) - self.actionIncrease_time_resolution.setObjectName( - "actionIncrease_time_resolution" - ) - self.actionDecrease_time_resolution = QAction(MainWindow) - self.actionDecrease_time_resolution.setObjectName( - "actionDecrease_time_resolution" - ) - self.actionZoom_to_fit = QAction(MainWindow) + self.actionRedo.setObjectName("actionRedo") + self.actionIncrease_time_resolution = QtGui.QAction(parent=MainWindow) + self.actionIncrease_time_resolution.setObjectName("actionIncrease_time_resolution") + self.actionDecrease_time_resolution = QtGui.QAction(parent=MainWindow) + self.actionDecrease_time_resolution.setObjectName("actionDecrease_time_resolution") + self.actionZoom_to_fit = QtGui.QAction(parent=MainWindow) self.actionZoom_to_fit.setObjectName("actionZoom_to_fit") - self.actionStatus_bar = QAction(MainWindow) - self.actionStatus_bar.setObjectName("actionStatus_bar") + self.actionStatus_bar = QtGui.QAction(parent=MainWindow) self.actionStatus_bar.setCheckable(True) self.actionStatus_bar.setChecked(True) - self.actionToolbar = QAction(MainWindow) - self.actionToolbar.setObjectName("actionToolbar") + self.actionStatus_bar.setObjectName("actionStatus_bar") + self.actionToolbar = QtGui.QAction(parent=MainWindow) self.actionToolbar.setCheckable(True) self.actionToolbar.setChecked(True) - self.action_show_port_numbers = QAction(MainWindow) - self.action_show_port_numbers.setObjectName("action_show_port_numbers") + self.actionToolbar.setObjectName("actionToolbar") + self.action_show_port_numbers = QtGui.QAction(parent=MainWindow) self.action_show_port_numbers.setCheckable(True) self.action_show_port_numbers.setChecked(False) self.action_show_port_numbers.setIconVisibleInMenu(False) - self.action_incorrect_execution_time = QAction(MainWindow) - self.action_incorrect_execution_time.setObjectName( - "action_incorrect_execution_time" - ) + self.action_show_port_numbers.setObjectName("action_show_port_numbers") + self.action_incorrect_execution_time = QtGui.QAction(parent=MainWindow) self.action_incorrect_execution_time.setCheckable(True) self.action_incorrect_execution_time.setChecked(True) self.action_incorrect_execution_time.setIconVisibleInMenu(False) - self.menu_open = QAction(MainWindow) + self.action_incorrect_execution_time.setObjectName("action_incorrect_execution_time") + self.menu_open = QtGui.QAction(parent=MainWindow) + icon = QtGui.QIcon.fromTheme("personal") + self.menu_open.setIcon(icon) self.menu_open.setObjectName("menu_open") - icon7 = QIcon(QIcon.fromTheme("personal")) - self.menu_open.setIcon(icon7) - self.actionToggle_full_screen = QAction(MainWindow) - self.actionToggle_full_screen.setObjectName("actionToggle_full_screen") + self.actionToggle_full_screen = QtGui.QAction(parent=MainWindow) self.actionToggle_full_screen.setCheckable(True) - self.actionPreferences = QAction(MainWindow) + self.actionToggle_full_screen.setObjectName("actionToggle_full_screen") + self.actionPreferences = QtGui.QAction(parent=MainWindow) + icon = QtGui.QIcon.fromTheme("preferences-desktop-personal") + self.actionPreferences.setIcon(icon) self.actionPreferences.setObjectName("actionPreferences") - icon8 = QIcon(QIcon.fromTheme("preferences-desktop-personal")) - self.actionPreferences.setIcon(icon8) - self.centralwidget = QWidget(MainWindow) - self.centralwidget.setObjectName("centralwidget") - sizePolicy.setHeightForWidth( - self.centralwidget.sizePolicy().hasHeightForWidth() - ) - self.centralwidget.setSizePolicy(sizePolicy) - self.horizontalLayout = QHBoxLayout(self.centralwidget) - self.horizontalLayout.setSpacing(0) - self.horizontalLayout.setObjectName("horizontalLayout") - self.horizontalLayout.setContentsMargins(0, 0, 0, 0) - self.splitter = QSplitter(self.centralwidget) - self.splitter.setObjectName("splitter") - self.splitter.setOrientation(Qt.Horizontal) - self.splitter.setHandleWidth(0) - self.view = QGraphicsView(self.splitter) - self.view.setObjectName("view") - self.view.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignTop) - self.view.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) - self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) - self.splitter.addWidget(self.view) - self.info_table = QTableWidget(self.splitter) - if self.info_table.columnCount() < 2: - self.info_table.setColumnCount(2) - font = QFont() - font.setBold(False) - font.setWeight(50) - __qtablewidgetitem = QTableWidgetItem() - __qtablewidgetitem.setTextAlignment(Qt.AlignLeading | Qt.AlignVCenter) - __qtablewidgetitem.setFont(font) - self.info_table.setHorizontalHeaderItem(0, __qtablewidgetitem) - __qtablewidgetitem1 = QTableWidgetItem() - __qtablewidgetitem1.setTextAlignment(Qt.AlignLeading | Qt.AlignVCenter) - self.info_table.setHorizontalHeaderItem(1, __qtablewidgetitem1) - if self.info_table.rowCount() < 2: - self.info_table.setRowCount(2) - __qtablewidgetitem2 = QTableWidgetItem() - self.info_table.setVerticalHeaderItem(0, __qtablewidgetitem2) - __qtablewidgetitem3 = QTableWidgetItem() - self.info_table.setVerticalHeaderItem(1, __qtablewidgetitem3) - brush = QBrush(QColor(255, 255, 255, 255)) - brush.setStyle(Qt.SolidPattern) - brush1 = QBrush(QColor(160, 160, 164, 255)) - brush1.setStyle(Qt.SolidPattern) - font1 = QFont() - font1.setBold(False) - font1.setWeight(50) - font1.setKerning(True) - __qtablewidgetitem4 = QTableWidgetItem() - __qtablewidgetitem4.setFont(font1) - __qtablewidgetitem4.setBackground(brush1) - __qtablewidgetitem4.setForeground(brush) - __qtablewidgetitem4.setFlags( - Qt.ItemIsSelectable - | Qt.ItemIsEditable - | Qt.ItemIsDragEnabled - | Qt.ItemIsDropEnabled - | Qt.ItemIsUserCheckable - ) - self.info_table.setItem(0, 0, __qtablewidgetitem4) - __qtablewidgetitem5 = QTableWidgetItem() - __qtablewidgetitem5.setFont(font) - __qtablewidgetitem5.setBackground(brush1) - __qtablewidgetitem5.setForeground(brush) - __qtablewidgetitem5.setFlags( - Qt.ItemIsSelectable - | Qt.ItemIsEditable - | Qt.ItemIsDragEnabled - | Qt.ItemIsDropEnabled - | Qt.ItemIsUserCheckable - ) - self.info_table.setItem(1, 0, __qtablewidgetitem5) - self.info_table.setObjectName("info_table") - self.info_table.setStyleSheet( - "alternate-background-color: #fadefb;background-color: #ebebeb;" - ) - self.info_table.setEditTriggers(QAbstractItemView.NoEditTriggers) - self.info_table.setAlternatingRowColors(True) - self.info_table.setSelectionBehavior(QAbstractItemView.SelectRows) - self.info_table.setRowCount(2) - self.info_table.setColumnCount(2) - self.splitter.addWidget(self.info_table) - self.info_table.horizontalHeader().setHighlightSections(False) - self.info_table.horizontalHeader().setStretchLastSection(True) - self.info_table.verticalHeader().setVisible(False) - self.info_table.verticalHeader().setDefaultSectionSize(24) - - self.horizontalLayout.addWidget(self.splitter) - - MainWindow.setCentralWidget(self.centralwidget) - self.menubar = QMenuBar(MainWindow) - self.menubar.setObjectName("menubar") - self.menubar.setGeometry(QRect(0, 0, 800, 20)) - self.menuFile = QMenu(self.menubar) - self.menuFile.setObjectName("menuFile") - self.menu_Recent_Schedule = QMenu(self.menuFile) - self.menu_Recent_Schedule.setObjectName("menu_Recent_Schedule") - self.menuView = QMenu(self.menubar) - self.menuView.setObjectName("menuView") - self.menu_view_execution_times = QMenu(self.menuView) - self.menu_view_execution_times.setObjectName("menu_view_execution_times") - self.menu_view_execution_times.setEnabled(False) - self.menu_Edit = QMenu(self.menubar) - self.menu_Edit.setObjectName("menu_Edit") - self.menuWindow = QMenu(self.menubar) - self.menuWindow.setObjectName("menuWindow") - self.menuHelp = QMenu(self.menubar) - self.menuHelp.setObjectName("menuHelp") - MainWindow.setMenuBar(self.menubar) - self.statusbar = QStatusBar(MainWindow) - self.statusbar.setObjectName("statusbar") - MainWindow.setStatusBar(self.statusbar) - self.toolBar = QToolBar(MainWindow) - self.toolBar.setObjectName("toolBar") - MainWindow.addToolBar(Qt.TopToolBarArea, self.toolBar) - - self.menubar.addAction(self.menuFile.menuAction()) - self.menubar.addAction(self.menu_Edit.menuAction()) - self.menubar.addAction(self.menuView.menuAction()) - self.menubar.addAction(self.menuWindow.menuAction()) - self.menubar.addAction(self.menuHelp.menuAction()) self.menuFile.addAction(self.menu_open) self.menuFile.addAction(self.menu_Recent_Schedule.menuAction()) self.menuFile.addAction(self.menu_load_from_file) @@ -322,6 +249,11 @@ class Ui_MainWindow: self.menuHelp.addAction(self.actionDocumentation) self.menuHelp.addSeparator() self.menuHelp.addAction(self.actionAbout) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menu_Edit.menuAction()) + self.menubar.addAction(self.menuView.menuAction()) + self.menubar.addAction(self.menuWindow.menuAction()) + self.menubar.addAction(self.menuHelp.menuAction()) self.toolBar.addAction(self.menu_open) self.toolBar.addAction(self.menu_save) self.toolBar.addAction(self.menu_save_as) @@ -335,300 +267,84 @@ class Ui_MainWindow: self.toolBar.addAction(self.actionReorder) self.retranslateUi(MainWindow) - - QMetaObject.connectSlotsByName(MainWindow) - - # setupUi + QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): - self.menu_load_from_file.setText( - QCoreApplication.translate( - "MainWindow", "&Import schedule from file...", None - ) - ) - # if QT_CONFIG(tooltip) - self.menu_load_from_file.setToolTip( - QCoreApplication.translate( - "MainWindow", "Import schedule from python script", None - ) - ) - # endif // QT_CONFIG(tooltip) - # if QT_CONFIG(statustip) - self.menu_load_from_file.setStatusTip("") - # endif // QT_CONFIG(statustip) - # if QT_CONFIG(shortcut) - self.menu_load_from_file.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+I", None) - ) - # endif // QT_CONFIG(shortcut) - self.menu_save.setText(QCoreApplication.translate("MainWindow", "&Save", None)) - # if QT_CONFIG(tooltip) - self.menu_save.setToolTip( - QCoreApplication.translate("MainWindow", "Save schedule", None) - ) - # endif // QT_CONFIG(tooltip) - # if QT_CONFIG(shortcut) - self.menu_save.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+S", None) - ) - # endif // QT_CONFIG(shortcut) - self.menu_node_info.setText( - QCoreApplication.translate("MainWindow", "&Node info", None) - ) - # if QT_CONFIG(tooltip) - self.menu_node_info.setToolTip( - QCoreApplication.translate("MainWindow", "Show/hide node information", None) - ) - # endif // QT_CONFIG(tooltip) - # if QT_CONFIG(shortcut) - self.menu_node_info.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+N", None) - ) - # endif // QT_CONFIG(shortcut) - self.menu_quit.setText(QCoreApplication.translate("MainWindow", "&Quit", None)) - # if QT_CONFIG(shortcut) - self.menu_quit.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+Q", None) - ) - # endif // QT_CONFIG(shortcut) - self.menu_save_as.setText( - QCoreApplication.translate("MainWindow", "Save &as...", None) - ) - # if QT_CONFIG(tooltip) - self.menu_save_as.setToolTip( - QCoreApplication.translate( - "MainWindow", "Save schedule with new file name", None - ) - ) - # endif // QT_CONFIG(tooltip) - # if QT_CONFIG(shortcut) - self.menu_save_as.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+Shift+S", None) - ) - # endif // QT_CONFIG(shortcut) - self.menu_exit_dialog.setText( - QCoreApplication.translate("MainWindow", "&Hide exit dialog", None) - ) - # if QT_CONFIG(tooltip) - self.menu_exit_dialog.setToolTip( - QCoreApplication.translate("MainWindow", "Hide exit dialog", None) - ) - # endif // QT_CONFIG(tooltip) - self.menu_close_schedule.setText( - QCoreApplication.translate("MainWindow", "&Close schedule", None) - ) - # if QT_CONFIG(shortcut) - self.menu_close_schedule.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+W", None) - ) - # endif // QT_CONFIG(shortcut) - self.actionAbout.setText( - QCoreApplication.translate("MainWindow", "&About", None) - ) - # if QT_CONFIG(tooltip) - self.actionAbout.setToolTip( - QCoreApplication.translate("MainWindow", "Open about window", None) - ) - # endif // QT_CONFIG(tooltip) - self.actionDocumentation.setText( - QCoreApplication.translate("MainWindow", "&Documentation", None) - ) - # if QT_CONFIG(tooltip) - self.actionDocumentation.setToolTip( - QCoreApplication.translate("MainWindow", "Open documentation", None) - ) - # endif // QT_CONFIG(tooltip) - self.actionReorder.setText( - QCoreApplication.translate("MainWindow", "Reorder", None) - ) - # if QT_CONFIG(tooltip) - self.actionReorder.setToolTip( - QCoreApplication.translate( - "MainWindow", "Reorder schedule based on start time", None - ) - ) - # endif // QT_CONFIG(tooltip) - # if QT_CONFIG(shortcut) - self.actionReorder.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+R", None) - ) - # endif // QT_CONFIG(shortcut) - self.actionPlot_schedule.setText( - QCoreApplication.translate("MainWindow", "&Plot schedule", None) - ) - # if QT_CONFIG(tooltip) - self.actionPlot_schedule.setToolTip( - QCoreApplication.translate("MainWindow", "Plot schedule", None) - ) - # endif // QT_CONFIG(tooltip) - self.action_view_variables.setText( - QCoreApplication.translate( - "MainWindow", "View execution times of variables", None - ) - ) - # if QT_CONFIG(tooltip) - self.action_view_variables.setToolTip( - QCoreApplication.translate("MainWindow", "View all variables", None) - ) - # endif // QT_CONFIG(tooltip) - self.action_view_port_accesses.setText( - QCoreApplication.translate( - "MainWindow", "View port access statistics", None - ) - ) - # if QT_CONFIG(tooltip) - self.action_view_port_accesses.setToolTip( - QCoreApplication.translate( - "MainWindow", "View port access statistics for storage", None - ) - ) - # endif // QT_CONFIG(tooltip) - self.actionUndo.setText(QCoreApplication.translate("MainWindow", "Undo", None)) - # if QT_CONFIG(shortcut) - self.actionUndo.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+Z", None) - ) - # endif // QT_CONFIG(shortcut) - self.actionRedo.setText(QCoreApplication.translate("MainWindow", "Redo", None)) - # if QT_CONFIG(shortcut) - self.actionRedo.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z", None) - ) - # endif // QT_CONFIG(shortcut) - self.actionIncrease_time_resolution.setText( - QCoreApplication.translate( - "MainWindow", "Increase time resolution...", None - ) - ) - self.actionDecrease_time_resolution.setText( - QCoreApplication.translate( - "MainWindow", "Decrease time resolution...", None - ) - ) - self.actionZoom_to_fit.setText( - QCoreApplication.translate("MainWindow", "Zoom to &fit", None) - ) - self.actionStatus_bar.setText( - QCoreApplication.translate("MainWindow", "&Status bar", None) - ) - # if QT_CONFIG(tooltip) - self.actionStatus_bar.setToolTip( - QCoreApplication.translate("MainWindow", "Show/hide status bar", None) - ) - # endif // QT_CONFIG(tooltip) - self.actionToolbar.setText( - QCoreApplication.translate("MainWindow", "&Toolbar", None) - ) - # if QT_CONFIG(tooltip) - self.actionToolbar.setToolTip( - QCoreApplication.translate("MainWindow", "Show/hide toolbar", None) - ) - # endif // QT_CONFIG(tooltip) - self.action_show_port_numbers.setText( - QCoreApplication.translate("MainWindow", "S&how port numbers", None) - ) - # if QT_CONFIG(tooltip) - self.action_show_port_numbers.setToolTip( - QCoreApplication.translate( - "MainWindow", "Show port numbers of operation", None - ) - ) - # endif // QT_CONFIG(tooltip) - self.action_incorrect_execution_time.setText( - QCoreApplication.translate("MainWindow", "&Incorrect execution time", None) - ) - # if QT_CONFIG(tooltip) - self.action_incorrect_execution_time.setToolTip( - QCoreApplication.translate( - "MainWindow", - "Highlight processes with execution time longer than schedule time", - None, - ) - ) - # endif // QT_CONFIG(tooltip) - self.menu_open.setText( - QCoreApplication.translate("MainWindow", "&Open...", None) - ) - # if QT_CONFIG(tooltip) - self.menu_open.setToolTip( - QCoreApplication.translate( - "MainWindow", "Open previously saved schedule", None - ) - ) - # endif // QT_CONFIG(tooltip) - # if QT_CONFIG(shortcut) - self.menu_open.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+O", None) - ) - # endif // QT_CONFIG(shortcut) - self.actionToggle_full_screen.setText( - QCoreApplication.translate("MainWindow", "Toggle f&ull screen", None) - ) - # if QT_CONFIG(shortcut) - self.actionToggle_full_screen.setShortcut( - QCoreApplication.translate("MainWindow", "F11", None) - ) - # endif // QT_CONFIG(shortcut) - self.actionPreferences.setText( - QCoreApplication.translate("MainWindow", "Preferences", None) - ) - # if QT_CONFIG(tooltip) - self.actionPreferences.setToolTip( - QCoreApplication.translate("MainWindow", "Color and Fonts", None) - ) - # endif // QT_CONFIG(tooltip) - # if QT_CONFIG(shortcut) - self.actionPreferences.setShortcut( - QCoreApplication.translate("MainWindow", "Ctrl+M", None) - ) - # endif // QT_CONFIG(shortcut) - ___qtablewidgetitem = self.info_table.horizontalHeaderItem(0) - ___qtablewidgetitem.setText( - QCoreApplication.translate("MainWindow", "Property", None) - ) - ___qtablewidgetitem1 = self.info_table.horizontalHeaderItem(1) - ___qtablewidgetitem1.setText( - QCoreApplication.translate("MainWindow", "Value", None) - ) - ___qtablewidgetitem2 = self.info_table.verticalHeaderItem(0) - ___qtablewidgetitem2.setText( - QCoreApplication.translate("MainWindow", "1", None) - ) - ___qtablewidgetitem3 = self.info_table.verticalHeaderItem(1) - ___qtablewidgetitem3.setText( - QCoreApplication.translate("MainWindow", "2", None) - ) - + _translate = QtCore.QCoreApplication.translate + item = self.info_table.verticalHeaderItem(0) + item.setText(_translate("MainWindow", "1")) + item = self.info_table.verticalHeaderItem(1) + item.setText(_translate("MainWindow", "2")) + item = self.info_table.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Property")) + item = self.info_table.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Value")) __sortingEnabled = self.info_table.isSortingEnabled() self.info_table.setSortingEnabled(False) - ___qtablewidgetitem4 = self.info_table.item(0, 0) - ___qtablewidgetitem4.setText( - QCoreApplication.translate("MainWindow", "Schedule", None) - ) - ___qtablewidgetitem5 = self.info_table.item(1, 0) - ___qtablewidgetitem5.setText( - QCoreApplication.translate("MainWindow", "Operator", None) - ) + item = self.info_table.item(0, 0) + item.setText(_translate("MainWindow", "Schedule")) + item = self.info_table.item(1, 0) + item.setText(_translate("MainWindow", "Operator")) self.info_table.setSortingEnabled(__sortingEnabled) - - self.menuFile.setTitle(QCoreApplication.translate("MainWindow", "&File", None)) - self.menu_Recent_Schedule.setTitle( - QCoreApplication.translate("MainWindow", "Open &recent", None) - ) - self.menuView.setTitle(QCoreApplication.translate("MainWindow", "&View", None)) - self.menu_view_execution_times.setTitle( - QCoreApplication.translate( - "MainWindow", "View execution times of type", None - ) - ) - self.menu_Edit.setTitle(QCoreApplication.translate("MainWindow", "&Edit", None)) - self.menuWindow.setTitle( - QCoreApplication.translate("MainWindow", "&Window", None) - ) - self.menuHelp.setTitle(QCoreApplication.translate("MainWindow", "&Help", None)) - self.toolBar.setWindowTitle( - QCoreApplication.translate("MainWindow", "toolBar", None) - ) - pass - - # retranslateUi + self.menuFile.setTitle(_translate("MainWindow", "&File")) + self.menu_Recent_Schedule.setTitle(_translate("MainWindow", "Open &recent")) + self.menuView.setTitle(_translate("MainWindow", "&View")) + self.menu_view_execution_times.setTitle(_translate("MainWindow", "View execution times of type")) + self.menu_Edit.setTitle(_translate("MainWindow", "&Edit")) + self.menuWindow.setTitle(_translate("MainWindow", "&Window")) + self.menuHelp.setTitle(_translate("MainWindow", "&Help")) + self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) + self.menu_load_from_file.setText(_translate("MainWindow", "&Import schedule from file...")) + self.menu_load_from_file.setToolTip(_translate("MainWindow", "Import schedule from python script")) + self.menu_load_from_file.setShortcut(_translate("MainWindow", "Ctrl+I")) + self.menu_save.setText(_translate("MainWindow", "&Save")) + self.menu_save.setToolTip(_translate("MainWindow", "Save schedule")) + self.menu_save.setShortcut(_translate("MainWindow", "Ctrl+S")) + self.menu_node_info.setText(_translate("MainWindow", "&Node info")) + self.menu_node_info.setToolTip(_translate("MainWindow", "Show/hide node information")) + self.menu_node_info.setShortcut(_translate("MainWindow", "Ctrl+N")) + self.menu_quit.setText(_translate("MainWindow", "&Quit")) + self.menu_quit.setShortcut(_translate("MainWindow", "Ctrl+Q")) + self.menu_save_as.setText(_translate("MainWindow", "Save &as...")) + self.menu_save_as.setToolTip(_translate("MainWindow", "Save schedule with new file name")) + self.menu_save_as.setShortcut(_translate("MainWindow", "Ctrl+Shift+S")) + self.menu_exit_dialog.setText(_translate("MainWindow", "&Hide exit dialog")) + self.menu_exit_dialog.setToolTip(_translate("MainWindow", "Hide exit dialog")) + self.menu_close_schedule.setText(_translate("MainWindow", "&Close schedule")) + self.menu_close_schedule.setShortcut(_translate("MainWindow", "Ctrl+W")) + self.actionAbout.setText(_translate("MainWindow", "&About")) + self.actionAbout.setToolTip(_translate("MainWindow", "Open about window")) + self.actionDocumentation.setText(_translate("MainWindow", "&Documentation")) + self.actionDocumentation.setToolTip(_translate("MainWindow", "Open documentation")) + self.actionReorder.setText(_translate("MainWindow", "Reorder")) + self.actionReorder.setToolTip(_translate("MainWindow", "Reorder schedule based on start time")) + self.actionReorder.setShortcut(_translate("MainWindow", "Ctrl+R")) + self.actionPlot_schedule.setText(_translate("MainWindow", "&Plot schedule")) + self.actionPlot_schedule.setToolTip(_translate("MainWindow", "Plot schedule")) + self.action_view_variables.setText(_translate("MainWindow", "View execution times of variables")) + self.action_view_variables.setToolTip(_translate("MainWindow", "View all variables")) + self.action_view_port_accesses.setText(_translate("MainWindow", "View port access statistics")) + self.action_view_port_accesses.setToolTip(_translate("MainWindow", "View port access statistics for storage")) + self.actionUndo.setText(_translate("MainWindow", "Undo")) + self.actionUndo.setShortcut(_translate("MainWindow", "Ctrl+Z")) + self.actionRedo.setText(_translate("MainWindow", "Redo")) + self.actionRedo.setShortcut(_translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z")) + self.actionIncrease_time_resolution.setText(_translate("MainWindow", "Increase time resolution...")) + self.actionDecrease_time_resolution.setText(_translate("MainWindow", "Decrease time resolution...")) + self.actionZoom_to_fit.setText(_translate("MainWindow", "Zoom to &fit")) + self.actionStatus_bar.setText(_translate("MainWindow", "&Status bar")) + self.actionStatus_bar.setToolTip(_translate("MainWindow", "Show/hide status bar")) + self.actionToolbar.setText(_translate("MainWindow", "&Toolbar")) + self.actionToolbar.setToolTip(_translate("MainWindow", "Show/hide toolbar")) + self.action_show_port_numbers.setText(_translate("MainWindow", "S&how port numbers")) + self.action_show_port_numbers.setToolTip(_translate("MainWindow", "Show port numbers of operation")) + self.action_incorrect_execution_time.setText(_translate("MainWindow", "&Incorrect execution time")) + self.action_incorrect_execution_time.setToolTip(_translate("MainWindow", "Highlight processes with execution time longer than schedule time")) + self.menu_open.setText(_translate("MainWindow", "&Open...")) + self.menu_open.setToolTip(_translate("MainWindow", "Open previously saved schedule")) + self.menu_open.setShortcut(_translate("MainWindow", "Ctrl+O")) + self.actionToggle_full_screen.setText(_translate("MainWindow", "Toggle f&ull screen")) + self.actionToggle_full_screen.setShortcut(_translate("MainWindow", "F11")) + self.actionPreferences.setText(_translate("MainWindow", "Preferences")) + self.actionPreferences.setToolTip(_translate("MainWindow", "Color and Fonts")) + self.actionPreferences.setShortcut(_translate("MainWindow", "Ctrl+M")) -- GitLab From bf03b089c551e8177ccc78bc45e39cc8cd96f4ed Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Wed, 22 Jan 2025 15:53:13 +0100 Subject: [PATCH 02/21] fixes from last time, also ran post-commit on all files --- b_asic/scheduler_gui/main_window.py | 8 +- b_asic/scheduler_gui/ui_main_window.py | 180 +++++++++++++++++++------ 2 files changed, 144 insertions(+), 44 deletions(-) diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py index 4de6e4cd..f4502f99 100644 --- a/b_asic/scheduler_gui/main_window.py +++ b/b_asic/scheduler_gui/main_window.py @@ -98,9 +98,9 @@ if __debug__: log.debug(f"Qt version (compile time): {QtCore.__version__}") log.debug(f"QT_API: {QT_API}") if QT_API.lower().startswith("pyside"): - import PySide6 + import PySide2 - log.debug(f"PySide version: {PySide6.__version__}") + log.debug(f"PySide version: {PySide2.__version__}") if QT_API.lower().startswith("pyqt"): from qtpy.QtCore import PYQT_VERSION_STR @@ -1694,8 +1694,8 @@ def start_scheduler(schedule: Optional[Schedule] = None) -> Optional[Schedule]: palette.setColor(QPalette.ColorRole.Window, QtCore.Qt.white) palette.setColor(QPalette.ColorRole.WindowText, QtCore.Qt.black) palette.setColor(QPalette.ColorRole.ButtonText, QtCore.Qt.black) - palette.setColor(QPalette.ColorRole.Base, QtCore.Qt.white) - palette.setColor(QPalette.ColorRole.AlternateBase, QtCore.Qt.lightGray) + palette.setColor(QPalette.ColorRole.Base, QtCore.Qt.white) + palette.setColor(QPalette.ColorRole.AlternateBase, QtCore.Qt.lightGray) palette.setColor(QPalette.ColorRole.Text, QtCore.Qt.black) app.setPalette(palette) else: diff --git a/b_asic/scheduler_gui/ui_main_window.py b/b_asic/scheduler_gui/ui_main_window.py index 7def5879..ad3fa898 100644 --- a/b_asic/scheduler_gui/ui_main_window.py +++ b/b_asic/scheduler_gui/ui_main_window.py @@ -9,23 +9,35 @@ from qtpy import QtCore, QtGui, QtWidgets -class Ui_MainWindow(object): +class Ui_MainWindow: def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/icons/basic/small_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) + icon.addPixmap( + QtGui.QPixmap(":/icons/basic/small_logo.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) MainWindow.setWindowIcon(icon) self.centralwidget = QtWidgets.QWidget(parent=MainWindow) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Preferred, + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.centralwidget.sizePolicy().hasHeightForWidth() + ) self.centralwidget.setSizePolicy(sizePolicy) self.centralwidget.setObjectName("centralwidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget) @@ -37,15 +49,30 @@ class Ui_MainWindow(object): self.splitter.setHandleWidth(0) self.splitter.setObjectName("splitter") self.view = QtWidgets.QGraphicsView(parent=self.splitter) - self.view.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop) - self.view.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing|QtGui.QPainter.RenderHint.TextAntialiasing) - self.view.setViewportUpdateMode(QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate) + self.view.setAlignment( + QtCore.Qt.AlignmentFlag.AlignLeading + | QtCore.Qt.AlignmentFlag.AlignLeft + | QtCore.Qt.AlignmentFlag.AlignTop + ) + self.view.setRenderHints( + QtGui.QPainter.RenderHint.Antialiasing + | QtGui.QPainter.RenderHint.TextAntialiasing + ) + self.view.setViewportUpdateMode( + QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate + ) self.view.setObjectName("view") self.info_table = QtWidgets.QTableWidget(parent=self.splitter) - self.info_table.setStyleSheet("alternate-background-color: #fadefb;background-color: #ebebeb;") - self.info_table.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.info_table.setStyleSheet( + "alternate-background-color: #fadefb;background-color: #ebebeb;" + ) + self.info_table.setEditTriggers( + QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers + ) self.info_table.setAlternatingRowColors(True) - self.info_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.info_table.setSelectionBehavior( + QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows + ) self.info_table.setRowCount(2) self.info_table.setColumnCount(2) self.info_table.setObjectName("info_table") @@ -54,14 +81,18 @@ class Ui_MainWindow(object): item = QtWidgets.QTableWidgetItem() self.info_table.setVerticalHeaderItem(1, item) item = QtWidgets.QTableWidgetItem() - item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter) + item.setTextAlignment( + QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignVCenter + ) font = QtGui.QFont() font.setBold(False) font.setWeight(50) item.setFont(font) self.info_table.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() - item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter) + item.setTextAlignment( + QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignVCenter + ) self.info_table.setHorizontalHeaderItem(1, item) item = QtWidgets.QTableWidgetItem() font = QtGui.QFont() @@ -75,7 +106,13 @@ class Ui_MainWindow(object): brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) item.setForeground(brush) - item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable) + item.setFlags( + QtCore.Qt.ItemFlag.ItemIsSelectable + | QtCore.Qt.ItemFlag.ItemIsEditable + | QtCore.Qt.ItemFlag.ItemIsDragEnabled + | QtCore.Qt.ItemFlag.ItemIsDropEnabled + | QtCore.Qt.ItemFlag.ItemIsUserCheckable + ) self.info_table.setItem(0, 0, item) item = QtWidgets.QTableWidgetItem() font = QtGui.QFont() @@ -88,7 +125,13 @@ class Ui_MainWindow(object): brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) item.setForeground(brush) - item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable) + item.setFlags( + QtCore.Qt.ItemFlag.ItemIsSelectable + | QtCore.Qt.ItemFlag.ItemIsEditable + | QtCore.Qt.ItemFlag.ItemIsDragEnabled + | QtCore.Qt.ItemFlag.ItemIsDropEnabled + | QtCore.Qt.ItemFlag.ItemIsUserCheckable + ) self.info_table.setItem(1, 0, item) self.info_table.horizontalHeader().setHighlightSections(False) self.info_table.horizontalHeader().setStretchLastSection(True) @@ -135,8 +178,16 @@ class Ui_MainWindow(object): self.menu_node_info.setCheckable(True) self.menu_node_info.setChecked(True) icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) - icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_filled_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On) + icon1.addPixmap( + QtGui.QPixmap(":/icons/misc/right_panel.svg"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) + icon1.addPixmap( + QtGui.QPixmap(":/icons/misc/right_filled_panel.svg"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.On, + ) self.menu_node_info.setIcon(icon1) self.menu_node_info.setIconVisibleInMenu(False) self.menu_node_info.setObjectName("menu_node_info") @@ -181,9 +232,13 @@ class Ui_MainWindow(object): self.actionRedo.setEnabled(False) self.actionRedo.setObjectName("actionRedo") self.actionIncrease_time_resolution = QtGui.QAction(parent=MainWindow) - self.actionIncrease_time_resolution.setObjectName("actionIncrease_time_resolution") + self.actionIncrease_time_resolution.setObjectName( + "actionIncrease_time_resolution" + ) self.actionDecrease_time_resolution = QtGui.QAction(parent=MainWindow) - self.actionDecrease_time_resolution.setObjectName("actionDecrease_time_resolution") + self.actionDecrease_time_resolution.setObjectName( + "actionDecrease_time_resolution" + ) self.actionZoom_to_fit = QtGui.QAction(parent=MainWindow) self.actionZoom_to_fit.setObjectName("actionZoom_to_fit") self.actionStatus_bar = QtGui.QAction(parent=MainWindow) @@ -203,7 +258,9 @@ class Ui_MainWindow(object): self.action_incorrect_execution_time.setCheckable(True) self.action_incorrect_execution_time.setChecked(True) self.action_incorrect_execution_time.setIconVisibleInMenu(False) - self.action_incorrect_execution_time.setObjectName("action_incorrect_execution_time") + self.action_incorrect_execution_time.setObjectName( + "action_incorrect_execution_time" + ) self.menu_open = QtGui.QAction(parent=MainWindow) icon = QtGui.QIcon.fromTheme("personal") self.menu_open.setIcon(icon) @@ -289,24 +346,34 @@ class Ui_MainWindow(object): self.menuFile.setTitle(_translate("MainWindow", "&File")) self.menu_Recent_Schedule.setTitle(_translate("MainWindow", "Open &recent")) self.menuView.setTitle(_translate("MainWindow", "&View")) - self.menu_view_execution_times.setTitle(_translate("MainWindow", "View execution times of type")) + self.menu_view_execution_times.setTitle( + _translate("MainWindow", "View execution times of type") + ) self.menu_Edit.setTitle(_translate("MainWindow", "&Edit")) self.menuWindow.setTitle(_translate("MainWindow", "&Window")) self.menuHelp.setTitle(_translate("MainWindow", "&Help")) self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) - self.menu_load_from_file.setText(_translate("MainWindow", "&Import schedule from file...")) - self.menu_load_from_file.setToolTip(_translate("MainWindow", "Import schedule from python script")) + self.menu_load_from_file.setText( + _translate("MainWindow", "&Import schedule from file...") + ) + self.menu_load_from_file.setToolTip( + _translate("MainWindow", "Import schedule from python script") + ) self.menu_load_from_file.setShortcut(_translate("MainWindow", "Ctrl+I")) self.menu_save.setText(_translate("MainWindow", "&Save")) self.menu_save.setToolTip(_translate("MainWindow", "Save schedule")) self.menu_save.setShortcut(_translate("MainWindow", "Ctrl+S")) self.menu_node_info.setText(_translate("MainWindow", "&Node info")) - self.menu_node_info.setToolTip(_translate("MainWindow", "Show/hide node information")) + self.menu_node_info.setToolTip( + _translate("MainWindow", "Show/hide node information") + ) self.menu_node_info.setShortcut(_translate("MainWindow", "Ctrl+N")) self.menu_quit.setText(_translate("MainWindow", "&Quit")) self.menu_quit.setShortcut(_translate("MainWindow", "Ctrl+Q")) self.menu_save_as.setText(_translate("MainWindow", "Save &as...")) - self.menu_save_as.setToolTip(_translate("MainWindow", "Save schedule with new file name")) + self.menu_save_as.setToolTip( + _translate("MainWindow", "Save schedule with new file name") + ) self.menu_save_as.setShortcut(_translate("MainWindow", "Ctrl+Shift+S")) self.menu_exit_dialog.setText(_translate("MainWindow", "&Hide exit dialog")) self.menu_exit_dialog.setToolTip(_translate("MainWindow", "Hide exit dialog")) @@ -315,35 +382,68 @@ class Ui_MainWindow(object): self.actionAbout.setText(_translate("MainWindow", "&About")) self.actionAbout.setToolTip(_translate("MainWindow", "Open about window")) self.actionDocumentation.setText(_translate("MainWindow", "&Documentation")) - self.actionDocumentation.setToolTip(_translate("MainWindow", "Open documentation")) + self.actionDocumentation.setToolTip( + _translate("MainWindow", "Open documentation") + ) self.actionReorder.setText(_translate("MainWindow", "Reorder")) - self.actionReorder.setToolTip(_translate("MainWindow", "Reorder schedule based on start time")) + self.actionReorder.setToolTip( + _translate("MainWindow", "Reorder schedule based on start time") + ) self.actionReorder.setShortcut(_translate("MainWindow", "Ctrl+R")) self.actionPlot_schedule.setText(_translate("MainWindow", "&Plot schedule")) self.actionPlot_schedule.setToolTip(_translate("MainWindow", "Plot schedule")) - self.action_view_variables.setText(_translate("MainWindow", "View execution times of variables")) - self.action_view_variables.setToolTip(_translate("MainWindow", "View all variables")) - self.action_view_port_accesses.setText(_translate("MainWindow", "View port access statistics")) - self.action_view_port_accesses.setToolTip(_translate("MainWindow", "View port access statistics for storage")) + self.action_view_variables.setText( + _translate("MainWindow", "View execution times of variables") + ) + self.action_view_variables.setToolTip( + _translate("MainWindow", "View all variables") + ) + self.action_view_port_accesses.setText( + _translate("MainWindow", "View port access statistics") + ) + self.action_view_port_accesses.setToolTip( + _translate("MainWindow", "View port access statistics for storage") + ) self.actionUndo.setText(_translate("MainWindow", "Undo")) self.actionUndo.setShortcut(_translate("MainWindow", "Ctrl+Z")) self.actionRedo.setText(_translate("MainWindow", "Redo")) self.actionRedo.setShortcut(_translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z")) - self.actionIncrease_time_resolution.setText(_translate("MainWindow", "Increase time resolution...")) - self.actionDecrease_time_resolution.setText(_translate("MainWindow", "Decrease time resolution...")) + self.actionIncrease_time_resolution.setText( + _translate("MainWindow", "Increase time resolution...") + ) + self.actionDecrease_time_resolution.setText( + _translate("MainWindow", "Decrease time resolution...") + ) self.actionZoom_to_fit.setText(_translate("MainWindow", "Zoom to &fit")) self.actionStatus_bar.setText(_translate("MainWindow", "&Status bar")) - self.actionStatus_bar.setToolTip(_translate("MainWindow", "Show/hide status bar")) + self.actionStatus_bar.setToolTip( + _translate("MainWindow", "Show/hide status bar") + ) self.actionToolbar.setText(_translate("MainWindow", "&Toolbar")) self.actionToolbar.setToolTip(_translate("MainWindow", "Show/hide toolbar")) - self.action_show_port_numbers.setText(_translate("MainWindow", "S&how port numbers")) - self.action_show_port_numbers.setToolTip(_translate("MainWindow", "Show port numbers of operation")) - self.action_incorrect_execution_time.setText(_translate("MainWindow", "&Incorrect execution time")) - self.action_incorrect_execution_time.setToolTip(_translate("MainWindow", "Highlight processes with execution time longer than schedule time")) + self.action_show_port_numbers.setText( + _translate("MainWindow", "S&how port numbers") + ) + self.action_show_port_numbers.setToolTip( + _translate("MainWindow", "Show port numbers of operation") + ) + self.action_incorrect_execution_time.setText( + _translate("MainWindow", "&Incorrect execution time") + ) + self.action_incorrect_execution_time.setToolTip( + _translate( + "MainWindow", + "Highlight processes with execution time longer than schedule time", + ) + ) self.menu_open.setText(_translate("MainWindow", "&Open...")) - self.menu_open.setToolTip(_translate("MainWindow", "Open previously saved schedule")) + self.menu_open.setToolTip( + _translate("MainWindow", "Open previously saved schedule") + ) self.menu_open.setShortcut(_translate("MainWindow", "Ctrl+O")) - self.actionToggle_full_screen.setText(_translate("MainWindow", "Toggle f&ull screen")) + self.actionToggle_full_screen.setText( + _translate("MainWindow", "Toggle f&ull screen") + ) self.actionToggle_full_screen.setShortcut(_translate("MainWindow", "F11")) self.actionPreferences.setText(_translate("MainWindow", "Preferences")) self.actionPreferences.setToolTip(_translate("MainWindow", "Color and Fonts")) -- GitLab From 6fd1f5f987fc6c190e7ce40c6822d080c26d8e3f Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Wed, 22 Jan 2025 15:03:18 +0000 Subject: [PATCH 03/21] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 32946f44..2e59a32d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -91,6 +91,12 @@ run-test-3.12-pyqt5: image: python:3.12 extends: ".run-test" +run-test-3.12-pyqt6: + variables: + QT_API: pyqt6 + image: python:3.12 + extends: ".run-test" + # Seemingly works with Qt6, but tests stall on closing scheduler GUI due to modal dialog(?) #run-test-3.10-pyside6: # variables: -- GitLab From 97342c36a63c7917c270d18ef84e071fbedb4585 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Thu, 23 Jan 2025 16:11:05 +0100 Subject: [PATCH 04/21] moved alap and asap to seperate class and changed some of the code --- b_asic/schedule.py | 386 +++++++++++++++++++++++---------- b_asic/scheduling_algorithm.py | 8 + 2 files changed, 274 insertions(+), 120 deletions(-) create mode 100644 b_asic/scheduling_algorithm.py diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 4b34d580..3f8a0592 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -36,6 +36,7 @@ from b_asic.resources import ProcessCollection from b_asic.signal_flow_graph import SFG from b_asic.special_operations import Delay, Input, Output from b_asic.types import TypeName +from b_asic.scheduling_algorithm import SchedAlg # Need RGB from 0 to 1 _EXECUTION_TIME_COLOR: Tuple[float, ...] = tuple( @@ -68,13 +69,8 @@ class Schedule: algorithm. cyclic : bool, default: False If the schedule is cyclic. - algorithm : {'ASAP', 'ALAP', 'provided'}, default: 'ASAP' - The scheduling algorithm to use. The following algorithm are available: - - * ``'ASAP'``: As-soon-as-possible scheduling. - * ``'ALAP'``: As-late-as-possible scheduling. - - If 'provided', use provided *start_times* and *laps* dictionaries. + algorithm : SchedulingAlgorithm, default: 'ASAP' + The scheduling algorithm to use. start_times : dict, optional Dictionary with GraphIDs as keys and start times as values. Used when *algorithm* is 'provided'. @@ -100,7 +96,7 @@ class Schedule: sfg: SFG, schedule_time: Optional[int] = None, cyclic: bool = False, - algorithm: Literal["ASAP", "ALAP", "provided"] = "ASAP", + algorithm: SchedAlg = "ASAP", start_times: Optional[Dict[GraphID, int]] = None, laps: Optional[Dict[GraphID, int]] = None, max_resources: Optional[Dict[TypeName, int]] = None, @@ -115,10 +111,14 @@ class Schedule: self._cyclic = cyclic self._y_locations = defaultdict(_y_locations_default) self._schedule_time = schedule_time + + self.scheduler = Scheduler(self) if algorithm == "ASAP": - self._schedule_asap() + self.scheduler.schedule_asap() elif algorithm == "ALAP": - self._schedule_alap() + self.scheduler.schedule_alap() + elif algorithm == "earliest_deadline": + self.scheduler.schedule_earliest_deadline() elif algorithm == "provided": if start_times is None: raise ValueError("Must provide start_times when using 'provided'") @@ -797,116 +797,116 @@ class Schedule: new_sfg = new_sfg.insert_operation_before(op, Delay(), port) return new_sfg() - def _schedule_alap(self) -> None: - """Schedule the operations using as-late-as-possible scheduling.""" - precedence_list = self._sfg.get_precedence_list() - self._schedule_asap() - max_end_time = self.get_max_end_time() - - if self.schedule_time is None: - self._schedule_time = max_end_time - elif self.schedule_time < max_end_time: - raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.") - - for output in self._sfg.find_by_type_name(Output.type_name()): - output = cast(Output, output) - self.move_operation_alap(output.graph_id) - for step in reversed(precedence_list): - graph_ids = { - outport.operation.graph_id - for outport in step - if not isinstance(outport.operation, Delay) - } - for graph_id in graph_ids: - self.move_operation_alap(graph_id) - - def _schedule_asap(self) -> None: - """Schedule the operations using as-soon-as-possible scheduling.""" - precedence_list = self._sfg.get_precedence_list() - - if len(precedence_list) < 2: - raise ValueError("Empty signal flow graph cannot be scheduled.") - - non_schedulable_ops = set() - for outport in precedence_list[0]: - operation = outport.operation - if operation.type_name() not in [Delay.type_name()]: - if operation.graph_id not in self._start_times: - # Set start time of all operations in the first iter to 0 - self._start_times[operation.graph_id] = 0 - else: - non_schedulable_ops.add(operation.graph_id) - - for outport in precedence_list[1]: - operation = outport.operation - if operation.graph_id not in self._start_times: - # Set start time of all operations in the first iter to 0 - self._start_times[operation.graph_id] = 0 - - for outports in precedence_list[2:]: - for outport in outports: - operation = outport.operation - if operation.graph_id not in self._start_times: - # Schedule the operation if it does not have a start time yet. - op_start_time = 0 - for current_input in operation.inputs: - if len(current_input.signals) != 1: - raise ValueError( - "Error in scheduling, dangling input port detected." - ) - if current_input.signals[0].source is None: - raise ValueError( - "Error in scheduling, signal with no source detected." - ) - source_port = current_input.signals[0].source - - if source_port.operation.graph_id in non_schedulable_ops: - source_end_time = 0 - else: - source_op_time = self._start_times[ - source_port.operation.graph_id - ] - - if source_port.latency_offset is None: - raise ValueError( - f"Output port {source_port.index} of" - " operation" - f" {source_port.operation.graph_id} has no" - " latency-offset." - ) - - source_end_time = ( - source_op_time + source_port.latency_offset - ) - - if current_input.latency_offset is None: - raise ValueError( - f"Input port {current_input.index} of operation" - f" {current_input.operation.graph_id} has no" - " latency-offset." - ) - op_start_time_from_in = ( - source_end_time - current_input.latency_offset - ) - op_start_time = max(op_start_time, op_start_time_from_in) - - self._start_times[operation.graph_id] = op_start_time - for output in self._sfg.find_by_type_name(Output.type_name()): - output = cast(Output, output) - source_port = cast(OutputPort, output.inputs[0].signals[0].source) - if source_port.operation.graph_id in non_schedulable_ops: - self._start_times[output.graph_id] = 0 - else: - if source_port.latency_offset is None: - raise ValueError( - f"Output port {source_port.index} of operation" - f" {source_port.operation.graph_id} has no" - " latency-offset." - ) - self._start_times[output.graph_id] = self._start_times[ - source_port.operation.graph_id - ] + cast(int, source_port.latency_offset) - self._remove_delays() + # def _schedule_alap(self) -> None: + # """Schedule the operations using as-late-as-possible scheduling.""" + # precedence_list = self._sfg.get_precedence_list() + # self._schedule_asap() + # max_end_time = self.get_max_end_time() + + # if self.schedule_time is None: + # self._schedule_time = max_end_time + # elif self.schedule_time < max_end_time: + # raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.") + + # for output in self._sfg.find_by_type_name(Output.type_name()): + # output = cast(Output, output) + # self.move_operation_alap(output.graph_id) + # for step in reversed(precedence_list): + # graph_ids = { + # outport.operation.graph_id + # for outport in step + # if not isinstance(outport.operation, Delay) + # } + # for graph_id in graph_ids: + # self.move_operation_alap(graph_id) + + # def _schedule_asap(self) -> None: + # """Schedule the operations using as-soon-as-possible scheduling.""" + # precedence_list = self._sfg.get_precedence_list() + + # if len(precedence_list) < 2: + # raise ValueError("Empty signal flow graph cannot be scheduled.") + + # non_schedulable_ops = set() + # for outport in precedence_list[0]: + # operation = outport.operation + # if operation.type_name() not in [Delay.type_name()]: + # if operation.graph_id not in self._start_times: + # # Set start time of all operations in the first iter to 0 + # self._start_times[operation.graph_id] = 0 + # else: + # non_schedulable_ops.add(operation.graph_id) + + # for outport in precedence_list[1]: + # operation = outport.operation + # if operation.graph_id not in self._start_times: + # # Set start time of all operations in the first iter to 0 + # self._start_times[operation.graph_id] = 0 + + # for outports in precedence_list[2:]: + # for outport in outports: + # operation = outport.operation + # if operation.graph_id not in self._start_times: + # # Schedule the operation if it does not have a start time yet. + # op_start_time = 0 + # for current_input in operation.inputs: + # if len(current_input.signals) != 1: + # raise ValueError( + # "Error in scheduling, dangling input port detected." + # ) + # if current_input.signals[0].source is None: + # raise ValueError( + # "Error in scheduling, signal with no source detected." + # ) + # source_port = current_input.signals[0].source + + # if source_port.operation.graph_id in non_schedulable_ops: + # source_end_time = 0 + # else: + # source_op_time = self._start_times[ + # source_port.operation.graph_id + # ] + + # if source_port.latency_offset is None: + # raise ValueError( + # f"Output port {source_port.index} of" + # " operation" + # f" {source_port.operation.graph_id} has no" + # " latency-offset." + # ) + + # source_end_time = ( + # source_op_time + source_port.latency_offset + # ) + + # if current_input.latency_offset is None: + # raise ValueError( + # f"Input port {current_input.index} of operation" + # f" {current_input.operation.graph_id} has no" + # " latency-offset." + # ) + # op_start_time_from_in = ( + # source_end_time - current_input.latency_offset + # ) + # op_start_time = max(op_start_time, op_start_time_from_in) + + # self._start_times[operation.graph_id] = op_start_time + # for output in self._sfg.find_by_type_name(Output.type_name()): + # output = cast(Output, output) + # source_port = cast(OutputPort, output.inputs[0].signals[0].source) + # if source_port.operation.graph_id in non_schedulable_ops: + # self._start_times[output.graph_id] = 0 + # else: + # if source_port.latency_offset is None: + # raise ValueError( + # f"Output port {source_port.index} of operation" + # f" {source_port.operation.graph_id} has no" + # " latency-offset." + # ) + # self._start_times[output.graph_id] = self._start_times[ + # source_port.operation.graph_id + # ] + cast(int, source_port.latency_offset) + # self._remove_delays() def _get_memory_variables_list(self) -> List[MemoryVariable]: ret: List[MemoryVariable] = [] @@ -1227,3 +1227,149 @@ class Schedule: # SVG is valid HTML. This is useful for e.g. sphinx-gallery _repr_html_ = _repr_svg_ + + +class Scheduler(): + def __init__(self, schedule: Schedule) -> None: + self.schedule = schedule + + def schedule_asap(self) -> None: + """Schedule the operations using as-soon-as-possible scheduling.""" + sched = self.schedule + prec_list = sched.sfg.get_precedence_list() + if len(prec_list) < 2: + raise ValueError("Empty signal flow graph cannot be scheduled.") + + # handle the first set in precedence graph (input and delays) + non_schedulable_ops = set() + for outport in prec_list[0]: + operation = outport.operation + if operation.type_name() == Delay.type_name(): + non_schedulable_ops.add(operation.graph_id) + elif operation.graph_id not in sched._start_times: + sched._start_times[operation.graph_id] = 0 + + # handle second set in precedence graph (first operations) + for outport in prec_list[1]: + operation = outport.operation + if operation.graph_id not in sched._start_times: + sched._start_times[operation.graph_id] = 0 + + # handle the remaining sets + for outports in prec_list[2:]: + for outport in outports: + operation = outport.operation + if operation.graph_id not in sched._start_times: + op_start_time = 0 + for current_input in operation.inputs: + if len(current_input.signals) != 1: + raise ValueError( + "Error in scheduling, dangling input port detected." + ) + if current_input.signals[0].source is None: + raise ValueError( + "Error in scheduling, signal with no source detected." + ) + source_port = current_input.signals[0].source + + if source_port.operation.graph_id in non_schedulable_ops: + source_end_time = 0 + else: + source_op_time = sched._start_times[ + source_port.operation.graph_id + ] + + if source_port.latency_offset is None: + raise ValueError( + f"Output port {source_port.index} of" + " operation" + f" {source_port.operation.graph_id} has no" + " latency-offset." + ) + + source_end_time = ( + source_op_time + source_port.latency_offset + ) + + if current_input.latency_offset is None: + raise ValueError( + f"Input port {current_input.index} of operation" + f" {current_input.operation.graph_id} has no" + " latency-offset." + ) + op_start_time_from_in = ( + source_end_time - current_input.latency_offset + ) + op_start_time = max(op_start_time, op_start_time_from_in) + + sched._start_times[operation.graph_id] = op_start_time + + # handle output and remove delays + for output in sched._sfg.find_by_type_name(Output.type_name()): + output = cast(Output, output) + source_port = cast(OutputPort, output.inputs[0].signals[0].source) + if source_port.operation.graph_id in non_schedulable_ops: + sched._start_times[output.graph_id] = 0 + else: + if source_port.latency_offset is None: + raise ValueError( + f"Output port {source_port.index} of operation" + f" {source_port.operation.graph_id} has no" + " latency-offset." + ) + sched._start_times[output.graph_id] = sched._start_times[ + source_port.operation.graph_id + ] + cast(int, source_port.latency_offset) + sched._remove_delays() + + def schedule_alap(self) -> None: + """Schedule the operations using as-late-as-possible scheduling.""" + self.schedule_asap() + sched = self.schedule + max_end_time = sched.get_max_end_time() + + if sched.schedule_time is None: + sched.set_schedule_time(max_end_time) + elif sched.schedule_time < max_end_time: + raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.") + + # move all outputs ALAP before operations + for output in sched.sfg.find_by_type_name(Output.type_name()): + output = cast(Output, output) + sched.move_operation_alap(output.graph_id) + + # move all operations ALAP + for step in reversed(sched.sfg.get_precedence_list()): + for outport in step: + if not isinstance(outport.operation, Delay): + sched.move_operation_alap(outport.operation.graph_id) + + def schedule_earliest_deadline(self) -> None: + """Schedule the operations using earliest deadline scheduling.""" + pass + # sched = self.schedule + # prec_list = sched.sfg.get_precedence_list() + # if len(prec_list) < 2: + # raise ValueError("Empty signal flow graph cannot be scheduled.") + + # # handle the first set in precedence graph (input and delays) + # non_schedulable_ops = set() + # for outport in prec_list[0]: + # operation = outport.operation + # if operation.type_name() == Delay.type_name(): + # non_schedulable_ops.add(operation.graph_id) + # elif operation.graph_id not in sched._start_times: + # sched._start_times[operation.graph_id] = 0 + + # # handle second set in precedence graph (first operations) + # for outport in prec_list[1]: + # operation = outport.operation + # if operation.graph_id not in sched._start_times: + # sched._start_times[operation.graph_id] = 0 + + # # handle the remaining sets + # for outports in prec_list[2:]: + # for outport in outports: + # operation = outport.operation + # if operation.graph_id not in sched._start_times: + # pass \ No newline at end of file diff --git a/b_asic/scheduling_algorithm.py b/b_asic/scheduling_algorithm.py new file mode 100644 index 00000000..8a1dbcd3 --- /dev/null +++ b/b_asic/scheduling_algorithm.py @@ -0,0 +1,8 @@ +from enum import Enum + +class SchedAlg(Enum): + ASAP = "ASAP" + ALAP = "ALAP" + EARLIEST_DEADLINE = "earliest_deadline" + LEAST_SLACK = "least_slack" + PROVIDED = "provided" -- GitLab From eb4a5de84b262910184d0c9dcda83f119612667d Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Thu, 23 Jan 2025 16:26:43 +0100 Subject: [PATCH 05/21] linting fixes --- b_asic/schedule.py | 16 ++++++++-------- b_asic/scheduling_algorithm.py | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 3f8a0592..86eaba91 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -7,7 +7,7 @@ Contains the schedule class for scheduling operations in an SFG. import io import sys from collections import defaultdict -from typing import Dict, List, Literal, Optional, Sequence, Tuple, cast +from typing import Dict, List, Optional, Sequence, Tuple, cast import matplotlib.pyplot as plt import numpy as np @@ -33,10 +33,10 @@ from b_asic.operation import Operation from b_asic.port import InputPort, OutputPort from b_asic.process import MemoryVariable, OperatorProcess from b_asic.resources import ProcessCollection +from b_asic.scheduling_algorithm import SchedAlg from b_asic.signal_flow_graph import SFG from b_asic.special_operations import Delay, Input, Output from b_asic.types import TypeName -from b_asic.scheduling_algorithm import SchedAlg # Need RGB from 0 to 1 _EXECUTION_TIME_COLOR: Tuple[float, ...] = tuple( @@ -1229,10 +1229,10 @@ class Schedule: _repr_html_ = _repr_svg_ -class Scheduler(): +class Scheduler: def __init__(self, schedule: Schedule) -> None: self.schedule = schedule - + def schedule_asap(self) -> None: """Schedule the operations using as-soon-as-possible scheduling.""" sched = self.schedule @@ -1303,7 +1303,7 @@ class Scheduler(): op_start_time = max(op_start_time, op_start_time_from_in) sched._start_times[operation.graph_id] = op_start_time - + # handle output and remove delays for output in sched._sfg.find_by_type_name(Output.type_name()): output = cast(Output, output) @@ -1337,7 +1337,7 @@ class Scheduler(): for output in sched.sfg.find_by_type_name(Output.type_name()): output = cast(Output, output) sched.move_operation_alap(output.graph_id) - + # move all operations ALAP for step in reversed(sched.sfg.get_precedence_list()): for outport in step: @@ -1366,10 +1366,10 @@ class Scheduler(): # operation = outport.operation # if operation.graph_id not in sched._start_times: # sched._start_times[operation.graph_id] = 0 - + # # handle the remaining sets # for outports in prec_list[2:]: # for outport in outports: # operation = outport.operation # if operation.graph_id not in sched._start_times: - # pass \ No newline at end of file + # pass diff --git a/b_asic/scheduling_algorithm.py b/b_asic/scheduling_algorithm.py index 8a1dbcd3..c6787a73 100644 --- a/b_asic/scheduling_algorithm.py +++ b/b_asic/scheduling_algorithm.py @@ -1,5 +1,6 @@ from enum import Enum + class SchedAlg(Enum): ASAP = "ASAP" ALAP = "ALAP" -- GitLab From c6c95908ada00ba951ceab486ce2d17cabfa69c8 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Fri, 24 Jan 2025 16:50:52 +0100 Subject: [PATCH 06/21] post commit --- b_asic/schedule.py | 126 +++++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 49 deletions(-) diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 86eaba91..c0d998cc 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -118,7 +118,7 @@ class Schedule: elif algorithm == "ALAP": self.scheduler.schedule_alap() elif algorithm == "earliest_deadline": - self.scheduler.schedule_earliest_deadline() + self.scheduler.schedule_earliest_deadline([]) elif algorithm == "provided": if start_times is None: raise ValueError("Must provide start_times when using 'provided'") @@ -1246,14 +1246,15 @@ class Scheduler: operation = outport.operation if operation.type_name() == Delay.type_name(): non_schedulable_ops.add(operation.graph_id) - elif operation.graph_id not in sched._start_times: + # elif operation.graph_id not in sched._start_times: + else: sched._start_times[operation.graph_id] = 0 # handle second set in precedence graph (first operations) for outport in prec_list[1]: operation = outport.operation - if operation.graph_id not in sched._start_times: - sched._start_times[operation.graph_id] = 0 + # if operation.graph_id not in sched._start_times: + sched._start_times[operation.graph_id] = 0 # handle the remaining sets for outports in prec_list[2:]: @@ -1304,23 +1305,7 @@ class Scheduler: sched._start_times[operation.graph_id] = op_start_time - # handle output and remove delays - for output in sched._sfg.find_by_type_name(Output.type_name()): - output = cast(Output, output) - source_port = cast(OutputPort, output.inputs[0].signals[0].source) - if source_port.operation.graph_id in non_schedulable_ops: - sched._start_times[output.graph_id] = 0 - else: - if source_port.latency_offset is None: - raise ValueError( - f"Output port {source_port.index} of operation" - f" {source_port.operation.graph_id} has no" - " latency-offset." - ) - sched._start_times[output.graph_id] = sched._start_times[ - source_port.operation.graph_id - ] + cast(int, source_port.latency_offset) - sched._remove_delays() + self._handle_outputs_and_delays(non_schedulable_ops) def schedule_alap(self) -> None: """Schedule the operations using as-late-as-possible scheduling.""" @@ -1344,32 +1329,75 @@ class Scheduler: if not isinstance(outport.operation, Delay): sched.move_operation_alap(outport.operation.graph_id) - def schedule_earliest_deadline(self) -> None: + def schedule_earliest_deadline(self, process_elements: list[Operation]) -> None: """Schedule the operations using earliest deadline scheduling.""" - pass - # sched = self.schedule - # prec_list = sched.sfg.get_precedence_list() - # if len(prec_list) < 2: - # raise ValueError("Empty signal flow graph cannot be scheduled.") - - # # handle the first set in precedence graph (input and delays) - # non_schedulable_ops = set() - # for outport in prec_list[0]: - # operation = outport.operation - # if operation.type_name() == Delay.type_name(): - # non_schedulable_ops.add(operation.graph_id) - # elif operation.graph_id not in sched._start_times: - # sched._start_times[operation.graph_id] = 0 - - # # handle second set in precedence graph (first operations) - # for outport in prec_list[1]: - # operation = outport.operation - # if operation.graph_id not in sched._start_times: - # sched._start_times[operation.graph_id] = 0 - - # # handle the remaining sets - # for outports in prec_list[2:]: - # for outport in outports: - # operation = outport.operation - # if operation.graph_id not in sched._start_times: - # pass + + # ACT BASED ON THE NUMBER OF PEs! + + sched = self.schedule + prec_list = sched.sfg.get_precedence_list() + if len(prec_list) < 2: + raise ValueError("Empty signal flow graph cannot be scheduled.") + + # handle the first set in precedence graph (input and delays) + non_schedulable_ops = set() + for outport in prec_list[0]: + operation = outport.operation + if operation.type_name() == Delay.type_name(): + non_schedulable_ops.add(operation.graph_id) + elif operation.graph_id not in sched._start_times: + sched._start_times[operation.graph_id] = 0 + + # latencies = [outport.operation.latency for outport in prec_list[1]] + current_time = 0 + sorted_outports = sorted( + prec_list[1], key=lambda outport: outport.operation.latency + ) + for outport in sorted_outports: + op = outport.operation + sched._start_times[op.graph_id] = current_time + current_time += 1 + + for outports in prec_list[2:]: + # try all remaining operations for one time step + candidates = [] + while len(candidates) == 0: + for outport in outports: + remaining_op = outport.operation + op_is_ready_to_be_scheduled = True + for op_input in remaining_op.inputs: + source_op = op_input.signals[0].source.operation + source_op_time = sched.start_times[source_op.graph_id] + source_end_time = source_op_time + source_op.latency + if source_end_time > current_time: + op_is_ready_to_be_scheduled = False + if op_is_ready_to_be_scheduled: + candidates.append(remaining_op) + # sched._start_times[remaining_op.graph_id] = current_time + current_time += 1 + sorted_candidates = sorted( + candidates, key=lambda candidate: candidate.latency + ) + # schedule the best candidate to current time + sched._start_times[sorted_candidates[0].graph_id] = current_time + + self._handle_outputs_and_delays(non_schedulable_ops) + + def _handle_outputs_and_delays(self, non_schedulable_ops) -> None: + sched = self.schedule + for output in sched._sfg.find_by_type_name(Output.type_name()): + output = cast(Output, output) + source_port = cast(OutputPort, output.inputs[0].signals[0].source) + if source_port.operation.graph_id in non_schedulable_ops: + sched._start_times[output.graph_id] = 0 + else: + if source_port.latency_offset is None: + raise ValueError( + f"Output port {source_port.index} of operation" + f" {source_port.operation.graph_id} has no" + " latency-offset." + ) + sched._start_times[output.graph_id] = sched._start_times[ + source_port.operation.graph_id + ] + cast(int, source_port.latency_offset) + sched._remove_delays() -- GitLab From 980170f1f54558cfd7c27e71f51879d83ad7ea78 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Fri, 24 Jan 2025 17:03:53 +0100 Subject: [PATCH 07/21] earliest deadline, first version working, needs testing --- b_asic/schedule.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/b_asic/schedule.py b/b_asic/schedule.py index c0d998cc..58fa572a 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -1361,7 +1361,9 @@ class Scheduler: for outports in prec_list[2:]: # try all remaining operations for one time step candidates = [] + current_time -= 1 while len(candidates) == 0: + current_time += 1 for outport in outports: remaining_op = outport.operation op_is_ready_to_be_scheduled = True @@ -1374,7 +1376,6 @@ class Scheduler: if op_is_ready_to_be_scheduled: candidates.append(remaining_op) # sched._start_times[remaining_op.graph_id] = current_time - current_time += 1 sorted_candidates = sorted( candidates, key=lambda candidate: candidate.latency ) -- GitLab From 831687a8776d95d32501a73fe255b9d881b58ce7 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:38:14 +0100 Subject: [PATCH 08/21] removed end-of-life py version 3.8 --- .gitlab-ci.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2e59a32d..96ca283e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,18 +35,6 @@ before_script: path: cov.xml coverage: /(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/ -run-test-3.8-pyside2: - variables: - QT_API: pyside2 - image: python:3.8 - extends: ".run-test" - -run-test-3.8-pyqt5: - variables: - QT_API: pyqt5 - image: python:3.8 - extends: ".run-test" - run-test-3.9-pyside2: variables: QT_API: pyside2 -- GitLab From 8c2e1053f977c33ef116fe346525690b7499cc18 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:40:42 +0100 Subject: [PATCH 09/21] removed py version 3.9 since it will reach end-of-life this year --- .gitlab-ci.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 96ca283e..873cea6c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,18 +35,6 @@ before_script: path: cov.xml coverage: /(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/ -run-test-3.9-pyside2: - variables: - QT_API: pyside2 - image: python:3.9 - extends: ".run-test" - -run-test-3.9-pyqt5: - variables: - QT_API: pyqt5 - image: python:3.9 - extends: ".run-test" - run-test-3.10-pyside2: variables: QT_API: pyside2 -- GitLab From 9f512f7cd59d72f9443f5926f9e5d182faab3569 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:41:11 +0100 Subject: [PATCH 10/21] updated toml file with new py version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c0d7de2f..ff1ea7b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ description = "Better ASIC Toolbox" readme = "README.md" maintainers = [{ name = "Oscar Gustafsson", email = "oscar.gustafsson@liu.se" }] license = { file = "LICENSE" } -requires-python = ">=3.8" +requires-python = ">=3.10" dependencies = [ "numpy", "qtpy", -- GitLab From 40eb2980980dad07d536e74c5b1e44682add922c Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:45:29 +0100 Subject: [PATCH 11/21] updated ci file with pyqt6 tests for python 3.10 and 3.11 --- .gitlab-ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 873cea6c..aeb235f0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,6 +47,12 @@ run-test-3.10-pyqt5: image: python:3.10 extends: ".run-test" +run-test-3.10-pyqt6: + variables: + QT_API: pyqt6 + image: python:3.10 + extends: ".run-test" + # PySide2 does not seem to have support for 3.11, "almost works" though #run-test-3.11-pyside2: # variables: @@ -61,6 +67,12 @@ run-test-3.11-pyqt5: image: python:3.11 extends: ".run-test" +run-test-3.11-pyqt6: + variables: + QT_API: pyqt6 + image: python:3.11 + extends: ".run-test" + run-test-3.12-pyqt5: variables: QT_API: pyqt5 -- GitLab From 7bc3424f7a7322d2b8f05cc9ed6556cfa2db0cd6 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:46:47 +0100 Subject: [PATCH 12/21] updated ci file with python 3.13 --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aeb235f0..1bb8d867 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -85,6 +85,12 @@ run-test-3.12-pyqt6: image: python:3.12 extends: ".run-test" +run-test-3.13-pyqt6: + variables: + QT_API: pyqt6 + image: python:3.13 + extends: ".run-test" + # Seemingly works with Qt6, but tests stall on closing scheduler GUI due to modal dialog(?) #run-test-3.10-pyside6: # variables: -- GitLab From c32e17ee379c60165c8f790d8c8270bb989f5d24 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:01:17 +0000 Subject: [PATCH 13/21] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1bb8d867..275368b0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,7 +49,7 @@ run-test-3.10-pyqt5: run-test-3.10-pyqt6: variables: - QT_API: pyqt6 + QT_API: PyQt6 image: python:3.10 extends: ".run-test" @@ -69,7 +69,7 @@ run-test-3.11-pyqt5: run-test-3.11-pyqt6: variables: - QT_API: pyqt6 + QT_API: PyQt6 image: python:3.11 extends: ".run-test" @@ -81,13 +81,13 @@ run-test-3.12-pyqt5: run-test-3.12-pyqt6: variables: - QT_API: pyqt6 + QT_API: PyQt6 image: python:3.12 extends: ".run-test" run-test-3.13-pyqt6: variables: - QT_API: pyqt6 + QT_API: PyQt6 image: python:3.13 extends: ".run-test" -- GitLab From 2e41421589db056bce9473775c87b4d102c1781c Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:13:02 +0000 Subject: [PATCH 14/21] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 275368b0..88a2d4be 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,6 +19,7 @@ before_script: # Install test dependencies - pip install -r requirements_test.txt - export PYTEST_QT_API=$QT_API + - export MPLBACKEND=qtagg .run-test: stage: test -- GitLab From 450b1e86d267471a8ec78c17d91b38af4aec156d Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 08:26:48 +0000 Subject: [PATCH 15/21] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 88a2d4be..1bb8d867 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,6 @@ before_script: # Install test dependencies - pip install -r requirements_test.txt - export PYTEST_QT_API=$QT_API - - export MPLBACKEND=qtagg .run-test: stage: test @@ -50,7 +49,7 @@ run-test-3.10-pyqt5: run-test-3.10-pyqt6: variables: - QT_API: PyQt6 + QT_API: pyqt6 image: python:3.10 extends: ".run-test" @@ -70,7 +69,7 @@ run-test-3.11-pyqt5: run-test-3.11-pyqt6: variables: - QT_API: PyQt6 + QT_API: pyqt6 image: python:3.11 extends: ".run-test" @@ -82,13 +81,13 @@ run-test-3.12-pyqt5: run-test-3.12-pyqt6: variables: - QT_API: PyQt6 + QT_API: pyqt6 image: python:3.12 extends: ".run-test" run-test-3.13-pyqt6: variables: - QT_API: PyQt6 + QT_API: pyqt6 image: python:3.13 extends: ".run-test" -- GitLab From 54d614eb4df4cd6a11c05c3d129ab7cf68a7c81f Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 09:15:30 +0000 Subject: [PATCH 16/21] debugging ci file --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1bb8d867..1fa2fb74 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -84,6 +84,7 @@ run-test-3.12-pyqt6: QT_API: pyqt6 image: python:3.12 extends: ".run-test" + allow_failure: true run-test-3.13-pyqt6: variables: -- GitLab From 7ef91215bd9f3aece99901e627dfab2980fe89d8 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 09:35:51 +0000 Subject: [PATCH 17/21] debugging (adding -s to pytest command) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1fa2fb74..7001d19d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ before_script: .run-test: stage: test script: - - pytest --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10 + - pytest -s --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10 # - lcov --capture --directory . --output-file coverage.info # - lcov --output-file coverage.info --extract coverage.info $PWD/src/'*' $PWD/b_asic/'*' # - lcov --list coverage.info -- GitLab From 7167a5b2f6501039a8c5f8cb23b6b026282ae783 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 09:41:50 +0000 Subject: [PATCH 18/21] attempting fix by adding libxcb-cursor-dev --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7001d19d..f95d4f67 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,7 @@ before_script: - apt-get update --yes # - apt-get install --yes build-essential cmake graphviz python3-pyqt5 xvfb xdg-utils lcov - apt-get install --yes graphviz python3-pyqt5 xvfb xdg-utils + - apt-get install -y libxcb-cursor-dev - python -m pip install --upgrade pip - python --version - pip install -r requirements.txt @@ -23,7 +24,7 @@ before_script: .run-test: stage: test script: - - pytest -s --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10 + - pytest --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10 # - lcov --capture --directory . --output-file coverage.info # - lcov --output-file coverage.info --extract coverage.info $PWD/src/'*' $PWD/b_asic/'*' # - lcov --list coverage.info -- GitLab From c23e613e89b4fb8639b3702c427ed0b6786446b3 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 11:01:17 +0100 Subject: [PATCH 19/21] CI fixes, hopefully working now --- .gitlab-ci.yml | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f95d4f67..5f4c6f59 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -54,14 +54,6 @@ run-test-3.10-pyqt6: image: python:3.10 extends: ".run-test" -# PySide2 does not seem to have support for 3.11, "almost works" though -#run-test-3.11-pyside2: -# variables: -# QT_API: pyside2 -# image: python:3.11 -# extends: ".run-test" -# allow_failure: true - run-test-3.11-pyqt5: variables: QT_API: pyqt5 @@ -85,28 +77,6 @@ run-test-3.12-pyqt6: QT_API: pyqt6 image: python:3.12 extends: ".run-test" - allow_failure: true - -run-test-3.13-pyqt6: - variables: - QT_API: pyqt6 - image: python:3.13 - extends: ".run-test" - -# Seemingly works with Qt6, but tests stall on closing scheduler GUI due to modal dialog(?) -#run-test-3.10-pyside6: -# variables: -# QT_API: pyside6 -# image: python:3.10 -# extends: ".run-test" -# allow_failure: true -# -#run-test-3.10-pyqt6: -# variables: -# QT_API: pyqt6 -# image: python:3.10 -# extends: ".run-test" -# allow_failure: true run-vhdl-tests: variables: -- GitLab From 2a7a7305c79f9eb587cf1e4e68e2b013f9bdc945 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 16:00:09 +0100 Subject: [PATCH 20/21] fixes from mr comments --- b_asic/schedule.py | 179 +----------------------------- b_asic/scheduler.py | 193 +++++++++++++++++++++++++++++++++ b_asic/scheduling_algorithm.py | 9 -- pyproject.toml | 7 +- 4 files changed, 199 insertions(+), 189 deletions(-) create mode 100644 b_asic/scheduler.py delete mode 100644 b_asic/scheduling_algorithm.py diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 58fa572a..a708fe1a 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -33,7 +33,7 @@ from b_asic.operation import Operation from b_asic.port import InputPort, OutputPort from b_asic.process import MemoryVariable, OperatorProcess from b_asic.resources import ProcessCollection -from b_asic.scheduling_algorithm import SchedAlg +from b_asic.scheduler import Scheduler, SchedulingAlgorithm from b_asic.signal_flow_graph import SFG from b_asic.special_operations import Delay, Input, Output from b_asic.types import TypeName @@ -96,7 +96,7 @@ class Schedule: sfg: SFG, schedule_time: Optional[int] = None, cyclic: bool = False, - algorithm: SchedAlg = "ASAP", + algorithm: SchedulingAlgorithm = "ASAP", start_times: Optional[Dict[GraphID, int]] = None, laps: Optional[Dict[GraphID, int]] = None, max_resources: Optional[Dict[TypeName, int]] = None, @@ -1227,178 +1227,3 @@ class Schedule: # SVG is valid HTML. This is useful for e.g. sphinx-gallery _repr_html_ = _repr_svg_ - - -class Scheduler: - def __init__(self, schedule: Schedule) -> None: - self.schedule = schedule - - def schedule_asap(self) -> None: - """Schedule the operations using as-soon-as-possible scheduling.""" - sched = self.schedule - prec_list = sched.sfg.get_precedence_list() - if len(prec_list) < 2: - raise ValueError("Empty signal flow graph cannot be scheduled.") - - # handle the first set in precedence graph (input and delays) - non_schedulable_ops = set() - for outport in prec_list[0]: - operation = outport.operation - if operation.type_name() == Delay.type_name(): - non_schedulable_ops.add(operation.graph_id) - # elif operation.graph_id not in sched._start_times: - else: - sched._start_times[operation.graph_id] = 0 - - # handle second set in precedence graph (first operations) - for outport in prec_list[1]: - operation = outport.operation - # if operation.graph_id not in sched._start_times: - sched._start_times[operation.graph_id] = 0 - - # handle the remaining sets - for outports in prec_list[2:]: - for outport in outports: - operation = outport.operation - if operation.graph_id not in sched._start_times: - op_start_time = 0 - for current_input in operation.inputs: - if len(current_input.signals) != 1: - raise ValueError( - "Error in scheduling, dangling input port detected." - ) - if current_input.signals[0].source is None: - raise ValueError( - "Error in scheduling, signal with no source detected." - ) - source_port = current_input.signals[0].source - - if source_port.operation.graph_id in non_schedulable_ops: - source_end_time = 0 - else: - source_op_time = sched._start_times[ - source_port.operation.graph_id - ] - - if source_port.latency_offset is None: - raise ValueError( - f"Output port {source_port.index} of" - " operation" - f" {source_port.operation.graph_id} has no" - " latency-offset." - ) - - source_end_time = ( - source_op_time + source_port.latency_offset - ) - - if current_input.latency_offset is None: - raise ValueError( - f"Input port {current_input.index} of operation" - f" {current_input.operation.graph_id} has no" - " latency-offset." - ) - op_start_time_from_in = ( - source_end_time - current_input.latency_offset - ) - op_start_time = max(op_start_time, op_start_time_from_in) - - sched._start_times[operation.graph_id] = op_start_time - - self._handle_outputs_and_delays(non_schedulable_ops) - - def schedule_alap(self) -> None: - """Schedule the operations using as-late-as-possible scheduling.""" - self.schedule_asap() - sched = self.schedule - max_end_time = sched.get_max_end_time() - - if sched.schedule_time is None: - sched.set_schedule_time(max_end_time) - elif sched.schedule_time < max_end_time: - raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.") - - # move all outputs ALAP before operations - for output in sched.sfg.find_by_type_name(Output.type_name()): - output = cast(Output, output) - sched.move_operation_alap(output.graph_id) - - # move all operations ALAP - for step in reversed(sched.sfg.get_precedence_list()): - for outport in step: - if not isinstance(outport.operation, Delay): - sched.move_operation_alap(outport.operation.graph_id) - - def schedule_earliest_deadline(self, process_elements: list[Operation]) -> None: - """Schedule the operations using earliest deadline scheduling.""" - - # ACT BASED ON THE NUMBER OF PEs! - - sched = self.schedule - prec_list = sched.sfg.get_precedence_list() - if len(prec_list) < 2: - raise ValueError("Empty signal flow graph cannot be scheduled.") - - # handle the first set in precedence graph (input and delays) - non_schedulable_ops = set() - for outport in prec_list[0]: - operation = outport.operation - if operation.type_name() == Delay.type_name(): - non_schedulable_ops.add(operation.graph_id) - elif operation.graph_id not in sched._start_times: - sched._start_times[operation.graph_id] = 0 - - # latencies = [outport.operation.latency for outport in prec_list[1]] - current_time = 0 - sorted_outports = sorted( - prec_list[1], key=lambda outport: outport.operation.latency - ) - for outport in sorted_outports: - op = outport.operation - sched._start_times[op.graph_id] = current_time - current_time += 1 - - for outports in prec_list[2:]: - # try all remaining operations for one time step - candidates = [] - current_time -= 1 - while len(candidates) == 0: - current_time += 1 - for outport in outports: - remaining_op = outport.operation - op_is_ready_to_be_scheduled = True - for op_input in remaining_op.inputs: - source_op = op_input.signals[0].source.operation - source_op_time = sched.start_times[source_op.graph_id] - source_end_time = source_op_time + source_op.latency - if source_end_time > current_time: - op_is_ready_to_be_scheduled = False - if op_is_ready_to_be_scheduled: - candidates.append(remaining_op) - # sched._start_times[remaining_op.graph_id] = current_time - sorted_candidates = sorted( - candidates, key=lambda candidate: candidate.latency - ) - # schedule the best candidate to current time - sched._start_times[sorted_candidates[0].graph_id] = current_time - - self._handle_outputs_and_delays(non_schedulable_ops) - - def _handle_outputs_and_delays(self, non_schedulable_ops) -> None: - sched = self.schedule - for output in sched._sfg.find_by_type_name(Output.type_name()): - output = cast(Output, output) - source_port = cast(OutputPort, output.inputs[0].signals[0].source) - if source_port.operation.graph_id in non_schedulable_ops: - sched._start_times[output.graph_id] = 0 - else: - if source_port.latency_offset is None: - raise ValueError( - f"Output port {source_port.index} of operation" - f" {source_port.operation.graph_id} has no" - " latency-offset." - ) - sched._start_times[output.graph_id] = sched._start_times[ - source_port.operation.graph_id - ] + cast(int, source_port.latency_offset) - sched._remove_delays() diff --git a/b_asic/scheduler.py b/b_asic/scheduler.py new file mode 100644 index 00000000..845859c9 --- /dev/null +++ b/b_asic/scheduler.py @@ -0,0 +1,193 @@ +from enum import Enum +from typing import TYPE_CHECKING, cast + +from b_asic.operation import Operation +from b_asic.port import OutputPort +from b_asic.special_operations import Delay, Output + +if TYPE_CHECKING: + from b_asic.schedule import Schedule + + +class SchedulingAlgorithm(Enum): + ASAP = "ASAP" + ALAP = "ALAP" + EARLIEST_DEADLINE = "earliest_deadline" + # LEAST_SLACK = "least_slack" # to be implemented + PROVIDED = "provided" + + +class Scheduler: + def __init__(self, schedule: "Schedule") -> None: + self.schedule = schedule + + def schedule_asap(self) -> None: + """Schedule the operations using as-soon-as-possible scheduling.""" + sched = self.schedule + prec_list = sched.sfg.get_precedence_list() + if len(prec_list) < 2: + raise ValueError("Empty signal flow graph cannot be scheduled.") + + # handle the first set in precedence graph (input and delays) + non_schedulable_ops = set() + for outport in prec_list[0]: + operation = outport.operation + if operation.type_name() == Delay.type_name(): + non_schedulable_ops.add(operation.graph_id) + # elif operation.graph_id not in sched._start_times: + else: + sched._start_times[operation.graph_id] = 0 + + # handle second set in precedence graph (first operations) + for outport in prec_list[1]: + operation = outport.operation + # if operation.graph_id not in sched._start_times: + sched._start_times[operation.graph_id] = 0 + + # handle the remaining sets + for outports in prec_list[2:]: + for outport in outports: + operation = outport.operation + if operation.graph_id not in sched._start_times: + op_start_time = 0 + for current_input in operation.inputs: + if len(current_input.signals) != 1: + raise ValueError( + "Error in scheduling, dangling input port detected." + ) + if current_input.signals[0].source is None: + raise ValueError( + "Error in scheduling, signal with no source detected." + ) + source_port = current_input.signals[0].source + + if source_port.operation.graph_id in non_schedulable_ops: + source_end_time = 0 + else: + source_op_time = sched._start_times[ + source_port.operation.graph_id + ] + + if source_port.latency_offset is None: + raise ValueError( + f"Output port {source_port.index} of" + " operation" + f" {source_port.operation.graph_id} has no" + " latency-offset." + ) + + source_end_time = ( + source_op_time + source_port.latency_offset + ) + + if current_input.latency_offset is None: + raise ValueError( + f"Input port {current_input.index} of operation" + f" {current_input.operation.graph_id} has no" + " latency-offset." + ) + op_start_time_from_in = ( + source_end_time - current_input.latency_offset + ) + op_start_time = max(op_start_time, op_start_time_from_in) + + sched._start_times[operation.graph_id] = op_start_time + + self._handle_outputs_and_delays(non_schedulable_ops) + + def schedule_alap(self) -> None: + """Schedule the operations using as-late-as-possible scheduling.""" + self.schedule_asap() + sched = self.schedule + max_end_time = sched.get_max_end_time() + + if sched.schedule_time is None: + sched.set_schedule_time(max_end_time) + elif sched.schedule_time < max_end_time: + raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.") + + # move all outputs ALAP before operations + for output in sched.sfg.find_by_type_name(Output.type_name()): + output = cast(Output, output) + sched.move_operation_alap(output.graph_id) + + # move all operations ALAP + for step in reversed(sched.sfg.get_precedence_list()): + for outport in step: + if not isinstance(outport.operation, Delay): + sched.move_operation_alap(outport.operation.graph_id) + + def schedule_earliest_deadline( + self, process_elements: dict[Operation, int] + ) -> None: + """Schedule the operations using earliest deadline scheduling.""" + + # ACT BASED ON THE NUMBER OF PEs! + + sched = self.schedule + prec_list = sched.sfg.get_precedence_list() + if len(prec_list) < 2: + raise ValueError("Empty signal flow graph cannot be scheduled.") + + # handle the first set in precedence graph (input and delays) + non_schedulable_ops = set() + for outport in prec_list[0]: + operation = outport.operation + if operation.type_name() == Delay.type_name(): + non_schedulable_ops.add(operation.graph_id) + elif operation.graph_id not in sched._start_times: + sched._start_times[operation.graph_id] = 0 + + current_time = 0 + sorted_outports = sorted( + prec_list[1], key=lambda outport: outport.operation.latency + ) + for outport in sorted_outports: + op = outport.operation + sched._start_times[op.graph_id] = current_time + current_time += 1 + + for outports in prec_list[2:]: + # try all remaining operations for one time step + candidates = [] + current_time -= 1 + while len(candidates) == 0: + current_time += 1 + for outport in outports: + remaining_op = outport.operation + op_is_ready_to_be_scheduled = True + for op_input in remaining_op.inputs: + source_op = op_input.signals[0].source.operation + source_op_time = sched.start_times[source_op.graph_id] + source_end_time = source_op_time + source_op.latency + if source_end_time > current_time: + op_is_ready_to_be_scheduled = False + if op_is_ready_to_be_scheduled: + candidates.append(remaining_op) + # sched._start_times[remaining_op.graph_id] = current_time + sorted_candidates = sorted( + candidates, key=lambda candidate: candidate.latency + ) + # schedule the best candidate to current time + sched._start_times[sorted_candidates[0].graph_id] = current_time + + self._handle_outputs_and_delays(non_schedulable_ops) + + def _handle_outputs_and_delays(self, non_schedulable_ops) -> None: + sched = self.schedule + for output in sched._sfg.find_by_type_name(Output.type_name()): + output = cast(Output, output) + source_port = cast(OutputPort, output.inputs[0].signals[0].source) + if source_port.operation.graph_id in non_schedulable_ops: + sched._start_times[output.graph_id] = 0 + else: + if source_port.latency_offset is None: + raise ValueError( + f"Output port {source_port.index} of operation" + f" {source_port.operation.graph_id} has no" + " latency-offset." + ) + sched._start_times[output.graph_id] = sched._start_times[ + source_port.operation.graph_id + ] + cast(int, source_port.latency_offset) + sched._remove_delays() diff --git a/b_asic/scheduling_algorithm.py b/b_asic/scheduling_algorithm.py deleted file mode 100644 index c6787a73..00000000 --- a/b_asic/scheduling_algorithm.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class SchedAlg(Enum): - ASAP = "ASAP" - ALAP = "ALAP" - EARLIEST_DEADLINE = "earliest_deadline" - LEAST_SLACK = "least_slack" - PROVIDED = "provided" diff --git a/pyproject.toml b/pyproject.toml index ff1ea7b2..21ece32f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,16 +12,17 @@ dependencies = [ "matplotlib>=3.7", "setuptools_scm[toml]>=6.2", "networkx>=3", - "qtawesome" + "qtawesome", + "pyqt6", ] classifiers = [ "Intended Audience :: Education", "Intended Audience :: Science/Research", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: C++", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", -- GitLab From 720336ddda37470237b57937d0ee95912b7001f7 Mon Sep 17 00:00:00 2001 From: Simon Bjurek <simbj106@student.liu.se> Date: Mon, 27 Jan 2025 16:01:21 +0100 Subject: [PATCH 21/21] fixes from mr comments --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 21ece32f..a9074708 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ dependencies = [ "setuptools_scm[toml]>=6.2", "networkx>=3", "qtawesome", - "pyqt6", ] classifiers = [ "Intended Audience :: Education", -- GitLab