From 13069779542e8c1a8285b10cd100a2ae0bf39d4e Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Wed, 8 Jul 2026 16:38:41 +0200 Subject: [PATCH] Debug: Add Timer window. --- src/View/Debug/Table.py | 74 +++++++++++++++++++++++++++++++++++++++ src/View/Debug/Window.py | 56 +++++++++++++++++++++++++++-- src/View/MainWindow.py | 17 ++++++++- src/View/ui/DebugTimer.ui | 68 +++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 src/View/Debug/Table.py create mode 100644 src/View/ui/DebugTimer.ui diff --git a/src/View/Debug/Table.py b/src/View/Debug/Table.py new file mode 100644 index 00000000..ce4c8f2b --- /dev/null +++ b/src/View/Debug/Table.py @@ -0,0 +1,74 @@ +# Table.py -- Pamhyr +# Copyright (C) 2026 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +import logging + +from functools import reduce +from tools import trace, timer, _timers, _calls + +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, + QCoreApplication, QModelIndex, pyqtSlot, + QRect, +) + +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, QAbstractItemView, + QUndoStack, QShortcut, QAction, QItemDelegate, + QComboBox, +) + +from Modules import Modules +from View.Tools.PamhyrTable import PamhyrTableModel + +logger = logging.getLogger() + + +class TableModel(PamhyrTableModel): + def _setup_lst(self): + self._lst = sorted( + map( + lambda f: ( + f"{f.__module__}.{f.__qualname__}", + _timers[f], + _calls[f] + ), + _timers + ), + key=lambda f: f[1], + reverse=True + ) + + def update_lst(self): + self._setup_lst() + self.layoutChanged.emit() + + def data(self, index, role): + row = index.row() + column = index.column() + + if role == Qt.DisplayRole: + if self._headers[column] == "name": + return self._lst[row][0] + elif self._headers[column] == "time": + return self._lst[row][1] + elif self._headers[column] == "calls": + return self._lst[row][2] + + return QVariant() diff --git a/src/View/Debug/Window.py b/src/View/Debug/Window.py index c5f4c720..e93ec9bf 100644 --- a/src/View/Debug/Window.py +++ b/src/View/Debug/Window.py @@ -1,5 +1,5 @@ # Window.py -- Pamhyr -# Copyright (C) 2023-2025 INRAE +# Copyright (C) 2023-2026 INRAE # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ from tools import trace, timer from View.Tools.PamhyrWindow import PamhyrWindow from View.Tools.PamhyrPythonEditor import PamhyrPythonEditor +from View.Debug.Table import TableModel from PyQt5.QtGui import ( QKeySequence, @@ -31,7 +32,7 @@ from PyQt5.QtGui import ( from PyQt5.QtCore import ( Qt, QVariant, QAbstractTableModel, QCoreApplication, QModelIndex, QRect, QThread, - pyqtSlot, pyqtSignal, + QTimer, pyqtSlot, pyqtSignal, ) from PyQt5.QtWidgets import ( @@ -101,3 +102,54 @@ class ReplWindow(PamhyrWindow): self.find(QTextEdit, "textEdit").append(msg) # Display results self.find(QTextEdit, "textEdit").append(str(value)) + +class TimerWindow(PamhyrWindow): + _pamhyr_ui = "DebugTimer" + _pamhyr_name = "Debug Timer" + + def __init__(self, study=None, config=None, + solver=None, parent=None): + title = _translate("Debug", "Debug Timer") + + super(TimerWindow, self).__init__( + title=title, + study=study, + config=config, + options=[], + parent=parent + ) + + self.setup_table() + self.setup_alarm() + self.setup_connections() + + def setup_table(self): + table = self.find(QTableView, f"tableView") + self._table = TableModel( + table_view=table, + table_headers={ + "name": "Function name", + "time": "Time (sec)", + "calls": "Number of calls" + }, + data=None, + ) + + def setup_alarm(self): + self._alarm = QTimer() + self._alarm.start(2000) + + def setup_connections(self): + self.find(QAction, "action_reset").triggered.connect(self.reset) + self.find(QAction, "action_export").triggered.connect(self.export) + + self._alarm.timeout.connect(self.update) + + def update(self): + self._table.update_lst() + + def reset(self): + return + + def export(self): + return diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index 70a70f5c..f112ccdf 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -100,7 +100,7 @@ from View.CheckList.WindowAdisTS import CheckListWindowAdisTS from View.Results.WindowAdisTS import ResultsWindowAdisTS from View.Results.ReadingResultsDialog import ReadingResultsDialog -from View.Debug.Window import ReplWindow +from View.Debug.Window import ReplWindow, TimerWindow from View.OutputRKAdisTS.Window import OutputRKAdisTSWindow from View.Pollutants.Window import PollutantsWindow from View.D90AdisTS.Window import D90AdisTSWindow @@ -409,21 +409,28 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): self.debug_action.setToolTip(self._trad["open_debug"]) self.debug_action.triggered.connect(self.open_debug) + self.debug_timer_action = QAction("Debug timer", self) + self.debug_timer_action.setToolTip(self._trad["open_debug_timer"]) + self.debug_timer_action.triggered.connect(self.open_debug_timer) + self.debug_sqlite_action = QAction("Debug SQLite", self) self.debug_sqlite_action.setToolTip(self._trad["open_debug_sql"]) self.debug_sqlite_action.triggered.connect(self.open_sqlite) if self.conf.debug: menu.addAction(self.debug_action) + menu.addAction(self.debug_timer_action) menu.addAction(self.debug_sqlite_action) self.set_debug_lvl(debug=True) else: if self.conf.debug: menu.addAction(self.debug_action) + menu.addAction(self.debug_timer_action) menu.addAction(self.debug_sqlite_action) self.set_debug_lvl(debug=True) else: menu.removeAction(self.debug_action) + menu.removeAction(self.debug_timer_action) menu.removeAction(self.debug_sqlite_action) self.set_debug_lvl(debug=False) @@ -2143,6 +2150,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ) repl.show() + def open_debug_timer(self): + repl = TimerWindow( + study=self._study, + config=self.conf, + parent=self + ) + repl.show() + def open_sqlite(self): if self._study is None: logger.debug("No study open for sql debuging...") diff --git a/src/View/ui/DebugTimer.ui b/src/View/ui/DebugTimer.ui new file mode 100644 index 00000000..0a4a99f4 --- /dev/null +++ b/src/View/ui/DebugTimer.ui @@ -0,0 +1,68 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + + + + + + 0 + 0 + 800 + 24 + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + ressources/export.pngressources/export.png + + + Export + + + + + + ressources/reload.pngressources/reload.png + + + Reset + + + + + +