Debug: Add Timer window.

opt-result
Pierre-Antoine 2026-07-08 16:38:41 +02:00
parent 476fa81bc2
commit 1306977954
4 changed files with 212 additions and 3 deletions

74
src/View/Debug/Table.py Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
# -*- 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()

View File

@ -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

View File

@ -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...")

68
src/View/ui/DebugTimer.ui Normal file
View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTableView" name="tableView"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="action_reset"/>
<addaction name="action_export"/>
</widget>
<action name="action_export">
<property name="icon">
<iconset>
<normaloff>ressources/export.png</normaloff>ressources/export.png</iconset>
</property>
<property name="text">
<string>Export</string>
</property>
</action>
<action name="action_reset">
<property name="icon">
<iconset>
<normaloff>ressources/reload.png</normaloff>ressources/reload.png</iconset>
</property>
<property name="text">
<string>Reset</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>